指令系统
助记符 | 指令代码 | 含义 |
---|---|---|
构造指令 | ||
LDC_D | 11 | 将数字压入栈(例:LDC_D 12345) |
LDC_B | 12 | 将布尔数据压入栈(例:INSN_B true) |
LDC_S | 13 | 将字符串数据压入栈(例:LDC_S “ssssss”) |
LDC_N | 14 | 将null压入栈(例:INSN_N) |
NEW_O | 15 | 构造一个键值对对象并压入栈 |
NEW_A | 16 | 构造一个集合对象并压入栈 |
存储指令 | ||
STORE | 21 | 栈顶数据存储到堆(例:STORE,2) |
LOAD | 22 | 从指定深度的堆中加载n号元素到栈(例:LOAD 1 ,1 ) |
GET | 23 | 获取栈顶对象元素的属性(例:GET,”xxxx”) |
PUT | 24 | 将栈顶对象元素放入对象元素中(例:GET,”xxxx”) |
PULL | 25 | 获取集合的指定索引元素。(例:PULL 123) |
PUSH | 26 | 将栈顶元素压入集合(例:PUSH) |
结束指令 | ||
EXIT | 31 | 结束所有指令序列的执行并返回数据和状态 |
RETURN | 32 | 结束当前指令序列的执行,并返回数据和状态给上一个指令序列。 |
THROW | 33 | 结束所有指令序列的执行,并抛出异常 |
运算指令 | ||
UO | 41 | 一元运算 |
DO | 42 | 二元运算,堆栈结构:【第一个操作数,第二个操作数】 |
TYPEOF | 43 | 计算值的类(string、number、boolean、object、list、udf、null) |
控制指令 | ||
IF | 51 | 如果条件判断失败那么 GOTO 到指定位置,否则继续往下执行 |
GOTO | 52 | 执行跳转 |
CAST_I | 53 | 将栈顶元素转换为迭代器 |
CAST_O | 54 | 将栈顶元素转换为一个对象,如果是集合那么取第一条记录 |
E_PUSH | 55 | 取出当前栈顶数据,并压入环境栈 |
E_POP | 56 | 丢弃环境栈顶的元素 |
E_LOAD | 57 | 加载环境栈顶的数据到数据栈 |
LOAD_C | 58 | 加载自定义路由 |
POP | 59 | 丢弃栈顶数据 |
函数指令 | ||
CALL | 61 | 发起服务调用(例:CALL,2) |
M_DEF | 62 | 函数定义,将栈顶元素转换为 UDF |
M_REF | 63 | 引用另一处的指令序列地址,并将其作为 UDF 形态存放到栈顶 |
M_TYP | 64 | 加载一个类型对象到栈顶,该类型是一个有效的 UDF。 |
M_FRAG | 65 | 引用外部片段执行器,并将其作为 UDF 形态存放到栈顶 |
LOCAL | 66 | 将入参存入堆,也用于标记变量名称 |
辅助指令 | ||
HINT | 71 | 设置 Hint,影响执行引擎的参数选项。 |
LABEL | 72 | 协助GOTO定位用,无实际作用 |
LINE | 73 | 行号,无实际作用 |
构造指令
LDC_D
定义数字,将数字压入栈(例:LDC_D 12345)
- 参数说明:共 1 参数;参数 1:数据;
- 栈行为:消费 0,产出 1
- 堆行为:无
代码:return 134
指令:
#00 LDC_D 134
#01 RETURN 0
LDC_B
定义布尔,将布尔数据压入栈(例:LDC_B true)
- 参数说明:共 1 参数;参数 1:数据;
- 栈行为:消费 0,产出 1
- 堆行为:无
代码:return true
指令:
#00 LDC_B true
#01 RETURN 0
LDC_S
定义字符串,将字符串数据压入栈(例:LDC_S "ssssss")
- 参数说明:共 1 参数;参数 1:数据;
- 栈行为:消费 0,产出 1
- 堆行为:无
代码:return "ssss"
指令:
#00 LDC_S ssss
#01 RETURN 0
LDC_N
定义 NULL,将 null 压入栈(例:LDC_N)
- 参数说明:共 0 参数;
- 栈行为:消费 0,产出 1
- 堆行为:无
代码:return null
指令:
#00 LDC_N
#01 RETURN 0
NEW_O
定义对象,构造一个键值对对象并压入栈
- 参数说明:共 0 参数;
- 栈行为:消费 0,产出 1
- 堆行为:无
代码1:return {}
指令1:
#00 NEW_O
#01 RETURN 0
代码2:return {'field_1':'f1','field_2':'f2'}
指令2:
#0 NEW_O
...(部分略)...
#5 RETURN 0
NEW_A
定义集合,构造一个集合对象并压入栈
- 参数说明:共 0 参数;
- 栈行为:消费 0,产出 1
- 堆行为:无
代码1:return []
指令1:
#00 NEW_A
#01 RETURN 0
代码2:return [1,2,3]
指令2:
#0 NEW_A
...(部分略)...
#7 RETURN 0
存储指令
STORE
堆保存操作,栈顶数据存储到堆(例:STORE,2)
- 参数说明:共 1 参数;参数 1 :存入堆的位置;
- 栈行为:消费 1,产出 0
- 堆行为:存入数据
代码:var a = 123 ; return a
指令:
#0 LDC_D 123
#1 STORE 0
#2 LOAD 0, 0
#3 RETURN 0
LOAD
堆读取操作,从指定深度的堆中加载n号元素到栈(例:LOAD 1 ,1 )
- 参数说明:共 2 参数;参数 1:堆深度(栈顶深度为 0);参数 2:元素序号;
- 栈行为:消费 0,产出 1
- 堆行为:取出数据(不删除)
代码:var a = 123 ; return a
指令:
#0 LDC_D 123
#1 STORE 0
#2 LOAD 0, 0
#3 RETURN 0
GET
从对象中读取数据,获取栈顶对象元素的属性(例:GET,"xxxx")
- 参数说明:共 1 参数;参数 1:属性名称(Map 的 Key 或 对象的属性名)
- 栈行为:消费 1,产出 1
- 堆行为:无
代码:var a = {'abc':true} ; return a.abc
指令: ...(部分略)...
#4 LOAD 0, 0
#5 GET abc
#6 RETURN 0
PUT
向对象写入数据,将栈顶对象元素放入对象元素中(例:PUT,"xxxx")
- 参数说明:共 1 参数;参数 1:属性名称(Map 的 Key 或 对象的属性名)
- 栈行为:消费 1,产出 0
- 堆行为:无
代码:return {'field_1':'f1','field_2':'f2'}
指令:
#0 NEW_O
#1 LDC_S f1
#2 PUT field_1
#3 LDC_S f2
#4 PUT field_2
#5 RETURN 0
PULL
从集合中获取数据,栈顶元素是一个集合类型,获取集合的指定索引元素。(例:PULL 123)
- 参数说明:共 1 参数;参数 1:元素位置(负数表示从后向前,正数表示从前向后)
- 栈行为:消费 1,产出 1
- 堆行为:无
代码:var a = [1,2,3,4,5] ; return a指令:
...(部分略)...
#11 STORE 0
#12 LOAD 0, 0
#13 PULL 2
#14 RETURN 0
PUSH
向对象中写入数据,将栈顶元素压入集合(例:PUSH)
- 参数说明:共 0 参数;
- 栈行为:消费 1,产出 0
- 堆行为:无
代码:return [1,2,3]
指令:
...(部分略)...
#1 LDC_D 1
#2 PUSH
#3 LDC_D 2
#4 PUSH
...(部分略)...
COPY
将栈顶的元素 Copy 一个(浅拷贝)
- 参数说明:共 0 参数;
- 栈行为:消费 0,产出 1
- 堆行为:无
代码:return abc[a]
指令:
[0]
#000 E_LOAD #
#001 GET abc
#002 E_LOAD #
#003 GET a
#004 COPY
#005 TYPEOF
#006 COPY
#007 LDC_S string
#008 DO ==
...(部分略)...
结束指令
EXIT
终止所有后续指令的执行并正常退出。结束所有指令序,执行并返回数据和状态
- 参数说明:共 1 参数;参数 1:退出码
- 栈行为:消费 1,产出 0
- 堆行为:无
代码:exit 123 , []
指令:
#0 NEW_A
#1 EXIT 123
RETURN
终止当前指令序列的执行并正常退出。结束当前指令序列的执行,并返回数据和状态给上一个指令序列。如果没有上一个指令序列那么结束整个查询
- 参数说明:共 1 参数;参数 1:返回码
- 栈行为:消费 1,产出 0
- 堆行为:无
代码:return 123 , []
指令:
#0 NEW_A
#1 RETURN 123
THROW
终止所有后续指令的执行并抛出异常。结束所有指令序列的执行,并抛出异常
- 参数说明:共 1 参数;参数 1:错误码
- 栈行为:消费 1,产出 0
- 堆行为:无
代码:throw 123 , []
指令:
#0 NEW_A
#1 THROW 123
计算指令
UO
一元运算。一元操作符有:"!" 对 boolean 值进行取反,"-",对 number 值取相反值。
- 参数说明:共 1 参数;参数 1:一元操作符
- 栈行为:消费 1,产出 1
- 堆行为:无
代码:return -(-1)
指令:
#0 LDC_D -1
#1 UO -
#2 RETURN 0
DO
二元运算。堆栈【第一个操作数,第二个操作数】支持的运算参考 语法 -> 运算符
- 参数说明:共 1 参数;参数 1:二元操作符
- 栈行为:消费 2,产出 1
- 堆行为:无
代码:return 1 + 2
指令:
#0 LDC_D 1
#1 LDC_D 2
#2 DO +
#3 RETURN 0
TYPEOF
计算堆栈顶元素的类型
- 参数说明:共 1 参数;参数 1:二元操作符
- 栈行为:消费 1,产出 1
- 堆行为:无
产出的数据类型为字符产,取值如下表:
类型字符 | 含义 |
---|---|
string | 通过 typeOf 计算得到的类型是 字符串。 |
number | 通过 typeOf 计算得到的类型是 数字。 |
boolean | 通过 typeOf 计算得到的类型是 布尔值。 |
vobject | 通过 typeOf 计算得到的类型是 对象。 |
list | 通过 typeOf 计算得到的类型是 集合。 |
udf | 通过 typeOf 计算得到的类型是 Udf 或 Lambda函数。 |
null | 通过 typeOf 计算得到的类型是 NULL 或 不存在这个属性。 |
代码:return abc[a]
指令:
[0]
#000 E_LOAD #
#001 GET abc
#002 E_LOAD #
#003 GET a
#004 COPY
#005 TYPEOF
#006 COPY
#007 LDC_S string
...
控制指令
IF
条件判断。如果条件判断失败那么 GOTO 到指定位置,否则继续往下执行
- 参数说明:共 1 参数;参数 1:GOTO 的位置
- 栈行为:消费 1,产出 0
- 堆行为:无
代码:if (1 == 1) return true; else return false
指令:
...(部分略)...
#02 DO ==
#03 IF 7 <- 如果判断失败那么跳转到 #07 行指令
...(部分略)...
#07 LABEL 7 <- LABEL 7 之后的相当于 else 部分
...(部分略)...
GOTO
执行跳转,指令执行序列指针跳转,DataQL 语言本身并不支持 goto 语句。goto 的产生会在 if/数组类型结果转换时产生。
- 参数说明:共 1 参数;参数 1:GOTO 的位置
- 栈行为:消费 0,产出 0
- 堆行为:无
代码:if (1 == 1) return true; else return false
指令:
...(部分略)...
#06 GOTO 11 <- 通常 goto 会跳转到一个 LABEL 指令上
...(部分略)...
#11 LABEL 11
CAST_I
类型转换指令(转换为迭代器)。将栈顶元素转换为迭代器,作为迭代器有三个特殊操作:data(数据)、next(移动到下一个,如果成功返回true)
- 参数说明:共 0 参数
- 栈行为:消费 1,产出 1
- 堆行为:无
代码:return a => [ field1 ]
指令:
...(部分略)...
#01 GET a
#02 CAST_I
#03 E_PUSH
...(部分略)...
CAST_O
类型转换指令(转换为对象),将栈顶元素转换为一个对象,如果是集合那么取第一条记录(可以通过 CAST_I 方式解决,但会多消耗大约8条左右的指令)
- 参数说明:共 0 参数
- 栈行为:消费 1,产出 1
- 堆行为:无
代码:return a => { 'field1','field2' }
指令:
...(部分略)...
#01 GET a
#02 CAST_O
#03 E_PUSH
...(部分略)...
LOAD_C
加载用户数据集,通过 CustomizeScope 接口获取用户数据集
- 参数说明:共 1 参数;参数 1:@#$ 符号之一
- 栈行为:消费 0,产出 1
- 堆行为:无
代码:return ${a}.b
指令:
#0 LOAD_C $ <- 可能的符号参数有三个"@#$",例如:${a} 产生 $,#{a} 产生 #
#1 GET a
#2 GET b
#3 RETURN 0
POP
丢弃栈顶数据。丢弃栈顶数据,该指令目前在编译结果转换时会通过转换语句优化产生,平常语句不会编译出该指令。
- 参数说明:共 0 参数;
- 栈行为:消费 1,产出 0
- 堆行为:无
代码:return a => []
指令:
#0 E_LOAD #
#1 GET a
#2 POP
#3 NEW_A
#4 RETURN 0
E_PUSH
数据交换到环境栈。取出当前栈顶数据,并压入环境栈。通常和 CAST_I 与 CAST_O 联合出现,每一个 E_PUSH 都会存在一个对应的 E_POP。
- 参数说明:共 0 参数;
- 栈行为:消费 1,产出 0
- 环境栈行为:消费 0,产出 1
- 堆行为:无
代码:return a => { 'field1','field2' }
指令:
...(部分略)...
#01 GET a
#02 CAST_O
#03 E_PUSH
...(部分略)...
#11 E_POP
#12 RETURN 0
E_POP
丢弃环境栈元素。
- 参数说明:共 0 参数;
- 栈行为:消费 0,产出 0
- 环境栈行为:消费 1,产出 0
- 堆行为:无
代码:return a => [ field1 ]
指令:
...(部分略)...
#01 GET a
#02 CAST_I
#03 E_PUSH
...(部分略)...
#18 E_POP
#19 RETURN 0
E_LOAD
数据从环境栈交换到数据栈,加载环境栈顶的数据到数据栈,一个有效的 E_LOAD 前面肯定会有一个 E_PUSH;除此之外E_LOAD也有单独出现的时候,但通常都不具备运行上的任何意义。 例如:"return a => []" 的编译结果中的 E_LOAD 就拿不到任何数据,除了编译毫无任何意义。因为根层的 E_LOAD 数据肯定是空的。
- 参数说明:共 1 参数;参数 1:操作符号 @#$
- 栈行为:消费 0,产出 1
- 环境栈行为:消费 0,产出 0
- 堆行为:无
代码:return a => { 'field1','field2' }
指令:
...(部分略)...
#03 E_PUSH
#04 NEW_O
#05 E_LOAD #
#06 GET field1
#07 PUT field1
...(部分略)...
函数指令
CALL
发起 UDF 调用。发起服务调用(例:CALL,2)
- 参数说明:共 1 参数;参数 1:发起调用时需要用到的调用参数个数 n
- 栈行为:消费:n + 1(n是参数,1 是函数入口),产出 1
- 堆行为:无
代码:return abs(-1)
指令:
...(部分略)...
#2 M_DEF
#3 LDC_D -1
#4 CALL 1 <- 在 CALL 发起函数调用之前通常会有 M_DEF、M_TYP、M_REF 三种之一的函数定义行为。
...(部分略)...
M_DEF
函数定义,将栈顶元素转换为 UDF
- 参数说明:共 0 参数;
- 栈行为:消费 1,产出 1
- 堆行为:无
代码:return abs(-1)
指令:
#0 E_LOAD #
#1 GET abs
#2 M_DEF <= 前面 GET 出来的 abs 定义为函数
...(部分略)...
M_TYP
加载一个对象到栈顶。通过 Finder 的 findBean 方法加载一个对象到栈顶。一般情况下对应的操作是 import。
- 参数说明:共 1 参数;参数为要加载的 Bean 名
- 栈行为:消费 0,产出 1
- 堆行为:无
代码:import 'net.hasor.test.dataql.udfs.DemoUdf' as foo; return foo().name
指令:
#0 M_TYP net.hasor.test.dataql.udfs.DemoUdf
#1 STORE 0
#2 LOAD 0, 0
#3 M_DEF
#4 CALL 0
...(部分略)...
M_FRAG
加载代码执行片段执行器,片段执行器允许通过扩展方式集成一个非 DataQL 语法的脚本块。
- 参数说明:共 1 参数;参数 1:片段类型
- 栈行为:消费 0,产出 1
- 堆行为:无
[1]
...(部分略)...
#03 M_FRAG sql <- 加载类型为 sql 的外部片段执行器。
#04 LOAD 0, 0
...(部分略)...
M_REF
将指令序列作为函数。引用另一处的指令序列地址,并将其作为 UDF 形态存放到栈顶。lambda 被调用的开始会像栈顶放入一个入参数组。
- 参数说明:共 1 参数;参数 1:内置 lambda 函数的入口地址
- 栈行为:消费 0,产出 1
- 堆行为:无
代码:var foo = () -> return {"name" : true}; return foo().name
指令:
[0]
#0 M_REF 1 <- 引用 [1] 指令序列作为函数
#1 STORE 0
#2 LOAD 0, 0
#3 M_DEF
#4 CALL 0
...(部分略)...
[1]
...(部分略)...
LOCAL
参数入堆。将入参存入堆,也用于标记变量名称。
- 参数说明:共 3 参数;参数 1:调用时的入参位置;参数 2:存储到堆中的位置;参数3:参数名助记符;
- 栈行为:消费 0,产出 0
- 堆行为:存入数据
代码:var foo = (a,b,c) -> return {"name" : a}; return foo().name
指令:
[0]
...(部分略)...
[1]
#0 LOCAL 0, 0, a
#1 LOCAL 1, 1, b
#2 LOCAL 2, 2, c
...(部分略)...
辅助指令
HINT
设置 Hint,影响执行引擎的参数选项。
- 参数说明:共 2 参数;参数 1:选项Key;参数 2:选项Value
- 栈行为:消费 2,产出 0
- 堆行为:无
代码:hint a = 'abc' return 1
指令:
#0 LDC_S a
#1 LDC_S abc
#2 HINT
...(部分略)...
LABEL
协助GOTO定位用,无实际作用
- 参数说明:共 0 参数;
- 栈行为:消费 0,产出 0
- 堆行为:无
代码:if (1 == 1) return true; else return false
指令:
...(部分略)...
#02 DO ==
#03 IF 7 <- 如果判断失败那么跳转到 #07 行指令
...(部分略)...
#07 LABEL 7 <- LABEL 7 之后的相当于 else 部分
...(部分略)...
LINE
行号,无实际作用
- 参数说明:共 0 参数;
- 栈行为:消费 0,产出 0
- 堆行为:无