Syntax Nodes
Inspect one language lane at a time so line-level text and code deltas stay readable.
Diff Lane
English
0 modified sections0 code block delta0 anchor delta
Diff Lane
中文
3 modified sections0 code block delta0 anchor delta
modified节点的组成部分text+2 lines, -2 lines
v1.0.5
Section Text
1
从 `Tokens` 解析出节点之后,可以查看节点的组成部分。作为例子,仅列出 `BinaryExpr` 和 `FuncDecl` 的组成部分,关于其他节点的更详细的解释请参见《仓颉编程语言库 API》文档。2
3
- `BinaryExpr` 节点:4
- `leftExpr: Expr`:运算符左侧的表达式5
- `op: Token`:运算符6
- `rightExpr: Expr`:运算符右侧的表达式7
- `FuncDecl` 节点(部分):8
- `identifier: Token`:函数名9
- `funcParams: ArrayList<FuncParam>`:参数列表10
- `declType: TypeNode`:返回值类型11
- `block: Block`:函数体12
- `FuncParam`节点(部分):13
- `identifier: Token`:参数名14
- `paramType: TypeNode`:参数类型15
- `Block`节点(部分):16
- `nodes: ArrayList<Node>`:块中的表达式和声明17
18
每个组成部分都是 `public mut prop`,因此可以被查看和更新。通过一些例子展示更新的结果。v1.1.0
Section Text
1
从 `Tokens` 解析出节点之后,可以查看节点的组成部分。作为例子,仅列出 `BinaryExpr` 和 `FuncDecl` 的组成部分,关于其他节点的更详细的解释请参见《仓颉编程语言库 API》文档。2
3
- `BinaryExpr` 节点:4
- `leftExpr: Expr`:运算符左侧的表达式5
- `op: Token`:运算符6
- `rightExpr: Expr`:运算符右侧的表达式7
- `FuncDecl` 节点(部分):8
- `identifier: Token`:函数名9
- `funcParams: ArrayList<FuncParam>`:参数列表10
- `declType: TypeNode`:返回值类型11
- `block: Block`:函数体12
- `FuncParam` 节点(部分):13
- `identifier: Token`:参数名14
- `paramType: TypeNode`:参数类型15
- `Block` 节点(部分):16
- `nodes: ArrayList<Node>`:块中的表达式和声明17
18
每个组成部分都是 `public mut prop`,因此可以被查看和更新。通过一些例子展示更新的结果。modifiedBinaryExpr 案例text+1 line, -1 line
v1.0.5
Section Text
1
<!-- verify -->2
3
4
输出结果是:5
6
7
首先,通过解析,获得 `binExpr` 为节点 `x * y`,图示如下:8
9
10
第二步,将左侧的节点(即 `x`)替换为 `a + b`,因此,获得的语法树如下:11
12
13
当输出这个语法树的时候,必须在 `a + b` 周围添加括号,得到 `(a + b) * y`(如果输出`a + b * y`,含义为先做乘法,再做加法,与语法树的含义不同)。`ast` 库具备在输出语法树时自动添加括号的功能。14
15
第三步,将语法树根部的运算符从 `*` 替换为 `+`,因此得到语法树如下:16
17
18
这个语法树可以输出为 `a + b + y`,因为加法本身就是左结合的,不需要在左侧添加括号。Code 1 · cangjie
1
let binExpr = BinaryExpr(quote(x * y))2
binExpr.leftExpr = BinaryExpr(quote(a + b))3
println(binExpr.toTokens())4
5
binExpr.op = Token(TokenKind.ADD)6
println(binExpr.toTokens())Code 2 · text
1
(a + b) * y2
a + b + yCode 3 · text
1
*2
/ \3
x yCode 4 · text
1
*2
/ \3
+ y4
/ \5
a bCode 5 · text
1
+2
/ \3
+ y4
/ \5
a bv1.1.0
Section Text
1
<!-- verify -->2
3
4
输出结果是:5
6
7
首先,通过解析,获得 `binExpr` 为节点 `x * y`,图示如下:8
9
10
第二步,将左侧的节点(即 `x`)替换为 `a + b`,因此,获得的语法树如下:11
12
13
当输出这个语法树的时候,必须在 `a + b` 周围添加括号,得到 `(a + b) * y`(如果输出 `a + b * y`,含义为先做乘法,再做加法,与语法树的含义不同)。`ast` 库具备在输出语法树时自动添加括号的功能。14
15
第三步,将语法树根部的运算符从 `*` 替换为 `+`,因此得到语法树如下:16
17
18
这个语法树可以输出为 `a + b + y`,因为加法本身就是左结合的,不需要在左侧添加括号。Code 1 · cangjie
1
let binExpr = BinaryExpr(quote(x * y))2
binExpr.leftExpr = BinaryExpr(quote(a + b))3
println(binExpr.toTokens())4
5
binExpr.op = Token(TokenKind.ADD)6
println(binExpr.toTokens())Code 2 · text
1
(a + b) * y2
a + b + yCode 3 · text
1
*2
/ \3
x yCode 4 · text
1
*2
/ \3
+ y4
/ \5
a bCode 5 · text
1
+2
/ \3
+ y4
/ \5
a bmodified使用 quote 插值语法节点text+1 line, -1 line
v1.0.5
Section Text
1
任何语法节点都可以在 `quote` 语句中插值,部分语法节点的 `ArrayList` 列表也可以被插值(主要对应实际情况中会出现这类节点列表的情况)。插值直接通过 `$(node)` 表达即可,其中 `node` 是任意节点类型的实例。2
3
下面,通过一些案例展示节点的插值。4
5
<!-- verify -->6
7
8
输出结果是:9
10
11
一般来说,插值运算符后面的表达式使用小括号限定作用域,例如 `$(binExpr)`。但是当后面只跟单个标识符的时候,小括号可省略,即可写为 `$binExpr`。因此,在案例中 `a` 和 `b` 都在 `quote` 中插入了 `binExpr`节点,结果为 `1 + 2`。然而,如果插值运算符后面的表达式更复杂,不加小括号可能造成作用域出错。例如,表达式 `binExpr.leftExpr` 求值为 `1 + 2` 的左表达式,即 `1`,因此 `c` 正确赋值为 `1`。但 `d` 中的插值被解释为 `($binExpr).leftExpr`,因此结果是 `1 + 2.leftExpr`。为了明确插值的作用域,推荐在插值运算符中使用小括号。12
13
下面的案例展示节点列表(`ArrayList`)的插值。14
15
<!-- verify -->16
17
18
输出结果是:19
20
21
在这个案例中,创建了一个节点列表 `incrs`,包含表达式 `x += 1`,...,`x += 5`。对 `incrs` 的插值将节点依次列出,在每个节点后换行。这适用于插入需要依次执行的表达式和声明的情况。22
23
下面的案例展示在某些情况下,需要在插值周围添加括号,以保证正确性。24
25
<!-- verify -->26
27
28
输出结果是:29
30
31
首先,构建表达式 `x + y`,然后将该表达式插入到模板 `$(binExpr1) * z` 中。这里的意图是得到一个先计算 `x + y` 再乘 `z` 的表达式,但是,插值的结果是 `x + y * z`,即先计算 `y * z` 再加 `x`。这是因为插值不会自动添加括号以保证被插入的表达式的原子性(这和前一节介绍的 `leftExpr` 的替换不同)。因此,需要在 `$(binExpr1)` 周围添加小括号,保证得到正确的结果。Code 1 · cangjie
1
var binExpr = BinaryExpr(quote(1 + 2))2
let a = quote($(binExpr))3
let b = quote($binExpr)4
let c = quote($(binExpr.leftExpr))5
let d = quote($binExpr.leftExpr)6
println("a: ${a.toTokens()}")7
println("b: ${b.toTokens()}")8
println("c: ${c.toTokens()}")9
println("d: ${d.toTokens()}")Code 2 · text
1
a: 1 + 22
b: 1 + 23
c: 14
d: 1 + 2.leftExprCode 3 · cangjie
1
var incrs = ArrayList<Node>()2
for (i in 1..=5) {3
incrs.add(parseExpr(quote(x += $(i))))4
}5
var foo = quote(6
func foo(n: Int64) {7
let x = n8
$(incrs)9
x10
})11
println(foo)Code 4 · text
1
func foo(n: Int64) {2
let x = n3
x += 14
x += 25
x += 36
x += 47
x += 58
x9
}Code 5 · cangjie
1
var binExpr1 = BinaryExpr(quote(x + y))2
var binExpr2 = BinaryExpr(quote($(binExpr1) * z)) // 错误:得到 x + y * z3
println("binExpr2: ${binExpr2.toTokens()}")4
println("binExpr2.leftExpr: ${binExpr2.leftExpr.toTokens()}")5
println("binExpr2.rightExpr: ${binExpr2.rightExpr.toTokens()}")6
var binExpr3 = BinaryExpr(quote(($(binExpr1)) * z)) // 正确:得到 (x + y) * z7
println("binExpr3: ${binExpr3.toTokens()}")Code 6 · text
1
binExpr2: x + y * z2
binExpr2.leftExpr: x3
binExpr2.rightExpr: y * z4
binExpr3: (x + y) * zv1.1.0
Section Text
1
任何语法节点都可以在 `quote` 语句中插值,部分语法节点的 `ArrayList` 列表也可以被插值(主要对应实际情况中会出现这类节点列表的情况)。插值直接通过 `$(node)` 表达即可,其中 `node` 是任意节点类型的实例。2
3
下面,通过一些案例展示节点的插值。4
5
<!-- verify -->6
7
8
输出结果是:9
10
11
一般来说,插值运算符后面的表达式使用小括号限定作用域,例如 `$(binExpr)`。但是当后面只跟单个标识符的时候,小括号可省略,即可写为 `$binExpr`。因此,在案例中 `a` 和 `b` 都在 `quote` 中插入了 `binExpr` 节点,结果为 `1 + 2`。然而,如果插值运算符后面的表达式更复杂,不加小括号可能造成作用域出错。例如,表达式 `binExpr.leftExpr` 求值为 `1 + 2` 的左表达式,即 `1`,因此 `c` 正确赋值为 `1`。但 `d` 中的插值被解释为 `($binExpr).leftExpr`,因此结果是 `1 + 2.leftExpr`。为了明确插值的作用域,推荐在插值运算符中使用小括号。12
13
下面的案例展示节点列表(`ArrayList`)的插值。14
15
<!-- verify -->16
17
18
输出结果是:19
20
21
在这个案例中,创建了一个节点列表 `incrs`,包含表达式 `x += 1`,...,`x += 5`。对 `incrs` 的插值将节点依次列出,在每个节点后换行。这适用于插入需要依次执行的表达式和声明的情况。22
23
下面的案例展示在某些情况下,需要在插值周围添加括号,以保证正确性。24
25
<!-- verify -->26
27
28
输出结果是:29
30
31
首先,构建表达式 `x + y`,然后将该表达式插入到模板 `$(binExpr1) * z` 中。这里的意图是得到一个先计算 `x + y` 再乘 `z` 的表达式,但是,插值的结果是 `x + y * z`,即先计算 `y * z` 再加 `x`。这是因为插值不会自动添加括号以保证被插入的表达式的原子性(这和前一节介绍的 `leftExpr` 的替换不同)。因此,需要在 `$(binExpr1)` 周围添加小括号,保证得到正确的结果。Code 1 · cangjie
1
var binExpr = BinaryExpr(quote(1 + 2))2
let a = quote($(binExpr))3
let b = quote($binExpr)4
let c = quote($(binExpr.leftExpr))5
let d = quote($binExpr.leftExpr)6
println("a: ${a.toTokens()}")7
println("b: ${b.toTokens()}")8
println("c: ${c.toTokens()}")9
println("d: ${d.toTokens()}")Code 2 · text
1
a: 1 + 22
b: 1 + 23
c: 14
d: 1 + 2.leftExprCode 3 · cangjie
1
var incrs = ArrayList<Node>()2
for (i in 1..=5) {3
incrs.add(parseExpr(quote(x += $(i))))4
}5
var foo = quote(6
func foo(n: Int64) {7
let x = n8
$(incrs)9
x10
})11
println(foo)Code 4 · text
1
func foo(n: Int64) {2
let x = n3
x += 14
x += 25
x += 36
x += 47
x += 58
x9
}Code 5 · cangjie
1
var binExpr1 = BinaryExpr(quote(x + y))2
var binExpr2 = BinaryExpr(quote($(binExpr1) * z)) // 错误:得到 x + y * z3
println("binExpr2: ${binExpr2.toTokens()}")4
println("binExpr2.leftExpr: ${binExpr2.leftExpr.toTokens()}")5
println("binExpr2.rightExpr: ${binExpr2.rightExpr.toTokens()}")6
var binExpr3 = BinaryExpr(quote(($(binExpr1)) * z)) // 正确:得到 (x + y) * z7
println("binExpr3: ${binExpr3.toTokens()}")Code 6 · text
1
binExpr2: x + y * z2
binExpr2.leftExpr: x3
binExpr2.rightExpr: y * z4
binExpr3: (x + y) * z