Skip to content

Commit 576a099

Browse files
committed
Remove parse command; deduplicate cascading errors
1 parent a720b29 commit 576a099

2 files changed

Lines changed: 20 additions & 108 deletions

File tree

crates/allium-parser/src/parser.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,14 @@ impl<'s> Parser<'s> {
116116
}
117117

118118
fn error(&mut self, span: Span, msg: impl Into<String>) {
119+
let line = self.source_map.line_col(span.start).0;
120+
if let Some(last) = self.diagnostics.last() {
121+
if last.severity == crate::diagnostic::Severity::Error
122+
&& self.source_map.line_col(last.span.start).0 == line
123+
{
124+
return;
125+
}
126+
}
119127
self.diagnostics.push(Diagnostic::error(span, msg));
120128
}
121129

@@ -2605,8 +2613,18 @@ rule ProcessDigests {
26052613

26062614
#[test]
26072615
fn error_recovery_multiple() {
2608-
// Parser should recover and report multiple errors
2616+
// Parser should recover and report multiple errors (on separate lines)
26092617
let r = parse("entity E { + }\nentity F { - }");
26102618
assert!(r.diagnostics.len() >= 2, "expected at least 2 errors, got {}", r.diagnostics.len());
26112619
}
2620+
2621+
#[test]
2622+
fn error_dedup_same_line() {
2623+
// Multiple bad tokens on a single line should produce only one error
2624+
let r = parse("-- allium: 1\n+ - * /");
2625+
let errors: Vec<_> = r.diagnostics.iter()
2626+
.filter(|d| d.severity == crate::diagnostic::Severity::Error)
2627+
.collect();
2628+
assert_eq!(errors.len(), 1, "expected 1 error for same-line bad tokens, got {}", errors.len());
2629+
}
26122630
}

crates/allium/src/main.rs

Lines changed: 1 addition & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,14 @@ fn main() -> ExitCode {
99
if args.is_empty() || args[0] == "--help" || args[0] == "-h" {
1010
eprintln!("Usage: allium check <file.allium>...");
1111
eprintln!(" allium check <directory>");
12-
eprintln!(" allium parse <file.allium> [--json]");
1312
return ExitCode::from(2);
1413
}
1514

1615
match args[0].as_str() {
1716
"check" => cmd_check(&args[1..]),
18-
"parse" => cmd_parse(&args[1..]),
1917
other => {
2018
eprintln!("Unknown command: {other}");
21-
eprintln!("Available commands: check, parse");
19+
eprintln!("Available commands: check");
2220
ExitCode::from(2)
2321
}
2422
}
@@ -81,110 +79,6 @@ fn cmd_check(args: &[String]) -> ExitCode {
8179
}
8280
}
8381

84-
fn cmd_parse(args: &[String]) -> ExitCode {
85-
let json_mode = args.iter().any(|a| a == "--json");
86-
let files: Vec<&str> = args.iter().map(|s| s.as_str()).filter(|s| *s != "--json").collect();
87-
88-
if files.is_empty() {
89-
eprintln!("Usage: allium parse <file.allium> [--json]");
90-
return ExitCode::from(2);
91-
}
92-
93-
let source = match std::fs::read_to_string(files[0]) {
94-
Ok(s) => s,
95-
Err(e) => {
96-
eprintln!("{}: {e}", files[0]);
97-
return ExitCode::from(1);
98-
}
99-
};
100-
101-
let result = allium_parser::parse(&source);
102-
103-
if json_mode {
104-
// Minimal JSON output: just diagnostics for now.
105-
// Full AST serialisation can come later with serde.
106-
println!("{{");
107-
println!(" \"file\": {:?},", files[0]);
108-
println!(" \"version\": {:?},", result.module.version);
109-
println!(" \"declarations\": {},", result.module.declarations.len());
110-
println!(" \"diagnostics\": [");
111-
let source_map = SourceMap::new(&source);
112-
for (i, d) in result.diagnostics.iter().enumerate() {
113-
let (line, col) = source_map.line_col(d.span.start);
114-
let severity = match d.severity {
115-
Severity::Error => "error",
116-
Severity::Warning => "warning",
117-
};
118-
let comma = if i + 1 < result.diagnostics.len() { "," } else { "" };
119-
println!(
120-
" {{\"line\": {}, \"col\": {}, \"severity\": \"{severity}\", \"message\": {:?}}}{}",
121-
line + 1,
122-
col + 1,
123-
d.message,
124-
comma,
125-
);
126-
}
127-
println!(" ]");
128-
println!("}}");
129-
} else {
130-
println!("Parsed: {}", files[0]);
131-
if let Some(v) = result.module.version {
132-
println!("Version: {v}");
133-
}
134-
println!("Declarations: {}", result.module.declarations.len());
135-
for d in &result.module.declarations {
136-
println!(" {}", describe_decl(d));
137-
}
138-
if !result.diagnostics.is_empty() {
139-
let source_map = SourceMap::new(&source);
140-
println!("Diagnostics:");
141-
for d in &result.diagnostics {
142-
let (line, col) = source_map.line_col(d.span.start);
143-
let severity = match d.severity {
144-
Severity::Error => "error",
145-
Severity::Warning => "warning",
146-
};
147-
println!(" {}:{}: {severity}: {}", line + 1, col + 1, d.message);
148-
print_source_snippet(&source_map, &source, line, col);
149-
}
150-
}
151-
}
152-
153-
if result.diagnostics.iter().any(|d| d.severity == Severity::Error) {
154-
ExitCode::from(1)
155-
} else {
156-
ExitCode::SUCCESS
157-
}
158-
}
159-
160-
fn describe_decl(decl: &allium_parser::ast::Decl) -> String {
161-
use allium_parser::ast::*;
162-
match decl {
163-
Decl::ModuleDecl(m) => format!("module {}", m.name.name),
164-
Decl::Use(u) => {
165-
let alias = u.alias.as_ref().map(|a| format!(" as {}", a.name)).unwrap_or_default();
166-
format!("use {:?}{alias}", u.path.parts.iter().map(|p| match p {
167-
StringPart::Text(t) => t.as_str(),
168-
_ => "{...}",
169-
}).collect::<String>())
170-
}
171-
Decl::Block(b) => {
172-
let name = b.name.as_ref().map(|n| n.name.as_str()).unwrap_or("(anonymous)");
173-
format!("{:?} {name} ({} items)", b.kind, b.items.len())
174-
}
175-
Decl::Default(d) => format!("default {}", d.name.name),
176-
Decl::Variant(v) => format!("variant {} : {:?}", v.name.name, v.base),
177-
Decl::Deferred(_) => "deferred ...".to_string(),
178-
Decl::OpenQuestion(q) => {
179-
let text: String = q.text.parts.iter().map(|p| match p {
180-
StringPart::Text(t) => t.clone(),
181-
StringPart::Interpolation(id) => format!("{{{}}}", id.name),
182-
}).collect();
183-
format!("open question \"{text}\"")
184-
}
185-
}
186-
}
187-
18882
fn print_source_snippet(source_map: &SourceMap, source: &str, line: u32, col: u32) {
18983
let line_text = source_map.line_text(source, line);
19084
let line_num = format!("{}", line + 1);

0 commit comments

Comments
 (0)