Repository navigation
Expand file tree
/
Copy pathbuild_grammar_corpus.rs
More file actions
179 lines (172 loc) · 6.91 KB
/
Copy pathbuild_grammar_corpus.rs
File metadata and controls
179 lines (172 loc) · 6.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//! Rust 开发期语料导入;读取随仓上游 corpus,不运行编译器或改变批准状态。
use codeguard_adapters::{parse_grammar_test_corpus, parse_unique_json};
use codeguard_cli::grammar_evaluation::{validate_corpus, validate_corpus_against_manifest};
use codeguard_runtime::read_bounded_regular_file;
use serde_json::{Value, json};
use sha2::{Digest, Sha256};
use std::path::{Path, PathBuf};
use std::process::ExitCode;
fn build(base: &Path, additional: &Path, base_manifest: Option<&Path>) -> Result<Value, String> {
let bytes =
read_bounded_regular_file(base, 16 * 1024 * 1024).map_err(|_| "corpus_base_unavailable")?;
if let Some(path) = base_manifest {
let manifest = read_bounded_regular_file(path, 1024 * 1024)
.map_err(|_| "corpus_base_manifest_unavailable")?;
validate_corpus_against_manifest(&bytes, &manifest)?;
} else {
// 默认仍仅接受当前清单,不能自行猜测或查找历史身份。
validate_corpus(&bytes)?;
}
let mut document = parse_unique_json(&bytes).map_err(str::to_owned)?;
// 输出是新的当前绑定输入,不重写历史文件,也不赋予 oracle 或执行批准。
document["manifest_sha256"] = json!(format!(
"{:x}",
Sha256::digest(include_bytes!("../../../grammars/manifest.json"))
));
document["schema_version"] = json!("0.2.0");
let cases = document["cases"]
.as_array_mut()
.ok_or("corpus_cases_invalid")?;
for case in cases.iter_mut() {
case["cohort"] = json!(if case["label"] == "pending" {
"provisional_syntax"
} else {
"repository_regression"
});
}
let additional = read_bounded_regular_file(additional, 16 * 1024 * 1024)
.map_err(|_| "corpus_additional_unavailable")?;
let additional = parse_unique_json(&additional).map_err(str::to_owned)?;
cases.extend(
additional
.as_array()
.ok_or("corpus_additional_invalid")?
.iter()
.cloned(),
);
let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../grammars/dart/corpus");
let mut paths = std::fs::read_dir(&root)
.map_err(|_| "dart_corpus_directory_unavailable")?
.map(|e| e.map(|e| e.path()))
.collect::<Result<Vec<_>, _>>()
.map_err(|_| "dart_corpus_entry_unavailable")?;
paths.sort();
let mut total = 0;
for path in paths {
if path.extension().and_then(|e| e.to_str()) != Some("txt") {
continue;
}
let bytes = read_bounded_regular_file(&path, 16 * 1024 * 1024)
.map_err(|_| "dart_corpus_file_unavailable")?;
let source = std::str::from_utf8(&bytes).map_err(|_| "dart_corpus_encoding_invalid")?;
let name = path
.file_name()
.and_then(|s| s.to_str())
.ok_or("dart_corpus_path_invalid")?;
let stem = path
.file_stem()
.and_then(|s| s.to_str())
.ok_or("dart_corpus_path_invalid")?;
let origin_sha = format!("{:x}", Sha256::digest(&bytes));
for (index, sample) in parse_grammar_test_corpus(source)?.into_iter().enumerate() {
total += 1;
cases.push(json!({"id":format!("dart-upstream-{stem}-{index}"),"language":"dart",
"source_sha256":format!("{:x}",Sha256::digest(sample.source.as_bytes())),"source":sample.source,
"expected_valid":!sample.expected_error,"label":"regression","cohort":"upstream_grammar_regression",
"origin":format!("grammars/dart/corpus/{name}#sha256={origin_sha}:{}",sample.name)}));
}
}
if total != 150 {
return Err("dart_corpus_frozen_count_changed".into());
}
validate_corpus(&serde_json::to_vec(&document).map_err(|_| "corpus_serialization_failed")?)?;
Ok(document)
}
fn main() -> ExitCode {
let args: Vec<String> = std::env::args().skip(1).collect();
let (base, additional, base_manifest) = match args.as_slice() {
[base, additional] => (base, additional, None),
[base, additional, option, manifest] if option == "--base-manifest" => {
(base, additional, Some(Path::new(manifest)))
}
_ => {
eprintln!(
"用法: build_grammar_corpus BASE_JSON ADDITIONAL_JSON [--base-manifest HISTORICAL_MANIFEST_JSON]"
);
return ExitCode::from(2);
}
};
match build(
&PathBuf::from(base),
&PathBuf::from(additional),
base_manifest,
) {
Ok(document) => {
println!(
"{}",
serde_json::to_string_pretty(&document).expect("JSON value 可序列化")
);
ExitCode::SUCCESS
}
Err(reason) => {
eprintln!("语料导入拒绝:{reason}");
ExitCode::from(2)
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn importer_reproduces_every_checked_in_source_and_origin_byte() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
let document = super::build(
&root.join("tests/fixtures/grammar_regression.json"),
&root.join("tests/fixtures/grammar_additional_regressions.json"),
Some(&root.join("tests/fixtures/grammar_manifests/manifest_2026_10_04.json")),
)
.unwrap();
let mut historical: serde_json::Value = serde_json::from_str(include_str!(
"../../../tests/fixtures/grammar_regression_v0_2.json"
))
.unwrap();
assert_ne!(document["manifest_sha256"], historical["manifest_sha256"]);
historical["manifest_sha256"] = document["manifest_sha256"].clone();
assert_eq!(
document, historical,
"all historical samples and origins remain identical"
);
}
}
#[cfg(test)]
mod historical_identity_tests {
use super::build;
use std::path::Path;
#[test]
fn history_needs_an_explicit_matching_manifest() {
let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
for manifest in [None, Some(root.join("grammars/manifest.json"))] {
assert_eq!(
build(
&root.join("tests/fixtures/grammar_regression.json"),
&root.join("does-not-exist.json"),
manifest.as_deref()
)
.unwrap_err(),
"grammar_evaluation_corpus_identity_invalid"
);
}
}
#[test]
fn missing_explicit_manifest_does_not_fall_back_to_current_or_archived_metadata() {
let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
assert_eq!(
build(
&root.join("tests/fixtures/grammar_regression.json"),
&root.join("does-not-exist.json"),
Some(&root.join("missing-manifest.json"))
)
.unwrap_err(),
"corpus_base_manifest_unavailable"
);
}
}