Aviator介绍

Aviator简介

Aviator是一个高性能、轻量级的 java 语言实现的表达式求值引擎, 主要用于各种表达式的动态求值。现在已经有很多开源可用的 java 表达式求值引擎,为什么还需要 Avaitor 呢?

Aviator的设计目标是轻量级和高性能,相比于Groovy、JRuby的笨重, Aviator非常小, 加上依赖包也才 537K,不算依赖包的话只有 70K; 当然, Aviator的语法是受限的, 它不是一门完整的语言, 而只是语言的一小部分集合。

其次, Aviator的实现思路与其他轻量级的求值器很不相同, 其他求值器一般都是通过解释的方式运行, 而Aviator则是直接将表达式编译成 JVM 字节码, 交给 JVM 去执行。简单来说, Aviator的定位是介于 Groovy 这样的重量级脚本语言和 IKExpression 这样的轻量级表达式引擎之间。

AviatorScript 是一门高性能、轻量级寄宿于 JVM (包括 Android 平台)之上的脚本语言。

Aviator 使用场景

  1. 常见的公式计算
  2. 数据处理转换
  3. 数据核对
  4. 工作流逻辑判定
  5. 鉴权校验等等
  6. 动态脚本控制
  7. 规则判断及规则引擎

Aviator 的特性:

  1. 支持数字、字符串、正则表达式、布尔值、正则表达式等基本类型,完整支持所有 Java 运算符及优先级等。
  2. 函数是一等公民,支持闭包和函数式编程
  3. 内置 bigint/decmal 类型用于大整数和高精度运算,支持运算符重载得以让这些类型使用普通的算术运算符 +-*/ 参与运算。
  4. 完整的脚本语法支持,包括多行数据、条件语句、循环语句、词法作用域和异常处理等。
  5. 函数式编程结合 Sequence 抽象,便捷处理任何集合。
  6. 轻量化的模块系统
  7. 多种方式,方便地调用 Java 方法,完整支持 Java 脚本 API(方便从 Java 调用脚本)。
  8. 丰富的定制选项,可作为安全的语言沙箱和全功能语言使用。
  9. 轻量化,高性能,ASM 模式下通过直接将脚本翻译成 JVM 字节码,解释模式可运行于 Android 等非标 Java 平台
  10. 语法糖支持a.b.c.d
  11. 支持script执行


Aviator的设计是通过编译并动态生成字节码的方式将表达式编译成一个类,然后反射执行这个类

AviatorScript 文档: AviatorScript 文档 · 语雀

源码:GitHub - killme2008/aviatorscript: A high performance scripting language hosted on the JVM.

快速开始

推荐使用版本 5.2.6 及以上

1、POM.XML中引入AVIATOR依赖

  <dependency>
       <groupId>com.googlecode.aviator</groupId>
       <artifactId>aviator</artifactId>
       <version>5.2.6</version>
  </dependency>

2、基本使用

public static void main(String[] args) {

        System.out.println("-----------------------------------------------------------------");
        System.out.println("算术表达式【1+1】: " + AviatorEvaluator.execute("1+1"));
        System.out.println("逻辑表达式【1==1】: " + AviatorEvaluator.execute("1==1"));
        System.out.println("三元表达式【1==1 ? '对' : '错'】: " + AviatorEvaluator.execute("1==1 ? '对' : '错'"));

        System.out.println("正则表达式: " +  AviatorEvaluator.execute("'killme@2008gmail.com'=~/([\\w0-8]+@\\w+[\\.\\w+]+)/ ? $1:'unknow'"));
        System.out.println("-----------------------------------------------------------------");

        System.out.println("函数调用【6的3次方】: " + AviatorEvaluator.execute("math.pow(6,3)"));
        System.out.println("求字符串长度: " +       AviatorEvaluator.execute("string.length('hello')"));
        System.out.println("判断字符串是否包含字符串: " +     AviatorEvaluator.execute("string.contains('hello','h')"));
        System.out.println("是否以子串开头: " +     AviatorEvaluator.execute("math.pow(-3,2)"));
        System.out.println("求n次方: " +        AviatorEvaluator.execute("math.sqrt(14.0)"));
        System.out.println("正弦函数: " +      AviatorEvaluator.execute("math.sin(20)"));

        System.out.println("-----------------------------------------------------------------");


        Map env = new HashMap(16);
        env.put("yourname","aviator");
        String result3 = (String)AviatorEvaluator.execute(" 'hello ' + yourname ", env);
        System.out.println("变量和字符串相加:"+ result3);

        System.out.println("-----------------------------------------------------------------");

    }

 执行结果

