Solon v3.0.3

评估器

</> markdown

Liquor Java 语言评估器。支持完整的 Java 语法及各版本特性(具体看运行时版本)。评估器由“三个”关键类及两个工具组成:

部件描述
CodeSpec代码申明
LiquorEvaluator评估器。用于管理 CodeSpec 的编译、缓存
Execable可执行接口。由 CodeSpec 编译后会产生
::Scripts评估器的脚本工具
::Exprs评估器的表达式工具

1、CodeSpec 类结构及编译效果

字段描述
code申明代码(一般包含,代码头?和代码主体!)
imports申明类头导入
parameters申明参数
returnType申明返回类型
cached申明缓存的(默认为 true)。当代码无限变化时,不能用缓存(否则有 OOM 风险)

CodeSpec 会被编译成一个静态函数(并转换为 Execable)。格式效果如下:

#imports#

public class Execable$... {
    public static #returnType# _main$(#parameters#) {
        #code#
    }
}

其中 #imports#,由三部分组成:

  • LiquorEvaluator:globalImports(一般不用,避免产生相互干扰。特殊定制时可用)
  • CodeSpec:imports
  • code:header-imports (代码头部的 import 语句)

其中 CodeSpec:code + CodeSpec:imports 会形成:

  • 缓存键,用于缓存控制

2、LiquorEvaluator 接口及 eval 过程分解(使用时以 Scripts 和 Exprs 为主)

方法列表:

方法描述
printable(bool)配置可打印的
compile(codeSpec)预编译
eval(codeSpec, args)评估

eval 过程分解:

3、Exprs 代码展示(Scripts 类似)

也可以定制特定业务的体验工具。比如,Exprs 在接收 CodeSpec 时会自动申明 returnType。

public interface Exprs {
    
    static Execable compile(String code) {
        return compile(new CodeSpec(code));
    }

    static Execable compile(CodeSpec codeSpec) {
        //强制有估评结果
        if (codeSpec.getReturnType() == null) {
            codeSpec.returnType(Object.class);
        }

        return LiquorEvaluator.getInstance().compile(codeSpec);
    }


    
    static Object eval(String code) throws InvocationTargetException {
        return eval(new CodeSpec(code));
    }

    static Object eval(CodeSpec codeSpec, Object... args) throws InvocationTargetException {
        //强制有估评结果
        if (codeSpec.getReturnType() == null) {
            codeSpec.returnType(Object.class);
        }

        return LiquorEvaluator.getInstance().eval(codeSpec, args);
    }

    static Object eval(String code, Map<String, Object> context) throws InvocationTargetException {
        assert context != null;

        ParamSpec[] parameters = new ParamSpec[context.size()];
        Object[] args = new Object[context.size()];

        int idx = 0;
        for (Map.Entry<String, Object> entry : context.entrySet()) {
            parameters[idx] = new ParamSpec(entry.getKey(), entry.getValue().getClass());
            args[idx] = entry.getValue();
            idx++;
        }

        return eval(new CodeSpec(code).parameters(parameters), args);
    }
}