代码的模块化
代码文件的导入
代码文件可以使用 import 声明导入其他代码文件,解释器会提前将代码导入的其他文件解释并保存在内存中。
单一字节码模块
可以使用 compile() 方法将一段代码编译成一个单一字节码文件。在编译时,编译器会自动将代码中使用 import 语句导入的所有其他代码文件一并编译,这样在再分发时只需要发布单一的字节码模块即可。
资源空间
资源空间(HTResourceContext)是一个抽象接口,指编译器获取代码文件的辅助类。默认的资源空间的实现是 HTOverlayContext。这个实现不会自动读取任何资源。用户需要提前手动添加代码文件,才可以让 import 语句生效。
资源类型
资源类型(ResourceType)决定了解释器如何看待代码以及如何看待 import 语句引入的文件。在解释器的 eval() 方法中包含这个参数。
当省略掉 eval() 方法的 ResourceType type 参数时,解释器会以字面量的形式解释字符串(ResourceType.hetuLiteralCode)。这种类型的代码不会生成自己的命名空间,而是直接使用全局命名空间。
当 eval() 方法的代码类型参数为 ResourceType.hetuScript 时,解释器会使用类似 Javascript, Python 和 Lua 那样的形式来解释。除了声明语句之外,代码中可以直接执行表达式语句,例如在代码顶层直接调用某个函数。这种类型的代码会使用单独的命名空间。执行这种代码的效果类似于执行一个匿名函数。代码中的变量的初始化值会被立即运算。代码按照书写的顺序执行。
当 eval() 方法的代码类型参数为 ResourceType.hetuModule 时,解释器会使用类似 C++, Java 和 Dart 那样的 APP 的形式来解释。代码中只允许包含导入导出语句,以及声明语句。代码中的变量的初始化值在调用时才会被计算出来。代码的执行顺序也并不一定是书写顺序。可以通过传入 invoke 参数来立即调用一个函数。但不要求这个函数一定是 'main' 函数。
对于解释器的 evalFile() 方法,代码文件类型将以文件名后缀作为判断基准:'*.hts' 对应了 ResourceType.hetuScript,而 '*.ht' 对应了 ResourceType.hetuModule。
导入字节码文件
一个已经编译成了字节码文件的模块也可以被导入。但只能以整个模块导入,其作为入口代码的文件指定了你可以导入的内容。使用这种单一字节码文件可以提交一些效率,因为这样解释器无需进行 parse, analyze, compile 的过程。
在脚本代码文件中导入前,你需要通过解释器上的 loadBytecode() 方法来载入这个文件。下面是一个例子:
import 'dart:io';
import 'package:hetu_script/hetu_script.dart';
import 'package:hetu_script_dev_tools/hetu_script_dev_tools.dart';
void main() {
final sourceContext = HTFileSystemResourceContext(root: 'example/script/');
final hetu = Hetu(sourceContext: sourceContext);
hetu.init();
final binaryFile = File('example/script/module.out');
final bytes = binaryFile.readAsBytesSync();
hetu.loadBytecode(bytes: bytes, module: 'calculate');
hetu.evalFile('import_binary_module.hts');
}
然后你可以在代码中使用 import 加上 'module:' 开头的路径来导入它。注意,出于错误检查的目的,此时你必须为引入的 module 提供一个命名空间别名。
import 'module:calculate' as calculate;
final result = calculate.calculate()
导入 JSON 文件
和 Javascript 一样,河图中的对象字面量语法和 JSON 完全兼容,因此你可以直接导入一个 JSON 文件,而无需进行任何类型转换。
河图提供的 ResourceContext 会默认载入 json 和 json5 类型的文件作为代码文件。
import 'package:hetu_script/hetu_script.dart';
import 'package:hetu_script_dev_tools/hetu_script_dev_tools.dart';
void main() {
final sourceContext = HTFileSystemResourceContext(root: 'example/script');
final hetu = Hetu(sourceContext: sourceContext);
hetu.init();
hetu.eval('''
import 'values.json' as json
print(json.name) // use json value like a struct
''');
}
注意,json 资源文件并非代码文件,没有命名空间,因此在导入时必须指定一个别名才可以使用。