仓颉 std.ast 宏上下文编程指南:assertParentContext 嵌套校验与 setItem/getChildMessages 消息通信
编程语言语言运行时标准库垃圾回收并发编程【免费下载链接】cangjie_runtime仓颉编程语言运行时与标准库。项目地址https://gitcode.com/Cangjie/cangjie_runtime点击查看免费下载仓颉Cangjie的宏系统支持在编译期对源码进行语法树级变换而std.ast包提供的 Macro With Context带上下文的宏能力让嵌套宏之间不仅能感知彼此的调用关系还能在展开阶段直接交换数据。本文以 stdlib/doc/libs/std/ast/ast_samples/context.md 为骨架结合std.ast的 API 文档与 ffi.cj 源码实现完整讲解assertParentContext的嵌套校验、setItem与getChildMessages的消息传递机制并给出可直接运行的编译示例与排错要点。一、背景什么是带上下文的宏Macro With Context在嵌套宏场景下一个宏调用内层宏可能出现在另一个宏调用外层宏的调用参数内部。std.ast为这类场景提供了专门的一组上下文函数用于在宏展开时获取调用上下文信息主要包括assertParentContext(String)断言当前宏调用嵌套在指定外层宏调用内否则报编译错误insideParentContext(String)以布尔值形式返回嵌套关系检查结果setItem(key, value)重载Bool/Int64/String/Tokens内层宏向外层宏发送键值对消息getChildMessages(String)外层宏获取指定内层宏发送的全部消息。这些函数有一个共同的使用限制见 ast_package_overview.md只能作为函数被直接调用不能赋值给变量不能作为实参或返回值使用。从实现上看它们依赖宏展开器在展开过程中维护的当前宏对象MACRO_OBJECT线程局部对象来工作因此脱离宏展开过程调用是没有意义的。二、嵌套宏上下文校验assertParentContext2.1 完整示例与编译命令宏定义文件macro_definition.cj// macro_definition.cj macro package macro_definition import std.ast.* public macro Outter(input: Tokens): Tokens { return input } public macro Inner(input: Tokens): Tokens { assertParentContext(Outter) return input }宏调用文件macro_call.cj// macro_call.cj package macro_calling import macro_definition.* main() { Outter var a 0 Inner var b 0 // error: The macro call Inner should with the surround code contains a call Outter. }编译命令# 先编译宏定义文件 cjc macro_definition.cj --compile-macro # 编译使用宏的文件 cjc macro_call.cj -o demoInner宏在定义时通过assertParentContext(Outter)声明调用我时我必须以Outter宏调用为外围上下文。由于示例调用中Outter与Inner是平级的两条语句、不存在嵌套关系编译期会直接报出错误error: The macro call Inner should with the surround code contains a call Outter.2.2 源码实现视角assertParentContext的实现位于 stdlib/libs/std/ast/ffi.cj第 282 行附近public func assertParentContext(parentMacroName: String): Unit { unsafe { if (let Some(macroObjPtr) - MACRO_OBJECT.get()) { var pStr LibC.mallocCString(parentMacroName) ... var flag CJ_CheckParentContext(macroObjPtr, pStr, true) ... if (!flag) { throw MacroContextException(Parent macro context check failed for macro ${parentMacroName}.) } } } }可以看到校验最终由运行时接口CJ_CheckParentContext完成它会遍历宏调用上下文链确认名为parentMacroName的外层宏调用确实包裹着当前宏。校验失败时抛出的异常类型是 MacroContextException最终由编译器以标准错误形式呈现给用户。2.3 需要条件判断时使用 insideParentContext如果不想直接报错而是想根据嵌套关系做分支处理可以使用insideParentContext(String)它返回Booltrue表示当前宏嵌套在给定的外层宏调用内实现同样位于 ffi.cj第 304 行附近其内部调用CJ_CheckParentContext(macroObjPtr, pStr, false)区别仅在于不抛出异常而是返回结果。典型用法public macro inner(input: Tokens): Tokens { if (insideParentContext(outer)) { // 处于 outer 宏内时的逻辑 } else { // 未处于 outer 宏内时的逻辑 } return input }三、内层宏向外层宏发送消息setItemassertParentContext解决的是嵌套关系校验而setItem解决的是嵌套宏之间的数据通信。3.1 完整示例宏定义文件macro_definition.cj// macro_definition.cj macro package macro_definition import std.ast.* public macro Outter(input: Tokens): Tokens { let messages getChildMessages(Inner) for (m in messages) { let value1 m.getString(key1) // get value: value1 let value2 m.getString(key2) // get value: value2 println(value1: ${value1} value2: ${value2}) } return input } public macro Inner(input: Tokens): Tokens { assertParentContext(Outter) setItem(key1, value1) setItem(key2, value2) return input }宏调用文件macro_call.cj// macro_call.cj import macro_definition.* main() { Outter( Inner var cnt 0 ) println(cnt) }编译命令# 先编译宏定义文件 cjc macro_definition.cj --compile-macro # 编译使用宏的文件 cjc macro_call.cj -o demo编译阶段输出value1: value1 value2: value2在这个例子中内层宏Inner在展开时通过setItem(key1, value1)与setItem(key2, value2)把两个键值对暂存到外层宏的上下文中随后外层宏Outter展开时调用getChildMessages(Inner)拿到Inner发送的一组信息对象每个调用Inner的位置对应一条消息再通过信息对象的getString按 key 取出对应值。3.2 setItem 的四种重载setItem支持四种值类型对应四个重载见 ast_package_funcs.md重载发送类型检索接口setItem(String, String)字符串getString(key)setItem(String, Int64)整数getInt64(key)setItem(String, Bool)布尔getBool(key)setItem(String, Tokens)词法单元序列getTokens(key)从源码看ffi.cj 第 331396 行每种重载都会把值序列化后连同类型标签交给运行时接口CJ_SetItemInfo类型标签用常量区分let ITEM_TYPE_STRING: UInt8 1 let ITEM_TYPE_INT64: UInt8 2 let ITEM_TYPE_BOOL: UInt8 3 let ITEM_TYPE_TOKENS: UInt8 4例如发送Tokens时实现会先调用value.toBytes()将词法单元序列化再以字节指针形式传递外层宏读取时再反序列化为Tokens。因此setItem不仅能传简单值还能把一段代码如quote(1 1)完整地传出去。四、外层宏接收消息getChildMessages 与 MacroMessage4.1 接收语义getChildMessages(children: String): ArrayListMacroMessage用于获取名为children的内层宏发送的全部消息。关键语义一个内层宏调用 一条MacroMessage如果Outter内调用了多次InnergetChildMessages会返回与调用次数等长的消息列表每条MacroMessage内部是一个键值对映射用getString/getInt64/getBool/getTokens按 key 取值没有消息不是错误从实现看ffi.cj 第 559 行附近当没有对应消息时返回空列表ArrayListMacroMessage()外层宏可直接遍历若按 key 取不到对应类型的信息getString等接口会抛出Exception如Macro item ${key} does not exist.或类型不匹配时提示has a different type: expected String。4.2 MacroMessage 的完整接口MacroMessage类见 ast_package_classes.md除上述四个 getter 外还提供hasItem(key: String): Bool判断该条消息中是否存在指定 key可在取值前做防御性检查。一个使用hasItem的典型防御写法参考 ast_package_exceptions.md 中的示例public macro outer(input: Tokens) { let messages getChildMessages(inner) if (messages.size 0 !messages[0].hasItem(key1)) { throw MacroContextException(No such item) } return input }4.3 多值多类型综合示例下面是在官方文档示例基础上整理的一个同时传递Int64与Bool的完整场景宏定义与宏调用分别编译// 宏定义 macro package M import std.ast.* import std.collection.ArrayList public macro inner(input: Tokens) { setItem(Int64FromInner, 100) // 发送 Int64 setItem(TrueFromInner, true) // 发送 Bool return input } public macro outer(input: Tokens) { let messages getChildMessages(inner) let msg messages[0] println(Message from inner-macro: ${msg.getInt64(Int64FromInner)}) println(Bool message: ${msg.getBool(TrueFromInner)}) return input }// 宏调用 import M.* outer(inner(var a 1)) main() { }编译运行后输出Message from inner-macro: 100 Bool message: true五、编译与调试流程上下文宏涉及两类编译过程编译宏定义使用--compile-macro选项编译宏定义文件例如cjc macro_definition.cj --compile-macro编译宏调用方直接编译使用宏的文件并输出可执行程序例如cjc macro_call.cj -o demo。如需观察宏展开过程与中间结果官方 API 文档中的示例还使用了--debug-macro选项如cjc macro_call.cj --debug-macro配合std.ast的语法树节点dump函数示例见 ast_samples/dump.md可以输出 AST 节点的完整结构便于定位上下文宏代码中Tokens变换是否正确。需要注意宏展开后的代码不允许出现包声明和包导入语句详见 parseProgram 的说明因此消息传递、上下文校验等逻辑都应封装在宏函数内部完成最终return input返回干净的可编译Tokens。六、常见错误与排查要点现象原因与处理编译报错The macro call Inner should with the surround code contains a call Outter.Inner的assertParentContext(Outter)校验失败说明调用处不存在Outter包裹检查调用代码的嵌套结构参考 context.md 第一组示例。抛出Macro item key does not exist.getString等取值接口按 key 找不到对应项先调用hasItem(key)判断或检查setItem的 key 是否拼写一致。抛出Macro item key has a different type: expected String.setItem发送的类型与取值接口不匹配setItem(String, Int64)发的值必须用getInt64取。getChildMessages返回空列表内层宏未发送消息或内层宏名与参数不一致文档明确没有消息不是错误可按空列表处理。上下文函数无法在宏外使用assertParentContext等函数依赖宏展开上下文MACRO_OBJECT只能在宏展开过程中直接调用。总结通过assertParentContext/insideParentContext与setItem/getChildMessages的组合仓颉宏作者可以在编译期实现嵌套关系约束 父子宏数据交换两类能力前者在宏定义处声明依赖的外层宏让错误在编译期提前暴露后者以内层宏调用为粒度把字符串、整数、布尔甚至整段Tokens代码安全地传递给外层宏处理。配合--compile-macro、--debug-macro与dump调试手段即可构建结构清晰、约束严谨的嵌套宏体系。相关 API 的完整签名与更多示例可继续参阅 ast_package_overview.md、ast_package_funcs.md 与源码实现 stdlib/libs/std/ast/ffi.cj。赞分享编程语言语言运行时标准库垃圾回收并发编程【免费下载链接】cangjie_runtime仓颉编程语言运行时与标准库。项目地址https://gitcode.com/Cangjie/cangjie_runtime点击查看免费下载相关推荐仓颉编程语言嵌套宏上下文通信实战Macro With Context 的断言约束与消息传递机制仓颉编程语言嵌套宏上下文通信实战Macro With Context 的断言约束与消息传递机制 在仓颉Cangjie语言的宏系统中嵌套宏调用一个宏调用文档知识库教程OpenHarmony仓颉 std.ast 包函数 API 全解析从词法解析到宏上下文通信仓颉 std.ast 包函数 API 全解析从词法解析到宏上下文通信 导读 std.ast 是仓颉标准库中负责 源码解析与抽象语法树AST构建 的核心包编程语言语言运行时标准库垃圾回收并发编程仓颉 std.ast 包函数 API 全解析从词法解析到宏上下文通信仓颉 std.ast 包函数 API 全解析从词法解析到宏上下文通信 std.ast 是仓颉标准库中面向编译期宏开发的语法解析包本文以 ast_packag文档知识库教程OpenHarmony上一篇Sinon.JS 完整指南JavaScript 测试的 Spies、Stubs 与 Mocks 实战与源码解析下一篇Nx 23.1.0 Gradle 迁移指南将 dev.nx.gradle.project-graph 升级到 0.1.23创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

