Environment 是 Fluxon 执行期的“作用域 + 符号表”。解释器与编译执行引擎都会基于同一个 Environment 完成变量读写、
函数调用与扩展函数分派(target::method(...))。
它管理的核心要素:
- 函数:系统函数(含命名空间函数)。
- 扩展函数:上下文调用
target::method(...)。
- 变量:根变量(全局)与局部变量(函数调用作用域)。
- 上下文目标:
target 槽位(由 :: 调用临时写入)。
Environment 通常通过 FluxonRuntime#getInstance().newEnvironment() 创建。注册新的函数/扩展/变量后,
重新创建环境以刷新运行时缓存。
Root 与子环境
- 根环境(root):持有函数映射、扩展函数映射、根变量映射,以及运行时生成的缓存结构(用于加速调用分派)。
- 子环境(child):用于函数调用作用域,只存放局部变量数组与(可选的)局部变量名;通过
root 引用共享根数据。
函数解析
普通函数通过 Environment#getFunction(name) 在根函数表中查找;不存在会抛出 FunctionNotFoundError。
命名空间函数(如 fs:time)需要脚本先 import 'fs:time' 才会被解析到(见 术语表)。
扩展函数解析(target::method)
扩展函数的匹配依赖 target 的宿主类型:
- 解析器在可优化的场景下会为调用点生成
extensionPositionIndex,运行时会使用 root.dispatchTables[index] 快速解析。
- 对于动态注册或无法提前编号的调用点,会回退到
root.extensionFunctions.get(name) 的映射,并按“精确类型 →
isAssignableFrom”顺序匹配。
如果你在运行中动态注册了扩展函数,旧的 Environment 可能不会包含新的派发表缓存;建议在注册完成后重新 newEnvironment()。
变量与索引
变量访问在运行时以“索引”为主:
index = -1:根变量(保存在 rootVariables)。
index >= 0:局部变量(保存在 localVariables[index]),必要时沿 parent 链回溯。
当索引越界且不存在 parent 时会抛出 VariableNotFoundError,并附带 localVariableNames 以便定位问题。
上下文目标 target
上下文调用会把左侧表达式写入 Environment#target,再执行右侧函数/扩展;执行完成后解释器会恢复旧的 target。
调试与枚举
Environment#getRootFunctions():当前系统函数表。
Environment#getRootExtensionFunctions():当前扩展函数映射(类型 → Function)。
Environment#getRootVariables():当前根变量表(含宿主注入的对象)。
FunctionContext#toString():定位一次调用的 target 与参数。
外部变量注入
Fluxon 提供两种方式向脚本注入外部变量:根变量(RootVariable) 和 参数(Parameter)。
| 特性 | 根变量 | 参数 |
|---|
| 定义时机 | 运行时 | 编译期 |
| 存储方式 | HashMap 查找 | 数组索引 |
| 类型 | 无类型(Object) | 强类型(double、long、Object) |
| 性能 | 中等 | 高 |
| 共享范围 | 全局(所有 Environment 共享) | 每个 Environment 独立 |
根变量
根变量通过 HashMap 存储,适合全局常量或工具对象:
// 方式一:通过 FluxonRuntime 注册(全局共享)
FluxonRuntime.getInstance().registerVariable("config", configObject);
// 方式二:在 Environment 中定义
env.defineRootVariable("logger", loggerInstance);
env.setRootVariable("logger", newLoggerInstance); // 修改
Object logger = env.getRootVariable("logger"); // 读取
脚本中通过 & 引用访问:
&config :: get("timeout")
&logger :: info("message")
参数通过数组索引存储,适合高频调用场景:
// 编译期定义(必须指定类型)
CompilationContext ctx = new CompilationContext(source);
ctx.defineParameter("rate", double.class);
ctx.defineParameter("name", String.class);
CompiledScript script = ctx.compile();
// 运行时绑定
Environment env = script.newEnvironment();
env.setParameter("rate", 0.15);
env.setParameter("name", "Alice");
script.execute(env);
// 换值再执行(无需重新编译)
env.setParameter("rate", 0.20);
script.execute(env);
选择建议
- 根变量:全局配置、工具对象、不常变化的数据
- 参数:需要高频变化的输入值、性能敏感场景
参数必须在编译前定义,编译后无法新增;根变量可随时添加。
参数绑定 API
Environment 参数方法
| 方法 | 说明 |
|---|
setParameter(name, value) | 设置对象类型参数值。 |
setParameter(name, double) | 设置 double 类型参数值(避免装箱)。 |
setParameter(name, long) | 设置 long 类型参数值。 |
getParameterInfo(name) | 获取参数的元信息(类型、索引)。 |
脚本中使用
参数通过 & 引用访问,与普通变量语法一致:
total = &price * (1 + &rate)
greeting = "Hello, " + &name
FunctionContext 参数获取
在函数实现中,通过 FunctionContext 获取参数:
| 方法 | 说明 |
|---|
getRef(index) | 获取指定索引的参数原始引用。 |
getInt(index) | 获取 int 类型参数。 |
getLong(index) | 获取 long 类型参数。 |
getDouble(index) | 获取 double 类型参数。 |
getAsDouble(index) | 将任意数值参数转换为 double。 |
getString(index) | 获取 String 类型参数。 |
import static org.tabooproject.fluxon.runtime.FunctionSignature.returns;
import org.tabooproject.fluxon.runtime.Type;
runtime.registerFunction("multiply", returns(Type.D).params(Type.D, Type.D), ctx -> {
double a = ctx.getAsDouble(0);
double b = ctx.getAsDouble(1);
ctx.setReturnDouble(a * b);
});
相关链接