-----------------------------------------------------------------
算术表达式【1+1】: 2
逻辑表达式【1==1】: true
三元表达式【1==1 ? '对' : '错'】: 对
正则表达式: killme@2008gmail.com
-----------------------------------------------------------------
函数调用【6的3次方】: 216.0
求字符串长度: 5
判断字符串是否包含字符串: true
是否以子串开头: 9.0
求n次方: 3.7416573867739413
正弦函数: 0.9129452507276277
-----------------------------------------------------------------
变量和字符串相加:hello aviator
-----------------------------------------------------------------
 

语法介绍

1、系统函数

函数名称

说明

assert(predicate, [msg])

断言函数,当 predicate 的结果为 false 的时候抛出 AssertFailed 异常, msg 错误信息可选。

sysdate()

返回当前日期对象 java.util.Date

rand()

返回一个介于 [0, 1) 的随机数,结果为 double 类型

rand(n)

返回一个介于 [0, n) 的随机数,结果为 long 类型

cmp(x, y)

比较 x 和 y 大小,返回整数,0 表示相等, 1 表达式 x > y,负数则 x < y。

print([out],obj)

打印对象,如果指定 out 输出流,向 out 打印, 默认输出到标准输出

println([out],obj)

或者

p([out], obj)

与 print 类似,但是在输出后换行

pst([out], e);

等价于 e.printStackTrace(),打印异常堆栈,out 是可选的输出流,默认是标准错误输出

now()

返回 System.currentTimeMillis() 调用值

long(v)

将值转为 long 类型

double(v)

将值转为 double 类型

boolean(v)

将值的类型转为 boolean,除了 nil 和 false,其他都值都将转为布尔值 true。

str(v)

将值转为 string 类型,如果是 nil(或者 java null),会转成字符串 'null'

bigint(x)

将值转为 bigint 类型

decimal(x)

将值转为 decimal 类型

identity(v)

返回参数 v 自身,用于跟 seq 库的高阶函数配合使用。

type(x)

返回参数 x 的类型,结果为字符串,如 string, long, double, bigint, decimal, function 等。Java  类则返回完整类名。

is_a(x, class)

当 x 是类 class 的一个实例的时候,返回 true,例如 is_a("a", String) ,class 是类名。

is_def(x)

返回变量 x 是否已定义(包括定义为 nil),结果为布尔值

undef(x)

“遗忘”变量  x,如果变量 x 已经定义,将取消定义。

range(start, end, [step])

创建一个范围,start 到 end 之间的整数范围,不包括 end, step 指定递增或者递减步幅。

tuple(x1, x2, ...)

创建一个 Object 数组,元素即为传入的参数列表。

eval(script, [bindings], [cached])

对一段脚本文本 script 进行求值,等价于 AviatorEvaluator.execute(script, env, cached)

comparator(pred)

将一个谓词(返回布尔值)转化为 java.util.Comparator 对象,通常用于 sort 函数。

max(x1, x2, x3, ...)

取所有参数中的最大值,比较规则遵循逻辑运算符规则。

min(x1, x2, x3, ...)

取所有参数中的最小值,比较规则遵循逻辑运算符规则。

constantly(x)

用于生成一个函数,它对任意(个数)参数的调用结果 x。

