Compilation, Errors, and Debugging
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
中文
1 modified sections0 code block delta0 anchor delta
modified使用 --debug-macro 输出宏展开结果text+1 line, -1 line
v1.0.2
Section Text
1
借助宏在编译期做代码生成时,如果发生错误,处理起来十分棘手,这是开发者经常遇到但一般很难定位的问题。这是因为,开发者写的源码,经过宏的变换后变成了不同的代码片段。编译器抛出的错误信息是基于宏最终生成的代码进行提示的,但这些代码在开发者的源码中没有体现。2
3
为了解决这个问题,仓颉宏提供 debug 模式,在这个模式下,开发者可以从编译器为宏生成的 debug 文件中看到完整的宏展开后的代码,如下所示。4
5
宏定义文件:6
7
<!-- compile -macro3 -->8
<!-- cfg="--compile-macro" -->9
10
11
宏调用文件 `demo.cj`:12
13
<!-- compile -macro3 -->14
<!-- cfg="--debug-macro" -->15
16
17
在编译使用宏的文件时,在选项中,增加 `--debug-macro`,即使用仓颉宏的 _debug_ 模式。18
19
20
> **注意:**21
>22
> 如果使用仓颉的 `CJPM` 包管理工具进行编译,可在配置文件 `cjpm.toml` 中添加 `--debug-macro` 的编译选项来使用宏的 _debug_ 模式。23
>24
> ```text25
> compile-option = "--debug-macro"26
> ```27
28
在 _debug_ 模式下,会生成临时文件 _demo.cj.macrocall_,对应宏展开的部分如下:29
30
31
如果宏展开后的代码有语义错误,则编译器的错误信息会溯源到宏展开后代码的具体行列号。仓颉宏的 _debug_ 模式有以下注意事项:32
33
- 宏的 _debug_ 模式会重排源码的行列号信息,不适用于某些特殊的换行场景。例如:34
35
```cangjie36
// before expansion37
@M{} - 2 // macro M return 238
39
// after expansion40
// ===== Emmitted my Macro M at line 1 ===41
242
// ===== End of the Emit =====43
- 244
```45
46
这些因换行符导致语义改变的情形,不应使用 _debug_ 模式。47
48
- 不支持宏调用在宏定义内的调试,会编译报错。49
50
```cangjie51
public macro M(input: Tokens) {52
let a = @M2(1+2) // M2 is in macro M, not suitable for debug mode.53
return input + quote($a)54
}55
```56
57
- 不支持带括号宏的调试。58
59
```cangjie60
// main.cj61
62
main() {63
// For macro with parenthesis, newline introduced by debug will change the semantics64
// of the expression, so it is not suitable for debug mode.65
let t = @M(1+2)66
}67
```Code 1 · cangjie
1
macro package define2
3
import std.ast.*4
5
public macro Outer(input: Tokens): Tokens {6
let messages = getChildMessages("Inner")7
8
let getTotalFunc = quote(public func getCnt() {9
)10
for (m in messages) {11
let identName = m.getString("identifierName")12
getTotalFunc.append(Token(TokenKind.IDENTIFIER, identName))13
getTotalFunc.append(quote(+))14
}15
getTotalFunc.append(quote(0))16
getTotalFunc.append(quote(}))17
let funcDecl = parseDecl(getTotalFunc)18
19
let decl = (parseDecl(input) as ClassDecl).getOrThrow()20
decl.body.decls.add(funcDecl)21
return decl.toTokens()22
23
}24
25
public macro Inner(input: Tokens): Tokens {26
assertParentContext("Outer")27
let decl = parseDecl(input)28
setItem("identifierName", decl.identifier.value)29
return input30
}Code 2 · cangjie
1
import define.*2
3
@Outer4
class Demo {5
@Inner var state = 16
@Inner var cnt = 427
}8
9
main(): Int64 {10
let d = Demo()11
println("${d.getCnt()}")12
return 013
}14
Code 3 · shell
1
cjc --debug-macro demo.cj --import-path ./targetCode 4 · cangjie
1
// demo.cj.macrocall2
/* ===== Emitted by MacroCall @Outer in demo.cj:3:1 ===== */3
/* 3.1 */class Demo {4
/* 3.2 */ var state = 15
/* 3.3 */ var cnt = 426
/* 3.4 */ public func getCnt() {7
/* 3.5 */ state + cnt + 08
/* 3.6 */ }9
/* 3.7 */}10
/* 3.8 */11
/* ===== End of the Emit ===== */v1.0.5
Section Text
1
借助宏在编译期做代码生成时,如果发生错误,处理起来十分棘手,这是开发者经常遇到但一般很难定位的问题。这是因为,开发者写的源码,经过宏的变换后变成了不同的代码片段。编译器抛出的错误信息是基于宏最终生成的代码进行提示的,但这些代码在开发者的源码中没有体现。2
3
为了解决这个问题,仓颉宏提供 debug 模式,在这个模式下,开发者可以从编译器为宏生成的 debug 文件中看到完整的宏展开后的代码,如下所示。4
5
宏定义文件:6
7
<!-- compile -macro3 -->8
<!-- cfg="--compile-macro" -->9
10
11
宏调用文件 `demo.cj`:12
13
<!-- compile -macro3 -->14
<!-- cfg="--debug-macro" -->15
16
17
在编译使用宏的文件时,在选项中,增加 `--debug-macro`,即使用仓颉宏的 _debug_ 模式。18
19
20
> **注意:**21
>22
> 如果使用仓颉的 `CJPM` 项目管理工具进行编译,可在配置文件 `cjpm.toml` 中添加 `--debug-macro` 的编译选项来使用宏的 _debug_ 模式。23
>24
> ```text25
> compile-option = "--debug-macro"26
> ```27
28
在 _debug_ 模式下,会生成临时文件 _demo.cj.macrocall_,对应宏展开的部分如下:29
30
31
如果宏展开后的代码有语义错误,则编译器的错误信息会溯源到宏展开后代码的具体行列号。仓颉宏的 _debug_ 模式有以下注意事项:32
33
- 宏的 _debug_ 模式会重排源码的行列号信息,不适用于某些特殊的换行场景。例如:34
35
```cangjie36
// before expansion37
@M{} - 2 // macro M return 238
39
// after expansion40
// ===== Emmitted my Macro M at line 1 ===41
242
// ===== End of the Emit =====43
- 244
```45
46
这些因换行符导致语义改变的情形,不应使用 _debug_ 模式。47
48
- 不支持宏调用在宏定义内的调试,会编译报错。49
50
```cangjie51
public macro M(input: Tokens) {52
let a = @M2(1+2) // M2 is in macro M, not suitable for debug mode.53
return input + quote($a)54
}55
```56
57
- 不支持带括号宏的调试。58
59
```cangjie60
// main.cj61
62
main() {63
// For macro with parenthesis, newline introduced by debug will change the semantics64
// of the expression, so it is not suitable for debug mode.65
let t = @M(1+2)66
}67
```Code 1 · cangjie
1
macro package define2
3
import std.ast.*4
5
public macro Outer(input: Tokens): Tokens {6
let messages = getChildMessages("Inner")7
8
let getTotalFunc = quote(public func getCnt() {9
)10
for (m in messages) {11
let identName = m.getString("identifierName")12
getTotalFunc.append(Token(TokenKind.IDENTIFIER, identName))13
getTotalFunc.append(quote(+))14
}15
getTotalFunc.append(quote(0))16
getTotalFunc.append(quote(}))17
let funcDecl = parseDecl(getTotalFunc)18
19
let decl = (parseDecl(input) as ClassDecl).getOrThrow()20
decl.body.decls.add(funcDecl)21
return decl.toTokens()22
23
}24
25
public macro Inner(input: Tokens): Tokens {26
assertParentContext("Outer")27
let decl = parseDecl(input)28
setItem("identifierName", decl.identifier.value)29
return input30
}Code 2 · cangjie
1
import define.*2
3
@Outer4
class Demo {5
@Inner var state = 16
@Inner var cnt = 427
}8
9
main(): Int64 {10
let d = Demo()11
println("${d.getCnt()}")12
return 013
}14
Code 3 · shell
1
cjc --debug-macro demo.cj --import-path ./targetCode 4 · cangjie
1
// demo.cj.macrocall2
/* ===== Emitted by MacroCall @Outer in demo.cj:3:1 ===== */3
/* 3.1 */class Demo {4
/* 3.2 */ var state = 15
/* 3.3 */ var cnt = 426
/* 3.4 */ public func getCnt() {7
/* 3.5 */ state + cnt + 08
/* 3.6 */ }9
/* 3.7 */}10
/* 3.8 */11
/* ===== End of the Emit ===== */