实验性 0.1 · Rust 1.85+ · MIT OR Apache-2.0
QuickCoffee 是一台以 Rust 编写、受 CoffeeScript 启发的紧凑字节码脚本引擎。它适合把确定性的业务规则、校验、数据整形和受限插件逻辑嵌入应用;也提供一个单文件 CLI,便于直接运行和检查脚本。
它不是 JavaScript 运行时,也不试图兼容浏览器、Node.js 或 CoffeeScript 的全部历史行为。没有公开原型链、全局或自由 this、eval、反引号 JavaScript,以及隐式文件、网络或时钟权限。class 本身是完整的受限语言能力:支持 new、extends、super、实例/静态方法及 class 内 this/@,但这些接收者能力不会泄露到 class 外。
先使用已验证的正式归档;这不需要本地 Rust 工具链。选择与你的系统对应的 TARGET:
- Apple silicon Mac:
aarch64-apple-darwin - Intel Mac:
x86_64-apple-darwin - Linux x86_64:
x86_64-unknown-linux-gnu
下载归档和同一 Release 的 checksum,再校验、解包并确认版本。请整段执行;&& 确保任一步失败后不再继续解包或运行。若有错误,先解决下载、校验或目录问题,再重试,不要跳过校验:
VERSION=0.1.0
TARGET=aarch64-apple-darwin
ARCHIVE="quickcoffee-${VERSION}-${TARGET}.tar.gz"
BASE="https://github.com/coffee-js/quickcoffee/releases/download/v${VERSION}"
curl -fLO "${BASE}/${ARCHIVE}" &&
curl -fLO "${BASE}/SHA256SUMS" &&
grep -q " ${ARCHIVE}$" SHA256SUMS &&
if command -v sha256sum >/dev/null; then
grep " ${ARCHIVE}$" SHA256SUMS | sha256sum -c -
else
grep " ${ARCHIVE}$" SHA256SUMS | shasum -a 256 -c -
fi &&
tar -xzf "${ARCHIVE}" &&
cd "quickcoffee-${VERSION}-${TARGET}" &&
./qcoffee --versionWindows x86_64 请使用同一 Release 的 quickcoffee-0.1.0-x86_64-pc-windows-msvc.zip;可复制的 PowerShell 下载、校验和解包命令见发布与平台归档。归档不会自动修改 PATH,因此以下命令使用 ./(Windows 使用 ./qcoffee.exe 和 ./qtest.exe)。
归档内带有一个小型 JSON 清洗任务。它接收显式输入,校验字段,清理文本并稳定排序;这类校验、转换和规则计算正是 QuickCoffee 目前最适合的日常用途:
./qcoffee --json --module-root examples/getting-started demo -- '{"name":" Fix login ","tags":[" bug ","urgent"]}'
# {"ok":true,"exports":{"result":{"name":"Fix login","tags":["bug","urgent"]}}}规则在 examples/getting-started/task.coffee,入口在 demo.coffee。修改规则后,用同目录的隔离测试立即验证:
./qtest --module-root examples/getting-started test
# ok test/normalize_task.coffee接下来可以复制这个目录,把 normalize_task 换成自己的表单校验、配置整理或轻量业务规则。脚本不会隐式读取文件、访问网络或时间;需要这些能力时,由宿主显式读取数据后通过 argv、global 或 native callback 传入。完整语法可在需要时再查阅中文语法索引,不必先读完整手册。
每个归档包含五个 CLI、README、更新日志、双许可证与可直接运行的 Decimal .litcoffee/.coffee/.cson 场景,并与按文件名稳定排序的 SHA256SUMS 一起发布;发布门禁会从解包后的干净工作区验证 .coffee、GitHub-compatible .litcoffee、qdocco、qtest、qcson 双向转换和完整的 CSON → 定价规则链路。下载、校验、无 checkout 验收和维护者发布流程见发布与平台归档。Release archives and clean-install verification are documented bilingually in the same guide.
贡献 QuickCoffee、开发 Rust 嵌入程序,或需要跟随未发布改动时,使用 Rust 1.85 或更新版本从源码构建:
git clone https://github.com/coffee-js/quickcoffee.git &&
cd quickcoffee &&
cargo run --bin qcoffee -- -e "print(range(1, 4))"创建 invoice.coffee:
discount = (amount) ->
if amount >= 100 then amount * 0.9 else amount
print discount(120)在仓库目录中运行它。cargo run 不会把二进制安装到 PATH,因此源码示例继续通过 Cargo 调用:
cargo run --bin qcoffee -- invoice.coffee
# 108class 使用 CoffeeScript 风格的缩进成员体,同时保持接收者边界:
class Counter
constructor: (@value = 0) ->
increment: ->
@value = @value + 1
@value
counter = new Counter()
print counter.increment()| 场景 | 当前状态 | 说明 |
|---|---|---|
| 规则计算、定价、资格校验 | 适合 | 严格数值、函数、异常、switch 和 fuel 都已具备。 |
| 配置归并、表单/事件数据整形 | 适合 | 有不可变数组/Map、spread、解构、推导、Unicode 字符串和精确 JSON。 |
| class 形式的业务模型 | 适合 | 支持构造、继承、覆盖、super 和安全逸出的 receiver-bound =>。 |
| 受控嵌入式策略/插件 | 条件适合 | 宿主可注入全局值/原生函数,并设置 fuel、调用深度、数据资源限制和取消。 |
| 多文件 CLI 应用 | 受限适合 | 使用显式 --module-root ROOT ENTRY 运行静态 .coffee / .litcoffee 模块图,并可非执行地生成依赖敏感图指纹;嵌入宿主还可显式复用内存模块包。 |
| HTTP、文件 I/O、异步任务、定时调度 | 尚不适合 | 语言没有隐式环境能力、事件循环或异步语法;这些应由宿主以明确 capability 提供。 |
| 直接替换 JavaScript/CoffeeScript 项目 | 不适合 | 语义刻意不同,且缺少正则、日期时间、字节/流、生成器等能力。 |
完整的业务适用性、边界和规划请看业务就绪度评估。CoffeeScript 1.12.7 的逐项“实现 / 改写 / 拒绝”对照在特性矩阵。
QuickCoffee 已提供:
- 严格的 Bool 条件与数值运算;
Number、任意精度Integer与精确Decimal彼此分型,转换必须显式。 - 数组、无原型 Map、spread、严格递归解构、范围、切片、列表推导,以及 Unicode 标量级字符串索引和遍历。
- 函数、默认参数、rest 参数、闭包、
try/catch/finally、throw、return、循环与switch。 - 资源有界的 JSON/CSON 纯数据编解码、稳定标量排序、不可变
map_set/map_delete、trim/contains/starts_with/replace_all等确定性能力;JSON/CSON 保留 Integer/Decimal 精度,CSON 不执行表达式。 - 受限 class:
constructor、实例/静态方法、new、私有继承链、静态解析的super,以及只在合法 class 成员内可用的this、@和=>。 - 编译检查、结构化诊断、字节码反汇编/指纹,以及带隔离 Context 和有界共享编译缓存的
Runtime嵌入 API。
请把这些差异当作语言设计,而不是待补的 JavaScript 兼容性:没有隐式类型转换、undefined、公开 prototype / __proto__、任意函数构造、自由 this 或 eval。class 外使用 this、super 或 receiver-bound => 是编译错误。
完整语法和标准库边界见中文语法索引与English syntax index。
| 目的 | 命令 |
|---|---|
| 执行表达式 | qcoffee -e "print(1 + 2)" |
| 执行文件并传参 | qcoffee script.coffee -- first second(脚本中读取 argv) |
| 从标准输入执行 | qcoffee - < script.coffee |
| 运行受限模块图 | qcoffee --module-root modules app/main -- first |
| 检查模块图指纹 | qcoffee --fingerprint --module-root modules app/main |
| 运行隔离模块测试 | qtest --module-root examples/pricing test |
| 规范化 JSON 文件 | cargo run --example normalization -- examples/normalization/input.v1.json |
| CSON 转 canonical JSON | qcson to-json config.cson 或 qcson to-json - |
| JSON 转 canonical CSON | qcson to-cson config.json 或 qcson to-cson - |
| 用 CSON 驱动定价规则 | CONFIG_JSON="$(qcson to-json examples/pricing/config.cson)"; qcoffee --module-root examples/pricing configured -- "$CONFIG_JSON" |
| 持久交互会话 | qcoffee --interactive(逐物理行求值;:help、:quit) |
| 只检查、不执行 | qcoffee --check script.coffee |
| 稳定 JSON 输出 | qcoffee --json script.coffee(错误保留 legacy 字段并附带 version 1 完整 labels) |
| 限制本次执行 fuel | qcoffee --fuel 100000 script.coffee |
| 限制源码与字节码 | qcoffee --max-source-bytes 1000000 --max-bytecode-instructions 1000000 script.coffee |
| 限制模块图 | qcoffee --max-module-graph-modules 1024 --max-module-graph-source-bytes 16000000 --module-root modules app/main |
| 检查编译结果 | qcoffee --dump-bytecode script.coffee 或 qcoffee --fingerprint script.coffee |
qcson 只读取显式文件或标准输入,并把成功结果写到标准输出;它不执行 CSON/QuickCoffee,也不授予脚本文件、模块、网络、时钟或其他 capability。它刻意不提供原地覆盖或输出路径,需要保存时由用户显式重定向。--max-input-bytes / --max-output-bytes 在读取或输出增长前限制资源;--diagnostic-format json 把版本化 quickcoffee.qcson-diagnostic.v1 错误写到 stderr,不污染成功数据。
qcson reads only an explicit file or stdin and writes successful data to stdout. It executes neither CSON nor QuickCoffee and grants no script capability. There is deliberately no in-place or output-path mode; redirection is an explicit user choice. Resource limits apply before reads or output growth, and versioned JSON diagnostics remain on stderr.
.coffee 是普通 QuickCoffee 源码的规范扩展名;.litcoffee 使用 GitHub 原生支持的 Literate CoffeeScript 形式:Markdown 正文保持未缩进,技术标识使用反引号行内代码,可执行代码块统一缩进四个空格并与正文留出空行。```coffee 围栏只适用于生成后的普通 Markdown,不会成为 .litcoffee 的可执行代码。命名编译、执行、检查、模块加载和 qtest 都会自动识别 .litcoffee;qdocco 只接受 .litcoffee 并生成带版本标记的文档,--incremental 会在最终产物字节不变时保留已有文件。qbench 用于可重复的基准和 QuickJS 同机对照。这些都是项目工具,不是部署时的必需组件。
qtest --module-root ROOT ENTRY_OR_DIRECTORY... 显式授予一个受限模块根,把每个规范化入口预检为内存 ModulePackage 后在隔离 Context 中运行;入口必须 export test = true。将根内测试目录作为输入(例如 qtest --module-root . test)会递归发现其中的 .coffee 与 .litcoffee 入口,以稳定的根相对路径排序和去重;每个用例仍使用独立 Context。该模式复用 fuel、每 case timeout、filter/list、stats、JSON、TAP 与 JUnit 契约,普通文件模式仍不获得模块权限,目录外与符号链接逃逸也会被拒绝。
qtest --module-root ROOT ENTRY_OR_DIRECTORY... explicitly grants one restricted module root and preflights every canonical entry into an in-memory ModulePackage before running it in an isolated Context; each entry must export test = true. Passing a test directory under that root (for example, qtest --module-root . test) recursively discovers its .coffee and .litcoffee entries, with stable root-relative labels, sorting, and deduplication; each case still gets its own Context. The mode retains fuel, per-case timeout, filter/list, stats, JSON, TAP, and JUnit contracts. Ordinary-file mode gains no module authority, and outside-root or symlink escapes are rejected.
普通 qcoffee/qtest 脚本错误会在 legacy 错误首行后有界显示自定义领域错误的非 nil data,再显示 primary range、按调用顺序排列的 secondary ranges、紧凑源码片段与可操作 hint;直接 throw 的值仍只保留在既有首行,避免重复。.litcoffee 继续指向原始 Markdown 的物理行,无法可靠恢复的列不会被伪造。人类 details: 最多显示 160 个 Unicode 标量,超长内容以 … 标记;qcoffee --json 成功记录不变,错误记录保留完整领域 data、既有字段并增加 diagnostic: {version: 1, labels: [...]}。完整契约见 RFC 0160。
REPL 不猜测多行块:每个非命令物理行是一次求值,并以稳定的 <repl:N> 来源名保留到会话结束,让跨输入调用链仍能指回定义行;多行程序请使用 .coffee / .litcoffee 文件。
最小嵌入可以直接创建一个 Context;需要让多个隔离 Context 复用编译产物时,由一个 Runtime 统一创建:
use quickcoffee::{Error, ExecutionPolicy, Runtime};
fn evaluate_rule() -> Result<(), Error> {
let runtime = Runtime::builder()
.execution_policy(ExecutionPolicy::isolated_request())
.build();
let value = runtime
.context_builder()
.build()
.eval_named("rules/discount.coffee", "amount = 120; amount * 0.9")?;
println!("{value}");
Ok(())
}生产宿主默认采用每个 worker 一个 Runtime、每个请求一个隔离 Context,并从 ExecutionPolicy::isolated_request() 开始。Runtime、模块包和 VM 值留在创建它们的 worker;线程间只传普通 Rust 数据和 CancellationToken。真正不可信的脚本还需要进程隔离、OS 限额与外部超时。
完整选择表、固定源码依赖和可运行命令见生产嵌入指南。现有多 worker 示例、策略包宿主、定价宿主和JSON 规范化宿主覆盖这些用法,无需新增运行时抽象。
Production hosts default to one worker-owned Runtime and one isolated Context per request, starting from ExecutionPolicy::isolated_request(). VM values stay inside their worker; only ordinary Rust data and CancellationToken cross threads. See the bilingual production embedding cookbook. Truly untrusted scripts also require process isolation, OS limits, and external deadlines.
QuickCoffee 的核心语言、class、精确数值、确定性 JSON/CSON、Unicode 基元、CLI 诊断和基础嵌入 API 已实现,并由 RFC 与测试锁定。当前冻结没有真实使用证据的语言、标准库和运行时扩张;性能工作只处理影响实际任务且超过测量噪声的回归。
但它仍处于实验性 0.1:
- CLI 已支持显式根目录的受限模块加载和非执行模块图指纹;嵌入宿主可显式构建内存模块包,但没有持久化 manifest。普通文件、stdin、
-e和 REPL 不会隐式获得模块/文件权限。 - 原始 source、递归 bytecode、静态模块数、累计模块 source 与每轮累计 transient managed allocation 已有独立上限,但 logical memory 不等于进程 RSS 或完整沙箱;部署边界由 #77 跟踪。capability allowlist 已可显式配置,但具体系统能力仍必须由宿主实现并授权。
- 没有异步/并发、正则、日期时间、字节与流 API、网络或文件标准库;I/O 类能力保持为宿主显式责任。
- 性能已建立可重复的本地与 Linux 配对报告,但尚不能宣称达到 QuickJS 的整体量级;结果会随负载、平台和宿主交互而变化。
- 只有真实需求导致公开语义或兼容性变化时才新增 RFC;需要长期稳定接口的项目应先锁定版本并运行自己的语义与资源测试。
动态优先级与完成状态在路线图和 GitHub tracking issues 中维护:#65(产品入口)、#77(部署指南)、#66(统一性能基线)与 #78(冻结 backlog)。
qbench 分别报告普通编译、Program 准备、验证与执行,并可记录指令、调用、容器操作和托管值分配。qbench --compare-qjs /path/to/qjs --compare-iterations 1 --repeat 11 --json 可在同一机器上将启动、编译、预编译热执行和 CLI 总时长分开比较。
这些数字用于本仓库的回归判断,不是跨机器或跨语言的通用排名。测量协议、历史证据和解释边界见性能报告,最新优化进度见 #66。
前端、verifier 与 VM 执行另有独立的 cargo-fuzz 基线:make fuzz-smoke 使用固定 nightly、确定 seed、受审阅 seed corpus 与输入/资源边界运行三个 target;scheduled/manual workflow 还用同一 nightly 执行隔离的 Miri library smoke。make dependency-audit 通过 RustSec 审计根与 fuzz 两个 lockfile。nightly 不进入发布 crate 或每个 PR 的稳定工具链门禁;发现的 crash 必须最小化并转为普通回归测试。详见 fuzz README。
项目禁止 unsafe。修改源码后可运行:
make check该命令覆盖格式、debug/release 测试、示例、Clippy、公开 API 文档、crate 打包检查、确定性 qbench 护栏和全部可执行手册检查。
| 你想了解什么 | 入口 |
|---|---|
| 当前语法、标准库和 CLI 边界 | 中文语法索引 · English syntax index |
| 平台归档、校验和与发布门禁 | 发布与平台归档 / Releases |
| Rust 宿主生命周期、线程与隔离 | 生产嵌入指南 / Production embedding |
| 业务适用范围、性能判断和未完成能力 | 业务就绪度评估 |
| CoffeeScript 兼容性差异 | 特性矩阵 |
class / this / new / extends / super 的安全边界 |
RFC 0134 |
| 项目范围与不变设计原则 | RFC 0000 |
| 性能测量与历史基线 | PERFORMANCE.md |
| 长期方向与 issue 入口 | ROADMAP.md |
| 可执行语言手册 | 中文 · English |
RFC 0000 至 RFC 0162 是当前已采纳的语义、字节码、嵌入 API、工具与安全 CSON 数据契约;测试是这些契约的可执行验收。