2、字符串函数

date_to_string(date,format)

将 Date 对象转化化特定格式的字符串,2.1.1 新增

string_to_date(source,format)

将特定格式的字符串转化为 Date 对 象,2.1.1 新增

string.contains(s1,s2)

判断 s1 是否包含 s2,返回 Boolean

string.length(s)

求字符串长度,返回 Long

string.startsWith(s1,s2)

s1 是否以 s2 开始,返回 Boolean

string.endsWith(s1,s2)

s1 是否以 s2 结尾,返回 Boolean

string.substring(s,begin[,end])

截取字符串 s,从 begin 到 end,如果忽略 end 的话,将从 begin 到结尾,与 java.util.String.substring 一样。

string.indexOf(s1,s2)

java 中的 s1.indexOf(s2),求 s2 在 s1 中 的起始索引位置,如果不存在为-1

string.split(target,regex,[limit])

Java 里的 String.split 方法一致,2.1.1 新增函数

string.join(seq,seperator)

将集合 seq 里的元素以 seperator 为间隔 连接起来形成字符串,2.1.1 新增函数

string.replace_first(s,regex,replacement)

Java 里的 String.replaceFirst 方法, 2.1.1 新增

string.replace_all(s,regex,replacement)

Java 里的 String.replaceAll 方法 , 2.1.1 新增

3、数学函数

math.abs(d)

求 d 的绝对值

math.round(d)

四舍五入

math.floor(d)

向下取整

math.ceil(d)

向上取整

math.sqrt(d)

求 d 的平方根

math.pow(d1,d2)

求 d1 的 d2 次方

math.log(d)

求 d 的自然对数

math.log10(d)

求 d 以 10 为底的对数

math.sin(d)

正弦函数

math.cos(d)

余弦函数

math.tan(d)

正切函数

math.atan(d)

反正切函数

math.acos(d)

反余弦函数

math.asin(d)

反正弦函数

4、语法糖

public class TestAviator1 {

    public static void main(String[] args) {

        Foo foo = new Foo(100, 3.14f, new Date());
        Map<String, Object> env = new HashMap<>();
        env.put("foo", foo);

        String result =
                (String) AviatorEvaluator.execute(
                        " '[foo i='+ foo.i + ' f='+foo.f+' year='+(foo.date.year+1900)+ ' month='+foo.date.month +']' ",
                        env);

        System.out.println("执行结果:"+result);
    }

    public static class Foo{
        int i;
        float f;
        Date date = new Date();

        public Foo(int i, float f, Date date) {
            super();
            this.i = i;
            this.f = f;
            this.date = date;
        }

        public int getI() {
            return i;
        }

        public float getF() {
            return f;
        }

        public Date getDate() {
            return date;
        }

    }
}
执行结果
[foo i=100 f=3.14 year=2022 month=3]

集合处理

List<Map<String,Object>> list1=new ArrayList<>();
Map<String,Object> map1=new HashMap<>();
map1.put("name","我看那水");
map1.put("address","傻吊奥迪阿萨斯短时");
list1.add(map1);
map1=new HashMap<>();
map1.put("name","奥斯卡");
map1.put("address","地方进去恢复期计划和");
list1.add(map1);


List<Map<String,Object>> list=new ArrayList<>();

Map<String,Object> map=new HashMap<>();
map.put("coco",list1);
map.put("flag","收到货后");
list.add(map);
map=new HashMap<>();
map.put("coco",list1);
map.put("flag","爱莎");
list.add(map);

Map<String,Object> env=new HashMap<>();
env.put("data",list);

System.out.println( AviatorEvaluator.execute("#data.[1].flag", env, true));

System.out.println( AviatorEvaluator.execute("#data.[0].coco.[0].name", env, true));

 执行结果

爱莎
我看那水

5、自定义函数

/**
 * 判断函数
 *
 * @author carson deng
 * @data 2021/08/06
 */