VS2017 C++ DLL与C# P/Invoke跨语言调用实战指南

VS2017 C++ DLL与C# P/Invoke跨语言调用实战指南

1. 项目概述:为什么一个DLL调用问题值得花两小时认真拆解在某高校实验室做跨语言模块集成时,我第一次被“VS2017中C打包DLL库在CSharp(C#)中调用”这个看似基础的问题卡了整整一个下午。不是编译不过,也不是找不到入口…

2026/10/14 3:08:32 阅读更多 →
VS2017 C++ DLL与C# P/Invoke调用失败的根源与解决方案

VS2017 C++ DLL与C# P/Invoke调用失败的根源与解决方案

1. 为什么VS2017打包的C DLL在C#里调用总出“找不到入口点”或“无法加载模块”?这个问题我带过三届某高校嵌入式方向的毕业设计,几乎每届都有至少两个学生卡在同一个地方:用VS2017写好了一个功能完整的C算法库(比如图像灰度化、F…

2026/10/14 3:08:32 阅读更多 →
免费 Win11 与 Office 激活指南:MAS 脚本 4 种方式一键完成

免费 Win11 与 Office 激活指南:MAS 脚本 4 种方式一键完成

免费 Win11 与 Office 激活指南:MAS 脚本 4 种方式一键完成 【免费下载链接】Microsoft-Activation-Scripts Open-source Windows and Office activator featuring HWID, Ohook, TSforge, and Online KMS activation methods, along with advanced troubleshooting.…

2026/10/14 3:07:32 阅读更多 →

最新新闻

DNA到蛋白质的完整路径:转录、翻译与中心法则的分子实战

DNA到蛋白质的完整路径:转录、翻译与中心法则的分子实战

DNA怎么变成蛋白质?这个问题的完整答案,比课本上那张中心法则的箭头要丰富得多。我当年第一次给学生讲清楚转录和翻译的全程时,最深的感受是:知识链条其实不长,但每一环都有大量“看似理所当然、实则经不起追问”的细节…

2026/10/14 3:40:38 阅读更多 →
基于CNN的水下声源定位实战:从数据到部署全流程

基于CNN的水下声源定位实战:从数据到部署全流程

简介:一套基于PyTorch的海洋水下声源定位实战项目,使用卷积神经网络(CNN)对水下声学信号进行建模,预测声源方位角与距离,完整覆盖从声学数据到位置估计的流程。资源面向水声工程、人工智能、电子信息、自动…

2026/10/14 3:40:38 阅读更多 →
Falcom经典游戏源码构建与调试实战指南

Falcom经典游戏源码构建与调试实战指南

简介:本资源为Falcom十大经典游戏系列的项目源码整理包,面向游戏开发初学者、JRPG爱好者及逆向分析兴趣者,提供一份轻量级参考素材,辅助理解经典日式RPG的设计脉络与基础架构逻辑。压缩包共3个文件,含1个HTML页面&…

2026/10/14 3:40:38 阅读更多 →
秋叶SD整合包V5.0代码版:从改代码到批量出图API实战

秋叶SD整合包V5.0代码版:从改代码到批量出图API实战

简介:秋叶SD整合包V5.0面向希望快速上手Stable Diffusion的Windows新手用户,解决环境配置繁琐、参数调节门槛高的问题。资源包共3个文件,以inscode工程配置、html页面与gitignore忽略规则为主,压缩包仅6KB,属于轻量级代…

2026/10/14 3:40:38 阅读更多 →
三站时差定位球面模型实战:从时差解算到经纬度

三站时差定位球面模型实战:从时差解算到经纬度

简介:这份资源围绕三站时差定位(TDOA)展开,面向无线通信、雷达定位与物联网设备追踪方向的学习者和开发者,重点解决无GPS覆盖环境下利用信号到达时间差解算信号源位置的问题。内容涉及Chan提出的球面TDOA实现思路&…

2026/10/14 3:40:38 阅读更多 →
一张图微调YOLOv11:自然栖息地鸟类检测的流程与扩充

一张图微调YOLOv11:自然栖息地鸟类检测的流程与扩充

简介:面向 YOLOv11 模型验证需求,这份精简版鸟类目标检测数据集包含一张真实野外鸟类图像及配套标准标注,可用于快速原型验证、轻量级部署测试与小样本检测基线建立。压缩包共五个文件,包含三张 JPG 图像、一个数据配置文件与一个…

2026/10/14 3:39:38 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →