بنقرة واحدة
cangjie-macro
仓颉语言宏。当需要了解仓颉语言的Token/Tokens类型、quote表达式与插值、非属性宏、属性宏、嵌套宏与通信、std.ast包与语法节点(AST)解析时,应使用此 Skill。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
仓颉语言宏。当需要了解仓颉语言的Token/Tokens类型、quote表达式与插值、非属性宏、属性宏、嵌套宏与通信、std.ast包与语法节点(AST)解析时,应使用此 Skill。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
当需要构建鸿蒙应用项目时,使用此 Skill 执行构建流程。此 Skill 包含完整的构建命令、构建流程说明、构建失败处理流程。构建脚本会自动执行依赖安装、仓颉预编译、资源生成、编译、打包等步骤。
在鸿蒙应用(Cangjie)开发中,当需要使用 stdx 拓展库(如 crypto、encoding、net、log、actors 等),或在构建/链接阶段出现 stdx 相关错误时,使用此 Skill 获取/解压 stdx 包,并指导在 entry/cjpm.toml 中正确配置 bin-dependencies.path-option。
在进行仓颉工程或鸿蒙应用开发时的第一步,应该优先读取该SKILL,用来确定后续的开发步骤。
仓颉语言内置注解。当需要了解仓颉 SDK 提供的内置注解(@sourcePackage/@sourceFile/@sourceLine/@When/@FastNative/@Frozen/@Attribute/@Deprecated)的用途、语法和最优实践时,应使用此 Skill。
仓颉语言附录参考。当需要查阅仓颉语言的关键字列表、运算符优先级与结合性、运算符重载函数签名、运行时环境变量配置、包兼容性规则、TokenKind枚举类型时,应使用此 Skill。
仓颉标准库 Array 类型详细指南。当需要了解 Array 的构造、元素访问、切片、拼接、查找、排序、拷贝、反转、映射、扁平化等操作的完整 API 和用法时,应使用此 Skill。
| name | cangjie-macro |
| description | 仓颉语言宏。当需要了解仓颉语言的Token/Tokens类型、quote表达式与插值、非属性宏、属性宏、嵌套宏与通信、std.ast包与语法节点(AST)解析时,应使用此 Skill。 |
@ 前缀调用:@macroName(...)Tokens 输入,转换后返回新的 Tokens,在编译时替换调用处macro package <name>import std.ast.*Token 是最小词法单元:标识符、字面量、关键字或运算符Token 有:类型(TokenKind)、内容、位置信息Token(k: TokenKind) 或 Token(k: TokenKind, v: String)Token(TokenKind.ADD) → +,Token(TokenKind.IDENTIFIER, "x") → xTokens 是 Token 对象的序列Tokens()、Tokens(tks: Array<Token>)、Tokens(tks: ArrayList<Token>)size、get(index)、[] 索引、+ 拼接、dump() 调试输出、toString() 代码字符串quote(...) 将代码模板转换为 Tokensquote 内使用 $(expr) 插值来插入实现 ToTokens 的表达式ToTokens 的类型:所有 AST 节点类型、Token/Tokens、所有基本类型、Array<T>、ArrayList<T>quote 中未匹配的括号须用 \ 转义:\( 或 \)$ 作为字面 token(非插值)须转义:\$@ 须转义:\@public macro MacroName(args: Tokens): Tokens { ... }@MacroName(...) 带括号,或 @MacroName 在声明前(括号可选)func、struct、class、var、enum、interface、extend、prop 等声明Token 序列( ) 须用 \ 转义public macro Foo(attrTokens: Tokens, inputTokens: Tokens): Tokens { ... }Tokens 参数:属性 token + 输入 token@Foo[attrContent](inputContent) 或 @Foo[attrContent] 在声明前[] 中,常规内容在 () 中[](可为空)[]assertParentContext("OuterMacroName") — 若内层宏不在指定外层宏内则报错insideParentContext("OuterMacroName") — 返回 BoolsetItem("key", "value")getChildMessages("InnerMacroName") 返回消息对象集合getString("key") 获取值std.ast 是仓颉宏编程的核心依赖包,提供源码的词法分析和语法解析能力。主要包含:
Token(单个词法单元)和 Tokens(词法单元序列),以及 TokenKind 枚举(表示所有词法结构:符号、关键字、标识符等)Tokens 解析为抽象语法树(AST)节点对象的函数族(parseExpr、parseDecl、parseType 等)Node 为基类的完整语法树节点类型,涵盖声明(Decl)、表达式(Expr)、类型(TypeNode)、模式(Pattern)四大分支Visitor 抽象类提供节点访问函数,配合 traverse() 实现 AST 遍历assertParentContext、insideParentContext、setItem、getChildMessages 等函数,用于宏展开时的上下文信息传递diagReport 函数在宏展开阶段输出 ERROR/WARNING 级别的编译信息cangjieLex(字符串转 Tokens)、compareTokens(Tokens 比较)、ToTokens/ToBytes 接口所有宏实现文件须
import std.ast.*
Node — 所有语法节点的基类TypeNode — 所有类型节点Expr — 所有表达式节点Decl — 所有声明节点Pattern — 所有模式节点| 函数 | 说明 |
|---|---|
parseExpr(Tokens) | 解析为表达式节点 Expr |
parseDecl(Tokens) | 解析为声明节点 Decl |
parseType(Tokens) | 解析为类型节点 TypeNode |
parsePattern(Tokens) | 解析为模式节点 Pattern |
parseProgram(Tokens) | 解析整个源文件为 Program 节点 |
parseExprFragment(Tokens, Int64) | 部分解析表达式,返回 (Expr, Int64) |
parseDeclFragment(Tokens, Int64) | 部分解析声明,返回 (Decl, Int64) |
也可通过直接构造函数创建节点:BinaryExpr(quote(a + b))、FuncDecl(quote(func f1(...) {...})) 等
| 节点类 | 常用属性 |
|---|---|
FuncDecl | identifier、funcParams、declType、block、modifiers |
ClassDecl | identifier、body、modifiers、superTypes |
StructDecl | identifier、body、modifiers |
VarDecl | identifier、declType、expr、keyword(var/let) |
BinaryExpr | leftExpr、op、rightExpr |
CallExpr | callExpr、arguments |
Block | nodes: ArrayList<Node> |
Body | decls: ArrayList<Decl> |
FuncParam | identifier、paramType |
$(node) 在 quote 内ArrayList<Node> 可插值(项依次列出并换行)import std.ast.*
class MyVisitor <: Visitor {
public override func visit(varDecl: VarDecl) {
println("Found var: ${varDecl.identifier.value}")
breakTraverse() // 不继续遍历子节点
return
}
}
// 使用方式:node.traverse(MyVisitor())
| 函数 | 说明 |
|---|---|
cangjieLex(String) | 字符串转 Tokens |
compareTokens(Tokens, Tokens) | 比较两个 Tokens |
diagReport(level, tokens, msg, hint) | 宏展开阶段报错(ERROR/WARNING) |
详细的编译构建指导请参考
cangjie-macro-buildSkill,包含 cjc/cjpm 编译命令、项目结构、不同平台配置、并行宏展开、调试模式等完整说明。
macro package 声明的包中,宏定义和调用须在不同包中cjc --compile-macro),再编译调用包cjpm.toml 中设置 compile-option = "--compile-macro"@power[10](n) 在编译时展开幂运算循环@Memoize[true] 将递归函数转换为使用 HashMap 缓存结果@dprint2(x, y, x + y) 打印多个逗号分隔的表达式@linq(from x in 1..=10 where x % 2 == 1 select x * x) 实现迷你查询语言宏定义(macros/src/my_macros.cj):
macro package macros
import std.ast.*
public macro AutoToString(input: Tokens): Tokens {
let decl = parseDecl(input)
let classDecl = match (decl as ClassDecl) {
case Some(v) => v
case None =>
diagReport(DiagReportLevel.ERROR, input,
"AutoToString 只能用于 class 声明", "此处不是 class")
return input
}
let className = classDecl.identifier
// 收集所有 var/let 成员变量名
var fields = ArrayList<Token>()
for (d in classDecl.body.decls) {
if (let Some(varDecl) <- (d as VarDecl)) {
fields.add(varDecl.identifier)
}
}
// 构建 toString 方法体中的字段拼接
var parts = quote(var result = "${$(className)}{")
for (f in fields) {
parts = quote($(parts)
result += " $(f)=" + this.$(f).toString()
)
}
parts = quote($(parts)
result += " }"
return result
)
// 添加 toString 方法到 class
let toStringFunc = FuncDecl(quote(
public func toString(): String {
$(parts)
}
))
classDecl.body.decls.add(toStringFunc)
return classDecl.toTokens()
}
调用处(src/main.cj):
import macros.*
@AutoToString
class User {
var name: String = ""
var age: Int64 = 0
init(name: String, age: Int64) {
this.name = name
this.age = age
}
}
main() {
let u = User("Alice", 30)
println(u.toString())
// 输出: User{ name=Alice age=30 }
}
macro package macros
import std.ast.*
public macro Log(attrTokens: Tokens, inputTokens: Tokens): Tokens {
let level = attrTokens.toString().trimAscii()
let funcDecl = FuncDecl(inputTokens)
let funcName = funcDecl.identifier
let logStmt = quote(
println("[$(level)] entering $(funcName)")
)
// 在函数体开头插入日志语句
let oldNodes = funcDecl.block.nodes
funcDecl.block.nodes = ArrayList<Node>()
funcDecl.block.nodes.add(parseExpr(logStmt))
for (n in oldNodes) {
funcDecl.block.nodes.add(n)
}
return funcDecl.toTokens()
}
调用处:
import macros.*
@Log[DEBUG]
func compute(x: Int64): Int64 {
return x * 2
}
import std.ast.*
// 查找所有函数声明并打印函数名
class FuncCollector <: Visitor {
public var funcNames = ArrayList<String>()
public override func visit(funcDecl: FuncDecl) {
funcNames.add(funcDecl.identifier.value)
}
}
main() {
let code = quote(
class Calc {
func add(a: Int64, b: Int64): Int64 { a + b }
func sub(a: Int64, b: Int64): Int64 { a - b }
}
)
let decl = parseDecl(code)
let collector = FuncCollector()
decl.traverse(collector)
for (name in collector.funcNames) {
println("Found function: ${name}")
}
// 输出: Found function: add
// Found function: sub
}
macro package 中,与调用代码分离为独立模块cjc --compile-macro 编译public,辅助函数保持包内可见as 模式匹配 + diagReport 报告错误quote(...) + $(...) 插值生成代码,保持模板可读性Token,除非需要动态构造标识符ParenExprparseDecl/parseExpr 将 Tokens 转为强类型节点后再操作node.toTokens() 转回 Tokens 返回Visitor 模式遍历复杂 AST,避免手动递归dump() 调试 AST 结构--debug-macro 查看展开结果setItem/getChildMessages,而非全局变量