public class IfFunction extends AbstractFunction {

    /**
     * IF(bool,A,B)
     *
     * @param env  数据源
     * @param arg1 条件值
     * @param arg2 值1
     * @param arg3 值2
     * @return
     */
    @Override
    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {

        Boolean flag = FunctionUtils.getBooleanValue(arg1, env);

        return AviatorRuntimeJavaType.valueOf(flag ? arg2.getValue(env) : arg3.getValue(env));
    }

    /**
     * IF(bool,rule,A,B)
     *
     * @param env  数据源
     * @param arg1 条件值
     * @param arg2 KEY对应关系数据 target
     * @param arg3 规则对象1  MAP 对象
     * @param arg4 规则对象2  MAP 对象
     * @return
     */
    @Override
    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4) {

        Boolean flag = FunctionUtils.getBooleanValue(arg1, env);

        Map<String, Object> target = (Map<String, Object>) FunctionUtils.getJavaObject(arg2, env);
        Map<String, Object> rule;
        if (flag) {
            rule = (Map<String, Object>) FunctionUtils.getJavaObject(arg3, env);
        } else {
            rule = (Map<String, Object>) FunctionUtils.getJavaObject(arg4, env);
        }

        Map<String, Object> result = new HashMap<>(target.size());

        for (String key : rule.keySet()) {
            result.put(key, target.get(rule.get(key)));
        }

        return AviatorRuntimeJavaType.valueOf(result);
    }

    /**
     * 函数名称
     *
     * @return
     */
    @Override
    public String getName() {
        return "fpx.if";
    }
}

使用自定义函数

      //自定义函数执行
        AviatorEvaluator.addFunction(new IFFunction());

        Map env1 = new HashMap(16);
        env.put("yourname","aviator");
        String result4 = (String)AviatorEvaluator.execute("IF(yourname=='aviator','我是aviator','我不是aviator')", env);
        System.out.println("自定义函数:"+ result4);

执行结果

自定义函数:我是aviator

6、调用 Java 类方法和 Function Missing

默认情况下, aviator 能调用的函数列表是受限的,这是基于安全和控制的角度考虑,不允许表达式调用任意方法。

如果你想调用某个对象的 java 方法,aviator 提供了下列两种方式:

private static class TestFunctionMissing implements FunctionMissing {

    @Override
    public AviatorObject onFunctionMissing(final String name, final Map<String, Object> env,
        final AviatorObject... args) {
      // 当实现并设置了该处理器后,没有找到的函数调用都将调用该处理器执行
      System.out.println(
          "Function not found, name=" + name + ", env=" + env + ", args=" + Arrays.toString(args));
      return FunctionUtils.wrapReturn(name);
    }

  }

  public static void main(final String[] args) {
    // Set function missing handler.
    AviatorEvaluator.setFunctionMissing(new TestFunctionMissing());

    System.out.println(AviatorEvaluator.execute("test(1,2,3)"));
    System.out.println(AviatorEvaluator.execute("not_found(1,2,3)"));
  }

  • 性能相比自定义函数较差,接近 3 倍的差距,原因也是反射。
  • 无法调用静态方法,静态方法调用仍然需要采用其他两种方式。
  • 如果第一个参数为 null,无法找出方法,因为没有对象  class 信息。

函数加载java静态方法

       //调用java静态方法
AviatorEvaluator.addStaticFunctions("str", StringUtils.class);
System.out.println(AviatorEvaluator.execute("str.isNotBlank('hello')"));
//调用java方法
AviatorEvaluator.addInstanceFunctions("s", String.class);
System.out.println(AviatorEvaluator.execute("s.indexOf('hello','l')"));

