first version
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
macro package simapi.macros
|
||||
|
||||
import std.ast.*
|
||||
import std.fs.*
|
||||
import std.collection.*
|
||||
|
||||
/**
|
||||
* 编译期宏:从指定 cjpm.toml 读取 version 字段并替换变量声明。
|
||||
*
|
||||
* 用法:
|
||||
* ```
|
||||
* @ReadTomlVersion[path: "cjpm.toml"] // 读取当前包(编译目录)的版本
|
||||
* let appVersion: String = ""
|
||||
* @ReadTomlVersion[path: "../simapi-cj/cjpm.toml"] // 读取父包版本
|
||||
* let simApiVersion: String = ""
|
||||
* ```
|
||||
*
|
||||
* 说明:宏在编译期执行,工作目录为 cjpm build 的运行目录(应用项目根)。
|
||||
* 版本号仅匹配 `version = "x.y.z"`(排除 cjc-version)。
|
||||
*/
|
||||
public macro ReadTomlVersion(attr: Tokens, input: Tokens): Tokens {
|
||||
var path = "cjpm.toml"
|
||||
try {
|
||||
let attrText = attr.toString()
|
||||
if (let Some(idx) <- attrText.indexOf("path")) {
|
||||
let rest = attrText[idx..]
|
||||
if (let Some(q1) <- rest.indexOf("\"")) {
|
||||
let after = rest[(q1 + 1)..]
|
||||
if (let Some(q2) <- after.indexOf("\"")) {
|
||||
path = after[0..q2]
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
|
||||
var version = "0.0.0"
|
||||
try {
|
||||
let f = File(path, Read)
|
||||
var buf = Array<Byte>(8192, repeat: 0)
|
||||
var bytes = ArrayList<Byte>()
|
||||
var n = f.read(buf)
|
||||
while (n > 0) {
|
||||
for (i in 0..n) {
|
||||
bytes.add(buf[i])
|
||||
}
|
||||
n = f.read(buf)
|
||||
}
|
||||
f.close()
|
||||
// 按行解析(version 行是纯 ASCII;避免整体 UTF-8 解码含中文的 description 失败)
|
||||
let data = bytes.toArray()
|
||||
var lineStart = 0
|
||||
for (i in 0..data.size) {
|
||||
let isLast = (i == data.size - 1)
|
||||
if (data[i] == 10 || isLast) {
|
||||
let end = if (data[i] == 10) { i } else { i + 1 }
|
||||
let lineBytes = data[lineStart..end]
|
||||
let lineText = String.fromUtf8(lineBytes)
|
||||
if (!lineText.contains("cjc-version") && lineText.contains("version")) {
|
||||
let parts = lineText.split("\"")
|
||||
if (parts.size >= 2) {
|
||||
version = parts[1]
|
||||
}
|
||||
}
|
||||
lineStart = i + 1
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
version = "error:${ex.message}"
|
||||
}
|
||||
|
||||
// 生成替换声明:保留原声明的修饰符与变量名,只把值替换为版本号
|
||||
// declPrefix 例:"public static let" / "private let" / "let"
|
||||
var declPrefix = "let"
|
||||
var varName = "v"
|
||||
try {
|
||||
let inputText = input.toString()
|
||||
if (let Some(letIdx) <- inputText.indexOf("let")) {
|
||||
let prefix = inputText[0..letIdx].trimEnd()
|
||||
if (!prefix.isEmpty()) {
|
||||
declPrefix = "${prefix} let"
|
||||
}
|
||||
let rest = inputText[letIdx..]
|
||||
let afterLet = rest[3..].trimStart()
|
||||
if (let Some(nameEnd) <- afterLet.indexOf(":")) {
|
||||
varName = afterLet[0..nameEnd].trimEnd()
|
||||
}
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
|
||||
// 用 cangjieLex 把 "public static let name: String = "version"" 整体解析为 token 流
|
||||
let declText = "${declPrefix} ${varName}: String = \"${version}\""
|
||||
cangjieLex(declText)
|
||||
}
|
||||
Reference in New Issue
Block a user