@calcit/procs 0.12.18 → 0.12.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.yarn/install-state.gz +0 -0
- package/editing-history/202504160117-wasm-codegen-and-catalog-update.md +40 -0
- package/editing-history/202507160207-wasm-encoder-migration.md +48 -0
- package/editing-history/202604151211-record-nth-optimization.md +44 -0
- package/editing-history/202604160131-wasm-math-and-test-integration.md +28 -0
- package/lib/package.json +4 -3
- package/package.json +4 -3
package/.yarn/install-state.gz
CHANGED
|
Binary file
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# 202504160117 — 优化目录更新 + WASM codegen demo
|
|
2
|
+
|
|
3
|
+
## 优化目录更新
|
|
4
|
+
|
|
5
|
+
更新 `drafts/04-15-type-directed-optimization-catalog.md`:
|
|
6
|
+
|
|
7
|
+
- 标记 P0、P1、P2、P5、P7 为已完成,附 commit hash
|
|
8
|
+
- 标记 P3、P4 为推迟,附推迟原因
|
|
9
|
+
- 更新 Scope 行:从 `TernaryTreeList<ScopePair>` 改为 `Vec<ScopePair>`
|
|
10
|
+
- P5 描述更新为实际采用的 Vec 方案(而非原规划的 O(1) 方案)
|
|
11
|
+
- 新增「执行记录」节替代原「推荐执行顺序」,含基准数据(836ms→718ms,~14%)
|
|
12
|
+
|
|
13
|
+
## WASM codegen 实验性功能
|
|
14
|
+
|
|
15
|
+
### 新增文件
|
|
16
|
+
|
|
17
|
+
- `src/codegen/emit_wasm.rs` — ~440 行 WAT 代码生成器
|
|
18
|
+
- `demos/wasm-demo.cirru` — 示例程序(fibo、factorial、add-two)
|
|
19
|
+
- `docs/wasm-codegen.md` — 使用文档 + 未来改进路线
|
|
20
|
+
|
|
21
|
+
### 修改文件
|
|
22
|
+
|
|
23
|
+
- `src/codegen.rs` — 注册 `emit_wasm` 模块
|
|
24
|
+
- `src/cli_args.rs` — 新增 `EmitWasmCommand`(`cr <entry> wasm`)
|
|
25
|
+
- `src/bin/cr.rs` — 新增 `run_wasm_codegen` 入口
|
|
26
|
+
|
|
27
|
+
### 设计要点
|
|
28
|
+
|
|
29
|
+
- **纯 WAT 文本输出** — 零额外依赖,不引入 wasm-encoder 等 crate
|
|
30
|
+
- **All-f64 类型策略** — 所有值统一为 f64,Bool 用 1.0/0.0
|
|
31
|
+
- **支持子集** — defn、if、let、算术(&+/&-/&\*/&/)、比较(&</&>/&=)、recur、函数调用
|
|
32
|
+
- **不支持** — 字符串、Record/Map/Set、method dispatch、IO、可变参数
|
|
33
|
+
|
|
34
|
+
### 验证
|
|
35
|
+
|
|
36
|
+
- wasmtime compile 验证 WAT 合法
|
|
37
|
+
- wasmtime run 验证 fibo(10)=89、factorial(10)=3628800、add-two(3.5,2.5)=6
|
|
38
|
+
- cargo test 246/246 pass
|
|
39
|
+
- cargo clippy -- -D warnings clean
|
|
40
|
+
- yarn check-all pass
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# wasm-encoder 迁移:WAT 文本 → 二进制 .wasm
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
将 WASM codegen 从手工拼接 WAT 文本字符串改为使用 `wasm-encoder` crate 直接生成二进制 `.wasm`,
|
|
6
|
+
同时将测试运行时从 wasmtime CLI 替换为 Node.js 内置的 `WebAssembly` API。
|
|
7
|
+
|
|
8
|
+
## 动机
|
|
9
|
+
|
|
10
|
+
- wasmtime 是重量级依赖,CI 需要额外安装步骤,且跨版本 CLI 接口不稳定(v14/v25 breaking changes)
|
|
11
|
+
- WAT 字符串拼接容易出错且难以调试
|
|
12
|
+
- Node.js 自带 WebAssembly 运行时,零额外依赖
|
|
13
|
+
|
|
14
|
+
## 关键知识点
|
|
15
|
+
|
|
16
|
+
### wasm-encoder 用法
|
|
17
|
+
|
|
18
|
+
- `wasm-encoder = "0.246.2"`,仅 1 个传递依赖 `leb128fmt`
|
|
19
|
+
- TypeSection → FunctionSection → ExportSection → CodeSection → module.finish()
|
|
20
|
+
- `F64Const` 接受 `Ieee64` 而非 `f64`,需 `Ieee64::from(val)` 包装
|
|
21
|
+
- `Function::new(locals_vec)` + `instruction(&Instruction::...)` + `instruction(&Instruction::End)`
|
|
22
|
+
|
|
23
|
+
### WASM block depth 追踪
|
|
24
|
+
|
|
25
|
+
- `br N` 中 N 是相对深度(0 = 当前块)
|
|
26
|
+
- `if` 块会增加一层嵌套,所以在 `if` 内部 `br` 到外层 `loop` 需要 depth=1
|
|
27
|
+
- 解决方案:`WasmGenCtx` 添加 `block_depth` 字段,`emit_if` 时 +1,`recur` 使用 `Br(ctx.block_depth)`
|
|
28
|
+
|
|
29
|
+
### 两阶段编译
|
|
30
|
+
|
|
31
|
+
- 函数互调需要预知 fn_index,所以:
|
|
32
|
+
1. 第一遍:收集函数签名和索引映射 `HashMap<String, u32>`
|
|
33
|
+
2. 第二遍:编译函数体,失败的函数用 stub `[f64_const(0.0)]` 保持索引稳定
|
|
34
|
+
|
|
35
|
+
### 比较运算的 i32→f64 转换
|
|
36
|
+
|
|
37
|
+
- WASM 比较指令(f64.lt/gt/eq)返回 i32
|
|
38
|
+
- 用 `select(1.0, 0.0, cmp_result)` 转为 f64
|
|
39
|
+
- `if` 条件用 `f64.ne(val, 0.0)` 转回 i32
|
|
40
|
+
|
|
41
|
+
## 修改文件
|
|
42
|
+
|
|
43
|
+
- `src/codegen/emit_wasm.rs` — 完全重写
|
|
44
|
+
- `scripts/test-wasm.mjs` — 新增 Node.js 测试运行器
|
|
45
|
+
- `scripts/test-wasm.sh` — 简化为生成 + node 调用
|
|
46
|
+
- `.github/workflows/test.yaml` — 移除 wasmtime 安装步骤
|
|
47
|
+
- `Cargo.toml` / `Cargo.lock` — 添加 wasm-encoder
|
|
48
|
+
- `docs/wasm-codegen.md` — 更新文档
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# `&record:nth` — Compile-Time Record Field Index Optimization
|
|
2
|
+
|
|
3
|
+
## 概述
|
|
4
|
+
|
|
5
|
+
新增 `NativeRecordNth` / `&record:nth` 过程,在预处理阶段将 record 字段访问优化为 O(1) 索引访问,绕过运行时的类型分发链和二分查找。
|
|
6
|
+
|
|
7
|
+
## 优化前访问路径
|
|
8
|
+
|
|
9
|
+
- `(:field record)` → 重写为 `(get arg :field)` → 运行时 6 次类型判断 (`nil?` → `string?` → `map?` → `list?` → `tuple?` → `record?`) → `&record:get` → `index_of()` O(log n) 二分查找
|
|
10
|
+
- `&record:get record :field` → 运行时 `index_of()` O(log n) 二分查找
|
|
11
|
+
|
|
12
|
+
## 优化后访问路径
|
|
13
|
+
|
|
14
|
+
当预处理阶段可以通过 `resolve_type_value` + `as_struct()` 解析出 record 的 struct 定义时:
|
|
15
|
+
|
|
16
|
+
- `(:field record)` → 直接重写为 `(&record:nth record <compile-time-idx>)` → 运行时 O(1) `values[idx]`
|
|
17
|
+
- `&record:get record :field` → 重写为 `(&record:nth record <compile-time-idx>)` → 运行时 O(1)
|
|
18
|
+
|
|
19
|
+
## 触发条件
|
|
20
|
+
|
|
21
|
+
优化仅在类型信息明确时激活:
|
|
22
|
+
- record 由 `%Struct ...` 构造器在本地 `let` 中创建
|
|
23
|
+
- 函数参数有显式 struct 类型的 schema 标注
|
|
24
|
+
|
|
25
|
+
若类型不明,回 fallback 到原有路径,不影响运行时行为。
|
|
26
|
+
|
|
27
|
+
## 修改文件
|
|
28
|
+
|
|
29
|
+
1. **`src/calcit/proc_name.rs`** — 新增 `NativeRecordNth` 变体 (`&record:nth`),签名 `(record, number) → dynamic`
|
|
30
|
+
2. **`src/builtins/records.rs`** — 实现 `record_nth(xs)` 运行时函数,直接 `values[idx]` 访问
|
|
31
|
+
3. **`src/builtins.rs`** — 分发表连线 `NativeRecordNth => records::record_nth`
|
|
32
|
+
4. **`src/runner/preprocess/mod.rs`** — 两个重写点:
|
|
33
|
+
- Tag-call (`Calcit::Tag` as head):解析 arg 类型后索引重写
|
|
34
|
+
- `NativeRecordGet` proc call:解析 record arg 类型后索引重写
|
|
35
|
+
5. **`src/runner/preprocess/type_inference.rs`** — `infer_record_nth_type()` 根据 struct 的 `field_types[idx]` 推断返回类型
|
|
36
|
+
6. **`src/runner/preprocess/type_checking.rs`** — 将 `NativeRecordNth` 加入 core arg type check 跳过列表
|
|
37
|
+
7. **`src/codegen/emit_js.rs`** — JS 内联代码生成 `record.values[idx]`,无函数调用开销
|
|
38
|
+
|
|
39
|
+
## 知识点
|
|
40
|
+
|
|
41
|
+
- `CalcitStruct.index_of(field_str)` 在编译期使用,用字段名解析排序位置
|
|
42
|
+
- `resolve_type_value()` 返回 `None` 时优化不触发,安全回退
|
|
43
|
+
- JS CalcitRecord 的 `.values` 数组和 Rust 端的 `values` Vec 索引一致(均按字段名字母序排序)
|
|
44
|
+
- 对于真实项目(如 respo),函数参数通常缺少 struct 类型标注,优化暂不触发;后续若 schema 推断增强,无需改动 rewrite 逻辑即可自动生效
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# 202604160131 — WASM codegen 扩展: 数学函数 + 测试集成
|
|
2
|
+
|
|
3
|
+
## 新增 WASM 操作
|
|
4
|
+
|
|
5
|
+
- `floor` → `f64.floor`
|
|
6
|
+
- `ceil` → `f64.ceil`
|
|
7
|
+
- `round` → `f64.nearest`
|
|
8
|
+
- `sqrt` → `f64.sqrt`
|
|
9
|
+
- `identical?` → `f64.eq`
|
|
10
|
+
- `sin`/`cos`/`pow` 明确报错(WASM 无对应指令)
|
|
11
|
+
|
|
12
|
+
## 新增文件
|
|
13
|
+
|
|
14
|
+
- `calcit/test-wasm.cirru` — 17 个纯数值函数测试(fibo, factorial, add-two, sum-range, floor, ceil, round, sqrt, rem, compare, not, let-chain, collatz-steps, gcd 等)
|
|
15
|
+
- `scripts/test-wasm.sh` — WASM 验证脚本(生成 WAT → wasmtime compile → 逐函数验证返回值)
|
|
16
|
+
|
|
17
|
+
## 修改文件
|
|
18
|
+
|
|
19
|
+
- `src/codegen/emit_wasm.rs` — 新增 `unary_op` 辅助函数, 添加 Floor/Ceil/Round/Sqrt/Identical 分支
|
|
20
|
+
- `package.json` — `check-all` 加入 `try-wasm` 步骤; 新增 `try-wasm` 脚本
|
|
21
|
+
- `docs/wasm-codegen.md` — 更新支持列表、测试说明、路线图
|
|
22
|
+
|
|
23
|
+
## 验证
|
|
24
|
+
|
|
25
|
+
- `yarn check-all` 通过(含 compile, try-rs, try-js, try-ir, try-wasm)
|
|
26
|
+
- `cargo test` 246/246 pass
|
|
27
|
+
- `cargo clippy -- -D warnings` clean
|
|
28
|
+
- wasmtime 逐函数验证: 17/17 assertions pass
|
package/lib/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@calcit/procs",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.19",
|
|
4
4
|
"main": "./lib/calcit.procs.mjs",
|
|
5
5
|
"devDependencies": {
|
|
6
6
|
"@types/node": "^25.0.9",
|
|
@@ -18,12 +18,13 @@
|
|
|
18
18
|
"test-snippets": "cargo test -q snippets::tests",
|
|
19
19
|
"bench-recur-smoke": "cargo run --bin cr -- calcit/test.cirru js && node --input-type=module -e \"import { test_loop } from './js-out/test-recursion.main.mjs'; const n=3000; const t0=process.hrtime.bigint(); for(let i=0;i<n;i++) test_loop(); const dt=Number(process.hrtime.bigint()-t0)/1e6; console.log('test_loop_ms='+dt.toFixed(3));\"",
|
|
20
20
|
"check-smooth": "yarn fmt-rs && yarn lint-rs && yarn test-rs && yarn check-all",
|
|
21
|
-
"check-all": "yarn compile && yarn try-rs && yarn try-js && yarn try-ir",
|
|
21
|
+
"check-all": "yarn compile && yarn try-rs && yarn try-js && yarn try-ir && yarn try-wasm",
|
|
22
22
|
"try-rs": "cargo run --bin cr -- calcit/test.cirru",
|
|
23
23
|
"warn-dyn-method": "cargo run --bin cr -- calcit/test.cirru --warn-dyn-method",
|
|
24
24
|
"try-js-brk": "cargo run --bin cr -- calcit/test.cirru js && node --inspect-brk js-out/main.mjs",
|
|
25
25
|
"try-js": "cargo run --bin cr -- calcit/test.cirru js && node js-out/main.mjs",
|
|
26
|
-
"try-ir": "cargo run --bin cr -- calcit/test.cirru js"
|
|
26
|
+
"try-ir": "cargo run --bin cr -- calcit/test.cirru js",
|
|
27
|
+
"try-wasm": "bash scripts/test-wasm.sh"
|
|
27
28
|
},
|
|
28
29
|
"repository": {
|
|
29
30
|
"type": "git",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@calcit/procs",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.19",
|
|
4
4
|
"main": "./lib/calcit.procs.mjs",
|
|
5
5
|
"devDependencies": {
|
|
6
6
|
"@types/node": "^25.0.9",
|
|
@@ -18,12 +18,13 @@
|
|
|
18
18
|
"test-snippets": "cargo test -q snippets::tests",
|
|
19
19
|
"bench-recur-smoke": "cargo run --bin cr -- calcit/test.cirru js && node --input-type=module -e \"import { test_loop } from './js-out/test-recursion.main.mjs'; const n=3000; const t0=process.hrtime.bigint(); for(let i=0;i<n;i++) test_loop(); const dt=Number(process.hrtime.bigint()-t0)/1e6; console.log('test_loop_ms='+dt.toFixed(3));\"",
|
|
20
20
|
"check-smooth": "yarn fmt-rs && yarn lint-rs && yarn test-rs && yarn check-all",
|
|
21
|
-
"check-all": "yarn compile && yarn try-rs && yarn try-js && yarn try-ir",
|
|
21
|
+
"check-all": "yarn compile && yarn try-rs && yarn try-js && yarn try-ir && yarn try-wasm",
|
|
22
22
|
"try-rs": "cargo run --bin cr -- calcit/test.cirru",
|
|
23
23
|
"warn-dyn-method": "cargo run --bin cr -- calcit/test.cirru --warn-dyn-method",
|
|
24
24
|
"try-js-brk": "cargo run --bin cr -- calcit/test.cirru js && node --inspect-brk js-out/main.mjs",
|
|
25
25
|
"try-js": "cargo run --bin cr -- calcit/test.cirru js && node js-out/main.mjs",
|
|
26
|
-
"try-ir": "cargo run --bin cr -- calcit/test.cirru js"
|
|
26
|
+
"try-ir": "cargo run --bin cr -- calcit/test.cirru js",
|
|
27
|
+
"try-wasm": "bash scripts/test-wasm.sh"
|
|
27
28
|
},
|
|
28
29
|
"repository": {
|
|
29
30
|
"type": "git",
|