一键导入
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,而非全局变量