Show HN:CAPL Playground 在浏览器中编译并运行 Vector CAPL
Show HN: CAPL Playground – compile and run Vector CAPL in the browser
CAPL Playground 是一个在浏览器中编译并运行 Vector CAPL(CANoe/CANalyzer 节点语言)的在线工具,编译器完全在页面内运行,不上传服务器。
一个用于 Vector CAPL(CANoe/CANalyzer 节点语言)的在线演练场。 在浏览器中编写 CAPL,观察它经过真实的编译器流水线,以 JSON 形式检查 AST,阅读生成的 C,阅读生成的 WebAssembly——然后 运行该 WebAssembly,在一个带有虚拟时间、定时器、CAN 总线和按键事件的微型模拟测量环境中。
不会向服务器发送任何内容:编译器在页面内运行。
source.can ─▶ lexer ─▶ parser ─▶ AST ─▶ sema ─┬─▶ wasm backend ─▶ .wasm ─▶ simulator
├─▶ C backend ─▶ .c
└─▶ AST backend ─▶ .json
仓库布局
src/ the playground UI (React + Vite + Tailwind v4)
core/ Rust WASM bridge and editor-only syntax lexer
driver.ts frontend contract for capl-wasm
runtime/sim.ts the simulated CANoe measurement (host imports)
components/ editor, panels, architecture tab
rust/ the compiler core as reusable crates
crates/capl-diag spans + diagnostic bag
crates/capl-parse recursive-descent parser and lexer
crates/capl-ast AST, type lattice, visitor, serde JSON export
crates/capl-sema scopes, symbols, types
crates/capl-codegen-wasm wasm module writer (LEB128 + sections, no deps)
crates/capl-codegen-c C99 writer
crates/capl-driver stage orchestration, Backend trait, `capl` CLI
crates/capl-wasm wasm-bindgen facade for this page
Rust 编译器,TypeScript UI
页面在 React 启动前加载 capl-wasm。它在 globalThis.__CAPL_CORE__ 上注册唯一的编译器
实现;TypeScript 只负责编辑器、
模拟宿主和展示层。
./rust/build-wasm.sh # wasm-pack build → public/capl/capl_wasm.js cargo run -p capl-driver -- node.can --emit=wat cargo run -p capl-driver -- node.can --emit=wasm -o node.wasm cargo test --workspace
原生驱动程序相对于源文件解析 includes { "file.can" }。可以通过
CAPL_INCLUDE_PATH 环境变量提供额外的搜索目录(使用平台路径分隔符)。
浏览器构建没有文件系统访问权限,因此目前 include 仅限于原生驱动程序使用。
Rust 测试覆盖率和 CAPL 测试夹具
编译器在 rust/crates/capl-driver/tests/ 下有驱动程序级集成测试。它们通过
Rust 词法分析器、解析器、语义处理、C 后端和 WebAssembly 后端编译真实的 CAPL 程序。测试夹具
涵盖定时器和处理程序、周期性 CAN 消息、数组和函数、
64 位和浮点表达式,以及无效输入诊断。
安装一次 cargo-llvm-cov,然后
运行:
cd rust
cargo llvm-cov --workspace --all-features --lcov --output-path coverage/lcov.info
cargo llvm-cov --workspace --all-features --html --open在 Windows 上,./rust/coverage.ps1 运行 LCOV 命令并打印摘要。
CI 安装相同的工具,并在 Rust 测试任务期间生成 rust/coverage/lcov.info,然后将其作为 rust-coverage 工件上传。原生
覆盖率命令有意测量可复用的编译器 crate;
capl-wasm 门面由浏览器构建和运行时冒烟测试来检验。
生成的模块
wasm 后端手工写出二进制——LEB128、各个节、一个代码构建器, 同步生成字节和 WAT 清单。
0x0000 null guard
0x0040 vararg marshalling area (32 slots × 16 B) used by write()
0x0400 string pool, globals, message objects, function statics
导入(模块 "capl",由宿主提供——此处是浏览器模拟器,
其他地方可能是 CANoe 垫片或测试台):
write(fmt, argc, args) setTimer(id, ms) setTimerCyclic(id, ms)
cancelTimer(id) output(msgPtr) timeNow() -> i32
random(n) -> i32 strlen(ptr) -> i32 pow/sin/cos
canOnline() canOffline() stopMeasurement()
导出:memory、不可变全局变量 __msgbuf(事件
消息对象的地址)、__init、__set_this、__set_fuel、每个用户函数以及
每个事件处理程序一个函数(on_start、on_timer_tick、
on_message_0x100、on_key_103、……)。
每个循环回边都会递减一个燃料计数器,并在其归零时陷入,因此
意外的 while (1) {} 不会冻结标签页——模拟器会将其报告为
运行时陷入。
支持的语言子集
variables{} 块(也可以定义类型)· 全局变量 · const · 具名
struct 声明,带字段和字段数组 · 原生驱动程序 includes{}
支持相对路径和 CAPL_INCLUDE_PATH · 数组
和花括号初始化器 · byte word dword qword int long int64 float double char
· 标量类型和 数组,包括花括号初始化器和多维
索引 · 消息对象,带
.id .dlc .can .byte(n) .word(n) .dword(n) 和 this · timer/msTimer ·
事件 preStart start stopMeasurement preStop timer message key sysvar envVar errorFrame busOff(对 on message CAN2.0x100 进行通道感知匹配)·
if else while do for switch(带贯穿)break continue return · 完整的
C 表达式语法,包括 ?:、短路 &&/|| 和复合
赋值 · 用户函数,支持递归、数组参数和
基于地址的聚合参数/返回值 · 内置函数
write(printf 风格)、output、elCount、timeNow、random、abs、min、
max、sqrt、pow、sin、cos、floor、ceil、strlen、canOnline、
canOffline、stopMeasurement。
局部聚合变量在声明时由生成的 __zero 辅助函数清零,
这使示例保持可复现。诸如 const int N = 3 之类的编译期常量会被折叠为立即数,且从不占用线性内存。
当前的聚合 ABI 在 WASM 中将数组和结构体作为线性内存地址传递。C 后端在函数边界使用数组指针和结构体指针,返回结构体的函数返回指向所返回对象的指针。这使两个后端能够与相同的源码级模型互操作;调用方应将聚合值视为基于存储的对象,而非标量寄存器值。
TODO:CAPL 语言覆盖范围
编译器有意实现了一个聚焦的 CAPL 子集。以下语法和语言特性保留给未来工作,不应仅因为词法分析器能识别其关键字就视为已支持:
includes在浏览器构建中,那里没有文件系统包含解析器;原生驱动程序支持相对文件和CAPL_INCLUDE_PATH。- 匿名结构体、递归布局、打包/位域,以及超出当前命名字段子集的完整 CAPL 布局兼容性。
- 基于数据库的对象和信号访问,例如
$Signal,包括消息限定的信号和信号赋值。 - CAPL 测试模块:
testcase、testfunction、测试设置/拆卸,以及测试判定/报告 API。 - 超出当前地址 ABI 的聚合转换,包括针对每个数组和结构体上下文的精确 CAPL 复制/别名规则。
- 除当前定时器、消息、按键、系统变量、环境变量和总线/错误事件之外的额外 CAPL 事件形式和运行时对象。
- CANoe/CANalyzer 项目使用的 CAPL 特定属性、限定符、命名空间和配置语法。
- 用于诊断、传输协议、面板、文件、套接字和测量配置的更广泛内置 API 表面。
每个条目在应被宣传为受支持之前,都需要解析器、语义分析、后端和运行时覆盖。新语法还应获得驱动程序集成测试夹具,并在适用时获得聚焦的优先级/诊断测试。
UI
- 浅色 / 深色 / 系统主题,记忆于
localStorage - 英语 / 简体中文,从
navigator.language自动检测 - 具有精确范围的诊断,可点击,在编辑器边栏中镜像显示
- 状态栏中的各阶段计时、令牌/节点计数和模块大小
- 模拟栏:虚拟时钟、
+100 ms/+1 s、帧注入、按键事件、待处理定时器检查器
键盘:Ctrl/⌘ + Enter 构建并运行。
免责声明
CAPL Playground 是一个独立的、实验性的兼容性与教学项目。它未获得 Vector Informatik GmbH、CANoe、CANalyzer 或任何其他 Vector 产品的赞助、认可、关联或衍生。“Vector”、“CAPL”、“CANoe”和“CANalyzer”是各自所有者的名称和商标,此处仅用于标识本项目旨在互操作的语言或行为。本项目不包含 Vector 软件、专有数据库、文档或测试资产,也不声称实现官方 CAPL 工具链。
使用本项目风险自负。您有责任检查适用于您使用中涉及的任何源代码、规范、示例、商标、逆向工程活动和部署环境的许可证和条款。本声明仅供参考,不构成法律建议。
许可证
版权所有 (c) 2026 Wei Li
本项目根据以下任一许可证双许可,由您选择:
除非您明确声明,否则任何有意提交以纳入本项目的贡献均应按上述方式双重许可,不附加任何额外条款或条件。
编译器架构参考
编译器架构参考了 DMD 前端的设计。
来源:Hacker News · github.com
