# 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宏调用即可,一共加了四个,就实现了所有这些功能。既简单明了,又做到了逻辑分离。
下面是运行后的效果,包括输出到控制台的日志和写入到日志文件的日志:
