Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions PERFORMANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ for character, index in 'a☕中x' by 2 then sum += index
sum
```

signed-by-iteration(10,000 次):
signed-by-iteration(20,000 次):

```coffee
sum = 0
Expand Down Expand Up @@ -543,7 +543,7 @@ rest 绑定会复制剩余元素到新的不可变数组,以保持宿主存储

`qbench --json` 现在包含 `signed-by-iteration`,并在每轮编译、验证和执行后检查 `3333`。该负载不把数组复制到宿主侧,反向位置由 VM 的有符号步长直接推进;运行基准时应与 `stepped-iteration` 一起比较编译、验证和执行三个阶段。

本次可复现实测在 Apple M1 Pro(T6000、16 GB 统一内存)、Darwin 25.5.0 上运行;编译器为 `rustc 1.94.0 (4a4ef493e 2026-03-02)`(完整 commit `4a4ef493e3a1488c6e321570238084b38948f6db`,LLVM 21.1.8),release 命令为 `cargo run --locked --release --bin qbench -- --json --iterations 100`。它得到 `signed-by-iteration` 一条记录:编译总计 `618750 ns`,验证总计 `28917 ns`,执行总计 `2363209 ns`,期望值为 `3333`。这是单次开发机样本,只用于确认工作负载已纳入语义护栏与性能采集;跨版本比较仍须按本报告口径重复至少三次并取中位数。
本次可复现实测(Apple arm64、Darwin 25.5.0`rustc 1.94.0`,release,命令 `cargo run --locked --release --bin qbench -- --json --iterations 100`)得到 `signed-by-iteration` 一条记录:编译总计 `618750 ns`,验证总计 `28917 ns`,执行总计 `2363209 ns`,期望值为 `3333`。这是单次开发机样本,只用于确认工作负载已纳入语义护栏与性能采集;跨版本比较仍须按本报告口径重复至少三次并取中位数。

标准 `cargo bench --locked --bench core`(10,000 次)同样已纳入该负载;本次样本为编译 `38.544 ms`、验证 `2.032 ms`、执行 `157.776 ms`,期望值 `3333`。它与正向 `stepped-iteration` 的执行样本(`124.616 ms`)同场输出,便于观察有符号步进的额外边界检查成本。

Expand Down
2 changes: 2 additions & 0 deletions RFCs/0083-qdocco-markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

`qdocco --markdown FILE [-o OUTPUT]` 先按普通 `qdocco` 路径读取、编译、验证并执行文件,再生成 Markdown。默认输出为输入文件同名的 `.md`;`-o` 指定其他路径。文档包含 `## Notes` 说明栏、`quickcoffee` 代码栏和 `## Final value` 最终值栏。代码围栏至少使用四个反引号,并按源码中最长的连续反引号序列自适应加长,以保留源文本而不让其中的 Markdown 标记执行。

输出路径经规范化后不得与输入源码相同(包括指向输入的符号链接),避免 `-o` 意外破坏文学源文件;此时命令以用法错误退出。

`--markdown` 与 `--check` 互斥;冲突返回退出码 2。读取、解析、验证或执行错误沿用现有非零退出语义。`qdocco --check` 仍只验证而不写任何产物,HTML 默认行为不变。

## 验收
Expand Down
10 changes: 10 additions & 0 deletions src/bin/qdocco.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ use std::{env, fs, path::PathBuf, process::ExitCode};
fn usage() {
eprintln!("Usage: qdocco [--check | --markdown] FILE [-o OUTPUT]\n qdocco --version");
}
fn same_path(left: &PathBuf, right: &PathBuf) -> bool {
match (fs::canonicalize(left), fs::canonicalize(right)) {
(Ok(left), Ok(right)) => left == right,
_ => left == right,
}
}
fn escape(input: &str) -> String {
input
.replace('&', "&")
Expand Down Expand Up @@ -127,6 +133,10 @@ fn main() -> ExitCode {
if !check {
let destination =
output.unwrap_or_else(|| input.with_extension(if markdown { "md" } else { "html" }));
if same_path(&input, &destination) {
eprintln!("output path must differ from the input source");
return ExitCode::from(2);
}
let document = if markdown {
render_markdown(&source, &result.to_string())
} else {
Expand Down
26 changes: 26 additions & 0 deletions tests/cli_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,32 @@ fn qdocco_renders_escaped_source_and_checks() {
);
let fenced_document = fs::read_to_string(&fenced_output).unwrap();
assert!(fenced_document.contains("`````quickcoffee\n# ````\ntrue\n`````"));
let overwrite = Command::new(bin("qdocco"))
.args([input.to_str().unwrap(), "-o", input.to_str().unwrap()])
.output()
.unwrap();
assert_eq!(overwrite.status.code(), Some(2));
assert!(String::from_utf8_lossy(&overwrite.stderr).contains("output path must differ"));
assert_eq!(fs::read_to_string(&input).unwrap(), "## <Guide>\n1 + 2\n");
#[cfg(unix)]
{
let linked_output = temp.join("demo-link.html");
std::os::unix::fs::symlink(&input, &linked_output).unwrap();
let overwrite_via_symlink = Command::new(bin("qdocco"))
.args([
input.to_str().unwrap(),
"-o",
linked_output.to_str().unwrap(),
])
.output()
.unwrap();
assert_eq!(overwrite_via_symlink.status.code(), Some(2));
assert!(
String::from_utf8_lossy(&overwrite_via_symlink.stderr)
.contains("output path must differ")
);
assert_eq!(fs::read_to_string(&input).unwrap(), "## <Guide>\n1 + 2\n");
}
let conflict = Command::new(bin("qdocco"))
.args(["--check", "--markdown", input.to_str().unwrap()])
.output()
Expand Down