7、调用脚本函数

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class InvokeScriptFunction {
  public static void main(final String[] args) throws Exception {
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("AviatorScript");

    // AviatorScript code in a String
    String script = "fn hello(name) { print('Hello, ' + name); }";
    // evaluate script
    engine.eval(script);

    // javax.script.Invocable is an optional interface.
    // Check whether your script engine implements or not!
    // Note that the AviatorScript engine implements Invocable interface.
    Invocable inv = (Invocable) engine;

    // invoke the global function named "hello"
    inv.invokeFunction("hello", "Scripting!!" );
  }
}

5、SpringBoot 整合 相关配置介绍

最佳实践:最佳实践 · 语雀

/**
 * 初始化表达式
 *
 * @author carson deng
 * @data 2021/08/17
 */
@Configuration
public class FunctionConfig {

    @PostConstruct
    public void init() {

//      AviatorEvaluator.EVAL,默认值,以运行时的性能优先,编译会花费更多时间做优化,目前会做一些常量折叠、公共变量提取的优化。适合长期运行的表达式。 表达式经常不会变化。
//      AviatorEvaluator.COMPILE 不会做任何编译优化,牺牲一定的运行性能,适合需要频繁编译表达式的场景, 比如经常编译不同的表达式。
        //执行优先
        AviatorEvaluator.setOption(Options.OPTIMIZE_LEVEL, AviatorEvaluator.EVAL);
        //编译优先  你可以修改为编译速度优先,这样不会做编译优化:
        //AviatorEvaluator.setOption(Options.OPTIMIZE_LEVEL, AviatorEvaluator.COMPILE);

        //打开跟踪执行 默认关闭
        AviatorEvaluator.setOption(Options.TRACE_EVAL, true);
        
        //启用属性访问语法时,如果未找到属性值或引发异常,返回NULL  默认值为false 设置为true
        AviatorEvaluator.setOption(Options.NIL_WHEN_PROPERTY_NOT_FOUND, true);
        
        //计算精度 java.util.MathContext.DECIMAL128
        AviatorEvaluator.setOption(Options.MATH_CONTEXT, MathContext.DECIMAL128);

        //浮点数解析
        //是否将整型数字都解析为 BigDecimal,默认为 false,也就是不启用。在所有数字都是需要高精度计算的场景,结合 ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL 选项,可以减少一些类型转换。
        AviatorEvaluator.setOption(Options.ALWAYS_PARSE_INTEGRAL_NUMBER_INTO_DECIMAL, false);

        //解析浮点数 默认 false
        //是否将所有浮点数解析为 Decimal 类型,适合需要高精度运算的场景,并且不想为每个浮点数字指定 M 后缀(表示 Decimal 类型)。默认为 false 不开启。
        AviatorEvaluator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL, false);
        
         /**
         * 正则分组捕获 默认为 true 开启
         * email=~/([\\w0-8]+)@\\w+[\\.\\w+]+/ ? $1:'unknow'
         * 将 email 变量中的用户名部分(@ 符号之前)匹配出来,并放到 $1变量中,如果关闭 PUT_CAPTURING_GROUPS_INTO_ENV(设置为 false),将不会将捕获的分组放入 env,也就无法获取到匹配的分组。默认为 true 开启。
         */
        AviatorEvaluator.setOption(Options.PUT_CAPTURING_GROUPS_INTO_ENV, true);

        /**
         * 变量语法糖
         * 是否启用变量访问的语法糖,默认情况下 Aviator 会通过 commons-beantuils 反射访问类似 a.b.c 这样的嵌套 JavaBean 变量,或者 #list.[0].name 这样的数组(链表)中的元素。但是部分用户可能想关闭这个行为,强制都从 env 中获取这些变量值,那么就可以将该选项关闭,也就是设置为 false。默认为 true 开启。
         */
        AviatorEvaluator.setOption(Options.ENABLE_PROPERTY_SYNTAX_SUGAR, true);

