Add Endor source reader before lexing with provenance and URI provider
Verify databases and deploy Aster VM / verify-and-deploy (push) Successful in 6m53s
Verify databases and deploy Aster VM / verify-and-deploy (push) Successful in 6m53s
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
| 内容 | 职责 |
|
||||
| --- | --- |
|
||||
| Cargo.toml | cli 二进制与 core/frontend/host 依赖;无 storage 或 Tokio 依赖 |
|
||||
| [src](src/README.md) | 参数路由、引导演示、源码解析和退出码 |
|
||||
| [src](src/README.md) | 参数路由、引导演示、文件/stdin 阅读、源码解析和退出码 |
|
||||
| [tests](tests/README.md) | parse 命令的 AST 输出、错误位置和严格 UTF-8 检查 |
|
||||
|
||||
运行方式见 [运行指南](../../docs/operations/README.md),输入边界见 [配置](../../docs/operations/configuration.md)。parse 严格读取 UTF-8 文件并输出 AST,不执行源码,见 [前端](../../docs/runtime/frontend.md);metadata put/get 和只导入缺失项的 import 均使用文件,见 [宿主信息](../../docs/operations/host-information.md)。返回 [工作区](../README.md)。
|
||||
运行方式见 [运行指南](../../docs/operations/README.md),输入边界见 [配置](../../docs/operations/configuration.md)。parse 通过 EndorReader 严格读取 UTF-8 文件或 `-` 指定的 stdin 并输出 AST,不执行源码,见 [前端](../../docs/runtime/frontend.md);metadata put/get 和只导入缺失项的 import 均使用文件,见 [宿主信息](../../docs/operations/host-information.md)。返回 [工作区](../README.md)。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# CLI 入口
|
||||
|
||||
[main.rs](main.rs) 是唯一入口:同步 main 将 run 的结果转成进程退出码;run 处理 bootstrap、parse 文件、help、文件 metadata put/get/import,错误打印到 stderr 并返回失败。
|
||||
[main.rs](main.rs) 是唯一入口:同步 main 将 run 的结果转成进程退出码;run 处理 bootstrap、parse 文件/stdin、help、文件 metadata put/get/import,错误打印到 stderr 并返回失败。
|
||||
|
||||
bootstrap 创建并显式释放两个对象,不读取数据库环境、不打开数据库。parse 使用 frontend 输出 AST,词法/语法错误显示文件、行、列;不创建 VM 或执行源码。未知命令报错;metadata 通过 host::MetadataStore 读写文件,import 从标准输入接收旧记录且不覆盖已有文件。参数目前由 std::env::args 读取,非 Unicode 参数可能 panic,边界见 [配置](../../../docs/operations/configuration.md)。
|
||||
bootstrap 创建并显式释放两个对象,不读取数据库环境、不打开数据库。parse 使用 EndorReader 和 parse_source 输出 AST;`-` 从 stdin 读到 EOF,来源为 `<stdin>`。词法/语法错误显示来源、行、列;不创建 VM 或执行源码。未知命令报错;metadata 通过 host::MetadataStore 读写文件,import 从标准输入接收旧记录且不覆盖已有文件。参数目前由 std::env::args 读取,非 Unicode 参数可能 panic,边界见 [配置](../../../docs/operations/configuration.md)。
|
||||
|
||||
新增命令时更新用法、[运行指南](../../../docs/operations/README.md) 和 [smoke.py 的导航](../../../scripts/README.md)。返回 [cli](../README.md)。
|
||||
|
||||
+8
-10
@@ -2,9 +2,10 @@ use std::error::Error;
|
||||
use std::process::ExitCode;
|
||||
|
||||
use endor_core::{Value, Vm};
|
||||
use frontend::{EndorReader, parse_source};
|
||||
use host::MetadataStore;
|
||||
|
||||
const USAGE: &str = "Usage: cli [bootstrap | parse <file> | metadata put <key> <value> | metadata get <key> | metadata import | help]";
|
||||
const USAGE: &str = "Usage: cli [bootstrap | parse <file|-> | metadata put <key> <value> | metadata get <key> | metadata import | help]";
|
||||
|
||||
fn main() -> ExitCode {
|
||||
match run() {
|
||||
@@ -46,15 +47,12 @@ fn run() -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
["help"] | ["--help"] | ["-h"] => println!("{USAGE}"),
|
||||
["parse", path] => {
|
||||
let source =
|
||||
std::fs::read_to_string(path).map_err(|error| format!("{path}: {error}"))?;
|
||||
let program = frontend::parse(&source).map_err(|error| {
|
||||
let location = error.location(&source);
|
||||
format!(
|
||||
"{path}:{}:{}: {}",
|
||||
location.line, location.column, error.message
|
||||
)
|
||||
})?;
|
||||
let source = if *path == "-" {
|
||||
EndorReader::from_stream("<stdin>", std::io::stdin().lock())?
|
||||
} else {
|
||||
EndorReader::from_file(path)?
|
||||
};
|
||||
let program = parse_source(&source)?;
|
||||
println!("{program:#?}");
|
||||
}
|
||||
["metadata", "put", key, value] => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# CLI 命令检查
|
||||
|
||||
[parse.rs](parse.rs) 使用 Cargo 提供的 cli 测试二进制检查 parse 命令:合法 UTF-8 源码输出 AST 且不执行名称调用;非法语法输出文件/行/列并返回失败;非法 UTF-8 不替换字符。
|
||||
[parse.rs](parse.rs) 使用 Cargo 提供的 cli 测试二进制检查 parse 命令:合法 UTF-8 源码输出 AST 且不执行名称调用;非法语法输出文件/行/列并返回失败;非法 UTF-8 不替换字符;`parse -` 检查 stdin 输入、EOF 和带流名的错误。
|
||||
|
||||
测试仅在 ces-control 的工作区检查中运行,本地不执行。测试临时文件使用独立名称并在结束时清理。返回 [cli](../README.md),验证约定见 [验证](../../../docs/operations/validation.md)。
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
static NEXT_FILE: AtomicUsize = AtomicUsize::new(0);
|
||||
@@ -65,3 +66,42 @@ fn parse_command_reports_source_locations_and_rejects_invalid_utf8() {
|
||||
assert!(!output.status.success());
|
||||
assert!(output.stdout.is_empty());
|
||||
}
|
||||
|
||||
fn parse_stdin(source: &[u8]) -> std::process::Output {
|
||||
let mut child = Command::new(env!("CARGO_BIN_EXE_cli"))
|
||||
.args(["parse", "-"])
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
let mut stdin = child.stdin.take().unwrap();
|
||||
stdin.write_all(source).unwrap();
|
||||
drop(stdin);
|
||||
child.wait_with_output().unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_command_reads_stdin_to_eof_and_reports_its_origin() {
|
||||
let output = parse_stdin("function 表示(): String { return \"日\" }".as_bytes());
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"{}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
assert!(String::from_utf8(output.stdout).unwrap().contains("表示"));
|
||||
let output = parse_stdin(b"function f(): Number {\n return )\n}");
|
||||
assert!(!output.status.success());
|
||||
assert!(
|
||||
String::from_utf8(output.stderr)
|
||||
.unwrap()
|
||||
.contains("<stdin>:2:10:")
|
||||
);
|
||||
let output = parse_stdin(&[0xff]);
|
||||
assert!(!output.status.success());
|
||||
assert!(
|
||||
String::from_utf8(output.stderr)
|
||||
.unwrap()
|
||||
.contains("<stdin>: invalid UTF-8 at byte 0")
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user