Skip to content

Latest commit

 

History

History
668 lines (579 loc) · 20.2 KB

instruction.md

File metadata and controls

668 lines (579 loc) · 20.2 KB
id instruction
sidebar_position 6
title 8.6 QIL 指令参考
description DataQL 引擎,QIL 指令集、构造指令、存储指令、结束指令、运算指令、控制指令、函数指令、辅助指令

QIL 是 DataQL 的编译结果。普通查询通过 Query 执行,需要分析编译结果时可查阅本页指令;编译入口见独立使用。

助记符 指令代码 含义
构造指令
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
  • 堆行为:无