        /**
         * Env 处理
         * 从 4.0 开始,为了支持 lambda, aviator 引入了变量作用域 scope 的概念,本来的默认行为是不再修改用户传入的 env 对象,但是后面看到比较多的用户依赖这个行为,因此提供了这个新选项 USE_USER_ENV_AS_TOP_ENV_DIRECTLY,当为 true 的时候就会将用户传入的 env 作为最顶层的作用域 scope 来使用,并且默认为 true 启用。如果你不需要 aviator 产生副作用污染你传入的 env,这个选项更推荐设置为 false
         */
        AviatorEvaluator.setOption(Options.USE_USER_ENV_AS_TOP_ENV_DIRECTLY, true);
        
         /**
         * 参数捕获 默认false
         */
        AviatorEvaluator.setOption(Options.CAPTURE_FUNCTION_ARGS, false);
        
          /**
         * 循环次数控制
         * 限制循环语句的最大次数,这个循环包括 for 语句、 while 循环语句以及 map, filter, some 等任何涉及 sequence 遍历的高阶函数。用于限制用户传入的脚本执行循环的次数,避免死循环或者耗费大量 CPU 的场景出现。
         *
         * 默认值: 0,表示无限制。
         * 可以设置为任意正整数,比如 5000,表示单次循环最大次数是 5000。
         */
        AviatorEvaluator.setOption(Options.MAX_LOOP_COUNT, 0);
        
         /**
         * 语法特性 设置 AviatorScript 支持的语法特性集合,它接受的是一个 Set<Feature>  的集合
         */
        AviatorEvaluator.setOption(Options.FEATURE_SET,  Feature.asSet(Feature.Assignment,
                Feature.ForLoop,
                Feature.WhileLoop,
                Feature.Lambda,
                Feature.Let));

        /**
         * 类的白名单:ALLOWED_CLASS_SET
         * 请注意:
         * ● null 表示不限制(默认值)
         * ● 空集合表示禁止任何 class
         */
        AviatorEvaluator.setOption(Options.ALLOWED_CLASS_SET, (new HashSet<Object>()).add(ArrayBlockingQueue.class));

        
        //设置默认缓存表达式结果
        AviatorEvaluator.getInstance().setCachedExpressionByDefault(true);
        //设置LRU缓存
        AviatorEvaluator.getInstance().useLRUExpressionCache(20000);
    }
}

参数捕获:CAPTURE_FUNCTION_ARGS

是否捕获函数调用点的参数列表,如果启用,那么类似 func 这样的自定义函数:

func(a, b, c, 100+2)

这样的表达式,就可以在 func 内得到调用的参数列表,

@Override
public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
                          
                          final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4) {
    
    List<FunctionArgument> args = FunctionUtils.getFunctionArguments(env);
    
    ......
        
   }

得到的 args 就是参数列表:

[FunctionArgument, index=0, expression="a"]
[FunctionArgument, index=1, expression="b"]
[FunctionArgument, index=2, expression="c"]
[FunctionArgument, index=3, expression="100+2"]

你可以直接从 env 中通过 __args__ 变量直接获取:

List<FunctionArgument> args = (List<FunctionArgument>)env.get("__args__");

在 lambda 表达式中也可以捕获参数列表并使用,捕获的调用参数列表存放在 __args__ 变量:

List<FunctionArgument> args = (List<FunctionArgument>) AviatorEvaluator
        .execute("f = lambda(a,bc, d) -> __args__ end; f(1,2,100+2)");

assertEquals(3, args.size());
System.out.println(args);
assertEquals(0, args.get(0).getIndex());
assertEquals("1", args.get(0).getExpression());
assertEquals(1, args.get(1).getIndex());
assertEquals("2", args.get(1).getExpression());
assertEquals(2, args.get(2).getIndex());
assertEquals("100+2", args.get(2).getExpression());

利用这一特性,你可以在运行时对调用的参数做参数校验或者分支派发,以及对于函数调用过程做优化,例如对针对参数做结果缓存等等。不过这一特性会对性能带来稍许损失。

语法特性:FEATURE_SET

设置 AviatorScript 支持的语法特性集合,它接受的是一个 Set<Feature>  的集合,Feature 包括:

  • Assignment  赋值
  • Return  返回语句
  • If  条件语句
  • ForLoop    for 循环语句,包括 break/continue。
  • WhileLoop  while 循环语句,包括 break/continue
  • Let  局部变量定义 let 语句
  • LexicalScope  大括号定义词法作用域
  • Lambda   匿名函数 lambda 定义
  • Fn    命名函数的 fn 定义
  • InternalVars  内部变量,如 __instance__ 、 __env__ 等。
  • Module   模块系统,包括 exports 和 require/load 函数
  • ExceptionHandle  异常处理,包括 try/catch/finally/throw 语句
  • NewInstance  创建对象的 new 语法支持
  • StringInterpolation 字符串插值
  • Use 是否启用 use 语法导入 java 类到当前上下文,方便 new 或者 catch 异常类等。
  • StaticFields 是否启用静态字段直接访问,类似 Long.MAX_VALUE 等。
  • StaticMethods 是否启用静态方法直接使用(基于反射),类似 Math.abs(d) 等

你可以自定义语法特性集合:

/**
 * Configure engine example
 *
 * @author dennis(killme2008@gmail.com)
 *
 */
public class ConfigureInstanceExample {

  public static void main(final String[] args) {
    AviatorEvaluatorInstance instance = AviatorEvaluator.newInstance();

    instance.setOption(Options.USE_USER_ENV_AS_TOP_ENV_DIRECTLY, false);
    instance.setOption(Options.FEATURE_SET,
        Feature.asSet(Feature.Assignment, 
                      Feature.ForLoop, 
                      Feature.WhileLoop,
                      Feature.Lambda,
                      Feature.Let));

    System.out.println(instance
        .execute("let square = lambda(x) -> x*2 end; for x in range(0, 10) { p(square(x)); }"));
  }
}

这里我们启用了赋值、循环、let 以及 lambda 语法支持,然后执行一个简单脚本。 Feature.asSet 方法方便地生成一个语法特性集合。

如果我们没有启用某个语法特性,执行引擎将报错,比如假设我们将上面的 Feature.Let 移除:

Exception in thread "main" com.googlecode.aviator.exception.UnsupportedFeatureException: Feature.Let is not enabled
	at com.googlecode.aviator.parser.ExpressionParser.ensureFeatureEnabled(ExpressionParser.java:138)
	at com.googlecode.aviator.parser.ExpressionParser.statement(ExpressionParser.java:1364)
	at com.googlecode.aviator.parser.ExpressionParser.statements(ExpressionParser.java:1493)
	at com.googlecode.aviator.parser.ExpressionParser.parse(ExpressionParser.java:920)
	at com.googlecode.aviator.AviatorEvaluatorInstance.innerCompile(AviatorEvaluatorInstance.java:1293)
	at com.googlecode.aviator.AviatorEvaluatorInstance.compile(AviatorEvaluatorInstance.java:1256)
	at com.googlecode.aviator.AviatorEvaluatorInstance.compile(AviatorEvaluatorInstance.java:1207)
	at com.googlecode.aviator.AviatorEvaluatorInstance.execute(AviatorEvaluatorInstance.java:1383)
	at com.googlecode.aviator.AviatorEvaluatorInstance.execute(AviatorEvaluatorInstance.java:1400)
	at com.googlecode.aviator.AviatorEvaluatorInstance.execute(AviatorEvaluatorInstance.java:1436)
	at com.googlecode.aviator.example.ConfigureInstanceExample.main(ConfigureInstanceExample.java:24)

这个选项的默认值是 Feature.getFullFeatures() ,也就是启用所有的语法特性,如果你想使用 5.0 之前的兼容模式,只启用赋值、lambda 以及内部变量,可以用 Feature.getCompatibleFeatures() 。

禁用和启用单个选项可以通过 AviatorEvaluatorInstance 的 enableFeature(feature) 和 disableFeature(feature) 方法。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值