跳到主要内容

指令系统

助记符指令代码含义
构造指令
LDC_D11将数字压入栈(例:LDC_D 12345)
LDC_B12将布尔数据压入栈(例:INSN_B true)
LDC_S13将字符串数据压入栈(例:LDC_S “ssssss”)
LDC_N14将null压入栈(例:INSN_N)
NEW_O15构造一个键值对对象并压入栈
NEW_A16构造一个集合对象并压入栈
存储指令
STORE21栈顶数据存储到堆(例:STORE,2)
LOAD22从指定深度的堆中加载n号元素到栈(例:LOAD 1 ,1 )
GET23获取栈顶对象元素的属性(例:GET,”xxxx”)
PUT24将栈顶对象元素放入对象元素中(例:GET,”xxxx”)
PULL25获取集合的指定索引元素。(例:PULL 123)
PUSH26将栈顶元素压入集合(例:PUSH)
结束指令
EXIT31结束所有指令序列的执行并返回数据和状态
RETURN32结束当前指令序列的执行,并返回数据和状态给上一个指令序列。
THROW33结束所有指令序列的执行,并抛出异常
运算指令
UO41一元运算
DO42二元运算,堆栈结构:【第一个操作数,第二个操作数】
TYPEOF43计算值的类(string、number、boolean、object、list、udf、null)
控制指令
IF51如果条件判断失败那么 GOTO 到指定位置,否则继续往下执行
GOTO52执行跳转
CAST_I53将栈顶元素转换为迭代器
CAST_O54将栈顶元素转换为一个对象,如果是集合那么取第一条记录
E_PUSH55取出当前栈顶数据,并压入环境栈
E_POP56丢弃环境栈顶的元素
E_LOAD57加载环境栈顶的数据到数据栈
LOAD_C58加载自定义路由
POP59丢弃栈顶数据
函数指令
CALL61发起服务调用(例:CALL,2)
M_DEF62函数定义,将栈顶元素转换为 UDF
M_REF63引用另一处的指令序列地址,并将其作为 UDF 形态存放到栈顶
M_TYP64加载一个类型对象到栈顶,该类型是一个有效的 UDF。
M_FRAG65引用外部片段执行器,并将其作为 UDF 形态存放到栈顶
LOCAL66将入参存入堆,也用于标记变量名称
辅助指令
HINT71设置 Hint,影响执行引擎的参数选项。
LABEL72协助GOTO定位用,无实际作用
LINE73行号,无实际作用

构造指令

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
  • 堆行为:无