# cangjie_meta_programming **Repository Path**: zl3624/cangjie_meta_programming ## Basic Information - **Project Name**: cangjie_meta_programming - **Description**: 清华大学出版社《仓颉语言元编程》附书示例代码 - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2024-07-07 - **Last Updated**: 2025-07-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 仓颉语言元编程附书示例代码 #### 项目说明 清华大学出版社《仓颉语言元编程》附书示例代码 当前示例代码已全面适配仓颉语言1.0.0正式版本 #### 适配记录 [ChangeLog](./ChangeLog.md) #### 书籍介绍 仓颉语言元编程由张磊编写,清华大学出版社出版。该书从元编程的概念开始,逐步讲解仓颉元编程的基础知识、抽象语法树的常用用法,以及如何定义和使用仓颉宏。 该书内容丰富,包括12个章节 第1章 元编程简介,介绍了什么是元编程以及两种主要的元编程实现模式。 第2章 仓颉元编程初探,通过对一个典型问题的两种解决方式对比,展示仓颉元编程的强大能力。 第3章 词法单元,词法单元是抽象语法树的基础,本节介绍了词法单元的构造方式以及如何使用。 第4章 表达式,仓颉中几乎一切对象都是表达式,本章详细介绍了常用的表达式,并通过示例演示基本用法。 第5章 类型,仓颉语言包括多种数据类型,这些数据类型在抽象语法树中有对应的类型进行表示,本章详细介绍了几种主要的类型。 第6章 基础声明,介绍了变量和接口声明的使用方式。 第7章 函数声明,介绍了普通函数声明与main函数声明的使用方式,并通过一个示例演示面向切面编程思想的实现。 第8章 Class声明,介绍了Class声明相关的函数声明以及属性声明。 第9章 泛型与模式匹配,介绍了在元编程中泛型以及模式匹配的使用,重点介绍了六种常用的模式。 第10章 代码结构,介绍包节点和导入节点的用法,建立了抽象语法树的完整轮廓。 第11章 宏, 介绍了宏的定义以及调用方式,通过示例演示宏的用法。 第12章 宏示例实战解析,详细解析第二章演示的宏的实现代码,并介绍了如何增强该宏的功能。 #### 仓颉宏示例(本书第12章) 以下的代码模拟了登录以及入库、出库、查看库存等动作,包括多个类和顶层函数,假如要求把所有的函数调用都记录日志,也就是记录调用开始和结束的时间,以及传入的参数和返回的值,并且支持日志写入到控制台或者日志文件。 ``` main(): Unit { //模拟登录 if (!login("admin", "qD@0532")) { println("用户名或者密码错误!") return } //添加图书 let book = Book("仓颉语言元编程") //模拟入库 book.input(88) //模拟出库 book.output(66) //查看库存 println(book.stock) } //登录 func login(userName: String, password: String): Bool { let user = User.getUserByUserName(userName) return user.passwd == password } //用户 public class User { public User(var userId: Int64, var userName: String, var passwd: String) {} //根据用户名称查找用户信息 public static func getUserByUserName(userName: String) { return User(1, userName, "qD@0532") } } public class Book { public Book(var bookName: String, var stock: Int64) {} public init(bookName: String) { this.bookName = bookName this.stock = 0 } //入库 public func input(count: Int64) { this.stock += count return stock } //出库 public func output(count: Int64) { this.stock -= count return stock } } ``` 要完成这样的功能,可能需要几百行代码才能实现,而且代码会嵌入到现有的函数中,带来一定的调试困难。但是,如果有了元编程的支持,通过宏定义一切就可以迎刃而解了。 ``` import cradle.* from std import time.* from std import collection.* from std import fs.* from std import io.* from std import os.posix.* @Cradle main(): Unit { //模拟登录 if (!login("admin", "qD@0532")) { println("用户名或者密码错误!") return } //添加图书 let book = Book("仓颉语言元编程") //模拟入库 book.input(88) //模拟出库 book.output(66) //查看库存 println(book.stock) } //登录 @Cradle[console|logfile] func login(userName: String, password: String): Bool { let user = User.getUserByUserName(userName) return user.passwd == password } //用户 @Cradle[console|logfile] public class User { public User(var userId: Int64, var userName: String, var passwd: String) {} //根据用户名称查找用户信息 public static func getUserByUserName(userName: String) { return User(1, userName, "qD@0532") } } @Cradle[console|logfile] public class Book { public Book(var bookName: String, var stock: Int64) {} public init(bookName: String) { this.bookName = bookName this.stock = 0 } //入库 public func input(count: Int64) { this.stock += count return stock } //出库 public func output(count: Int64) { this.stock -= count return stock } } ``` 这是实现了上述功能的代码,只是在函数和类的定义位置添加上Cradle宏调用即可,一共加了四个,就实现了所有这些功能。既简单明了,又做到了逻辑分离。 下面是运行后的效果,包括输出到控制台的日志和写入到日志文件的日志: