名称: 宏系统 描述: 用于设计和实现宏系统的专业技能,包括卫生宏、过程宏和宏展开。支持基于模式的宏、准引用和卫生性管理。 允许工具: 读取、写入、编辑、Bash、Glob、Grep
宏系统技能
为编程语言设计和实现宏系统,从简单的基于文本的宏到复杂的卫生宏系统。
能力
- 设计宏调用语法和模式
- 实现基于模式的宏匹配和展开
- 实现带作用域管理的卫生宏展开
- 处理宏生成标识符的冲突避免
- 实现带AST操作的过程/语法宏
- 设计用于代码生成的准引用系统
- 处理宏调试和错误报告
- 实现用于开发的宏展开追踪
使用场景
在以下情况时调用此技能:
- 为新语言设计宏系统
- 实现卫生宏展开
- 创建过程宏API
- 构建准引用设施
- 调试宏展开问题
输入参数
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
| macroType | 字符串 | 是 | 宏系统类型(模式、过程、卫生) |
| targetLanguage | 字符串 | 是 | 宏实现的目标语言(Rust、Scheme等) |
| syntax | 对象 | 否 | 自定义语法规范 |
| hygieneModel | 字符串 | 否 | 卫生性模型(作用域集合、标记、无) |
| features | 数组 | 否 | 要实现的特性 |
特性选项
{
"features": [
"模式匹配",
"准引用",
"卫生性",
"过程宏",
"展开追踪",
"错误恢复",
"递归宏",
"宏模块化"
]
}
输出结构
宏系统/
├── 语法/
│ ├── 宏定义.语法 # 宏定义语法
│ ├── 宏调用.语法 # 调用语法
│ └── 准引用.语法 # 准引用语法
├── 展开/
│ ├── 模式匹配器.ts # 模式匹配引擎
│ ├── 模板替换.ts # 模板实例化
│ ├── 卫生管理器.ts # 卫生性/作用域管理
│ └── 展开器.ts # 主展开驱动
├── 过程宏/
│ ├── 过程宏-api.ts # 过程宏API
│ ├── 令牌流.ts # 令牌操作
│ └── 引用.ts # 准引用实现
├── 调试/
│ ├── 展开追踪.ts # 展开追踪
│ └── 错误报告器.ts # 宏错误消息
└── 测试/
├── 卫生性.测试.ts
├── 模式.测试.ts
└── 展开.测试.ts
宏系统类型
基于模式的宏(Scheme风格)
;; 定义
(define-syntax 我的或
(syntax-rules ()
[(我的或) #f]
[(我的或 e) e]
[(我的或 e1 e2 ...)
(let ([t e1])
(if t t (我的或 e2 ...)))]))
;; 实现模式
interface 宏规则 {
模式: 模式;
模板: 模板;
字面量: string[];
}
function 匹配模式(模式: 模式, 语法: 语法): 绑定 | null {
// 带省略号处理的模式匹配
}
function 替换模板(模板: 模板, 绑定: 绑定): 语法 {
// 带卫生性的模板实例化
}
过程宏(Rust风格)
// 派生宏示例
#[proc_macro_derive(Debug)]
pub fn 派生调试(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
impl_debug(&ast)
}
// 实现模式
interface 过程宏上下文 {
输入令牌: 令牌流;
跨度: 跨度;
卫生性: 卫生上下文;
}
interface 过程宏 {
展开(ctx: 过程宏上下文): 令牌流;
}
卫生展开
// 作用域集合卫生性模型(Racket风格)
interface 语法 {
数据: any;
作用域: Set<作用域>;
源位置: 源位置;
}
interface 作用域 {
id: number;
绑定: Map<符号, 绑定>;
}
function 引入作用域(语法: 语法, 作用域: 作用域): 语法 {
return { ...语法, 作用域: new Set([...语法.作用域, 作用域]) };
}
function 切换作用域(语法: 语法, 作用域: 作用域): 语法 {
const 新作用域 = new Set(语法.作用域);
if (新作用域.has(作用域)) {
新作用域.delete(作用域);
} else {
新作用域.add(作用域);
}
return { ...语法, 作用域: 新作用域 };
}
function 解析(语法: 语法): 绑定 | undefined {
// 查找具有最大匹配作用域集的绑定
}
准引用实现
// 准引用语法
// `(列表 ,x ,@xs) => (列表 (取消引用 x) (取消引用拼接 xs))
interface 准引用 {
模板: 准引用模板;
}
type 准引用模板 =
| { 类型: '字面量'; 值: any }
| { 类型: '取消引用'; 表达式: 语法 }
| { 类型: '取消引用拼接'; 表达式: 语法 }
| { 类型: '列表'; 元素: 准引用模板[] };
function 展开准引用(qq: 准引用, 环境: 环境): 语法 {
function 展开(模板: 准引用模板): 语法 {
switch (模板.类型) {
case '字面量':
return 引用字面量(模板.值);
case '取消引用':
return 求值(模板.表达式, 环境);
case '取消引用拼接':
// 拼接到外层列表
return 求值并拼接(模板.表达式, 环境);
case '列表':
return 创建列表(模板.元素.flatMap(展开));
}
}
return 展开(qq.模板);
}
展开追踪
interface 展开步骤 {
宏名称: string;
输入语法: 语法;
输出语法: 语法;
绑定: Map<string, 语法>;
位置: 源位置;
}
class 展开追踪器 {
private 步骤: 展开步骤[] = [];
记录步骤(步骤: 展开步骤): void {
this.步骤.push(步骤);
}
格式化追踪(): string {
return this.步骤.map((步骤, i) =>
`步骤 ${i + 1}: ${步骤.宏名称}
` +
` 输入: ${格式化语法(步骤.输入语法)}
` +
` 输出: ${格式化语法(步骤.输出语法)}
` +
` 绑定: ${格式化绑定(步骤.绑定)}`
).join('
');
}
}
错误处理
interface 宏错误 {
类型: '模式不匹配' | '卫生性违规' | '展开限制' | '语法错误';
消息: string;
宏名称: string;
输入语法: 语法;
建议: string[];
}
function 报告宏错误(错误: 宏错误): string {
const 基础 = `宏展开错误在'${错误.宏名称}'中:
${错误.消息}`;
const 上下文 = `
输入语法:
${格式化语法(错误.输入语法)}`;
const 提示 = 错误.建议.length > 0
? `
建议:
${错误.建议.map(s => ` - ${s}`).join('
')}`
: '';
return 基础 + 上下文 + 提示;
}
工作流程
- 定义宏语法 - 定义和调用的语法
- 实现模式匹配 - 将调用与模式匹配
- 构建模板替换 - 用绑定实例化模板
- 添加卫生性管理 - 处理标识符作用域
- 创建过程API - 用于复杂转换
- 构建准引用 - 代码生成助手
- 实现追踪 - 用于调试宏展开
- 生成测试套件 - 卫生性、模式、边界情况
应用的最佳实践
- 宏定义与展开的清晰分离
- 默认卫生性,显式非卫生性逃生舱口
- 带展开上下文的信息性错误消息
- 展开深度限制以防止无限递归
- 通过展开保留源位置
- 用于IDE支持的增量展开
参考文献
- 绑定作为作用域集合: https://www.cs.utah.edu/plt/scope-sets/
- Rust宏: https://doc.rust-lang.org/reference/macros.html
- Scheme R7RS宏: https://small.r7rs.org/
- Racket宏步进器: https://docs.racket-lang.org/macro-debugger/
目标流程
- 宏系统实现.js
- 解析器开发.js
- 语义分析.js