当前位置:   article > 正文

QLExpress 规则引擎_expressrunner

expressrunner

来自:QLExpress代码解读,运行原理解析

1. 概览

在这里插入图片描述

ExpressRunner.execute()实质分成两个步骤

//(1)将规则脚本编译成指令集:string -> InstructionSet
parseResult = this.parseInstructionSet(expressString);

//(2)指令集绑定上下文进行执行:InstructionSet + context ->Object
InstructionSetRunner.executeOuter(this,parseResult,this.loader,context, errorList,isTrace,false,aLog,false)
  • 1
  • 2
  • 3
  • 4
  • 5

通过设置ExpressRunner.execute()isCache入参,
编译得到的指令集就会以Map的形式,被缓存在ExpressRunner实例的内部对象里

2. 脚本编译过程:compile

	//ExpressRunner.java
	/**
     * 解析一段文本,生成指令集合
     */
    public InstructionSet parseInstructionSet(String text)
    {
       //(1)token分解
       Word[] words = WordSplit.parse(this.nodeTypeManager.splitWord,express);
       
       //(2)token解析
       List<ExpressNode> tempList = this.transferWord2ExpressNode(rootExpressPackage,words,selfDefineClass,true);
       
       //(3)匹配AST语法树
       QLMatchResult result = QLPattern.findMatchStatement(this.nodeTypeManager, this.nodeTypeManager.findNodeType("PROGRAM").getPatternNode(), tempList,0);
       result.getMatchs().get(0).buildExpressNodeTree();
       
        ExpressNode root =(ExpressNode)result.getMatchs().get(0).getRef();
        resetParent(root,null);
       
       //(4)生成指令集合
       InstructionSet result = createInstructionSet(root, "main");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  1. 输入文本:
sum=0;for(i=0;i<10;i=i+1){sum=sum+i;};return sum;
  • 1
  1. token分解:
    使用分隔符号(空格、换行、位操作、四则运算、Boolean运算符号)将String分解为Word[]:words = "sum",”=“,”0“,”;“,"for","(","i",......

  2. token解析:

    • 根据 Word 的值判断类型:数字、字符串、boolean、关键字等
    • 然后根据 Word 的值和类型构造 ExpressNode
  3. 匹配AST语法树
    根据KeyWordDefine4Java.java定义的推导文法,递归的构造出一棵AST(抽象语法树)

    • ExpressNode 包含父节点、子节点的List、type(Block、Break、Cast、CallFunction、If、In)
    • KeyWordDefine4Java中定义了如何split、有哪些关键词等等
  4. 生成指令集合

    • 通过工厂模式InstructionoFactoryExpressNode转换为InstructionSet
    • 不同的InstructionSet有不同的excute方法
1:LoadAttr:sum
2:LoadData 0
3:OP : = OPNUMBER[2]
4:openNewArea
5:clearDataStack
6:LoadAttr:i
7:LoadData 0
8:OP : = OPNUMBER[2]
9:clearDataStack
10:LoadAttr:i
11:LoadData 10
12:OP : < OPNUMBER[2]
13:GoToIf[false,isPop=true] +13
......
29:return [value]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3. 使用归纳总结

  • QLExpress属于弱类型脚本语言,一般不推荐声明局部变量的类型。语法编译阶段不会做类型校验,也不会做方法的参数校验,所以很灵活
  • QLExpress在运行时解析和执行表达式,相比于静态编译,它的编译过程更加轻量化和灵活。
  • QLExpress整个运算过程是通过threadLocal来保证线程安全的。
  • QLExpress的脚本编译过程比较耗时,但是是上下文无关的,所以同一个脚本运行缓存之后性能提升非常明显。
  • QLExpress指令计算运算过程中,基本不会new新对象,是通过缓存池技术来尽量减少资源的消耗。
  • QLExpress的宏,function,Operator,变量是非常开放的,名字可以为中文字符,也可以随意扩展,还可以通过脚本静态分析出包含哪些变量、函数,很方便的进行二次业务开发。
  • 脚本调用classLoader资源的时候可以import,也可以使用类的全路径,构造函数、静态方法、对象方法、类的字段、函数的不定参数调用统统搞定。
  • QLExpress的这套自定义的指令集属于解析执行,RunEnvironment中通过programPoint函数指针的跳转来实现每条指令的逐个计算,通过dataContainer作为栈来存储中间计算结果。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/742766
推荐阅读
相关标签
  

闽ICP备14008679号