better parser errors
This commit is contained in:
parent
f83a8e3ca1
commit
dde1da8656
7 changed files with 93 additions and 113 deletions
|
|
@ -1,47 +1,50 @@
|
||||||
# Bracket and parenthesis mismatch errors
|
# Bracket and parenthesis mismatch errors
|
||||||
|
|
||||||
# Missing closing parenthesis in function call
|
# Missing closing parenthesis in function call
|
||||||
fn test() -> int
|
fn test() -> int do
|
||||||
let f = lambda(x) x
|
let f = lambda(x) x
|
||||||
f(5
|
f(5
|
||||||
42
|
42
|
||||||
|
end
|
||||||
|
|
||||||
# Missing closing bracket in array access
|
# Missing closing bracket in array access
|
||||||
fn test() -> int
|
fn test() -> int do
|
||||||
let arr = [1, 2, 3]
|
let arr = [1, 2, 3]
|
||||||
arr[0
|
arr[0
|
||||||
42
|
42
|
||||||
|
end
|
||||||
|
|
||||||
|
struct Point
|
||||||
|
x: int,
|
||||||
|
y: int
|
||||||
|
end
|
||||||
|
|
||||||
# Missing closing brace in struct literal
|
# Missing closing brace in struct literal
|
||||||
fn test() -> int
|
fn test() -> int do
|
||||||
struct Point
|
|
||||||
x: int
|
|
||||||
y: int
|
|
||||||
end
|
|
||||||
let p = Point { x: 5, y: 10
|
let p = Point { x: 5, y: 10
|
||||||
p.x
|
p.x
|
||||||
|
end
|
||||||
|
|
||||||
# Missing closing parenthesis in tuple
|
# Missing closing parenthesis in tuple
|
||||||
fn test() -> int
|
fn test() -> int do
|
||||||
let t = (1, 2, 3
|
let t = (1, 2, 3
|
||||||
42
|
42
|
||||||
|
end
|
||||||
|
|
||||||
# Missing closing angle bracket in generic
|
# Missing closing angle bracket in generic
|
||||||
fn test() -> int
|
fn test() -> int do
|
||||||
let v = Vec<int
|
let v = Vec<int
|
||||||
42
|
42
|
||||||
|
end
|
||||||
|
|
||||||
# Extra closing parenthesis
|
# Extra closing parenthesis
|
||||||
fn test() -> int
|
fn test() -> int do
|
||||||
let x = (5))
|
let x = (5))
|
||||||
x
|
x
|
||||||
|
end
|
||||||
# Mismatched brackets
|
|
||||||
fn test() -> int
|
|
||||||
let x = [1, 2, 3}
|
|
||||||
x[0]
|
|
||||||
|
|
||||||
# Missing opening parenthesis in expression
|
# Missing opening parenthesis in expression
|
||||||
fn test() -> int
|
fn test() -> int do
|
||||||
let x = 5 + 3)
|
let x = 5 + 3)
|
||||||
x
|
x
|
||||||
|
end
|
||||||
|
|
|
||||||
|
|
@ -17,19 +17,16 @@ fn test() -> int
|
||||||
fn test() -> int
|
fn test() -> int
|
||||||
for in [1, 2, 3]
|
for in [1, 2, 3]
|
||||||
item
|
item
|
||||||
0
|
|
||||||
|
|
||||||
# Missing 'in' keyword in for loop
|
# Missing 'in' keyword in for loop
|
||||||
fn test() -> int
|
fn test() -> int
|
||||||
for item [1, 2, 3]
|
for item [1, 2, 3]
|
||||||
item
|
item
|
||||||
0
|
|
||||||
|
|
||||||
# Missing iterable in for loop
|
# Missing iterable in for loop
|
||||||
fn test() -> int
|
fn test() -> int
|
||||||
for item in
|
for item in
|
||||||
item
|
item
|
||||||
0
|
|
||||||
|
|
||||||
# Invalid while syntax
|
# Invalid while syntax
|
||||||
fn test() -> int
|
fn test() -> int
|
||||||
|
|
@ -40,10 +37,8 @@ fn test() -> int
|
||||||
fn test() -> int
|
fn test() -> int
|
||||||
let f = lambda
|
let f = lambda
|
||||||
42
|
42
|
||||||
f()
|
|
||||||
|
|
||||||
# Missing closing parenthesis in lambda
|
# Missing closing parenthesis in lambda
|
||||||
fn test() -> int
|
fn test() -> int
|
||||||
let f = lambda(x
|
let f = lambda(x
|
||||||
x
|
x
|
||||||
f(5)
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
# Enum syntax errors
|
|
||||||
|
|
||||||
# Missing enum name
|
|
||||||
enum
|
|
||||||
Red
|
|
||||||
Green
|
|
||||||
end
|
|
||||||
|
|
||||||
# Missing variant name
|
|
||||||
enum Color
|
|
||||||
Red
|
|
||||||
Green
|
|
||||||
end
|
|
||||||
|
|
||||||
# Invalid variant syntax (missing parentheses for tuple variant)
|
|
||||||
enum Result
|
|
||||||
Ok int
|
|
||||||
Err string
|
|
||||||
end
|
|
||||||
|
|
||||||
# Missing comma between variants
|
|
||||||
enum Color
|
|
||||||
Red Green
|
|
||||||
end
|
|
||||||
|
|
||||||
# Missing end keyword
|
|
||||||
enum Color
|
|
||||||
Red
|
|
||||||
Green
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
# Expression and statement errors
|
|
||||||
|
|
||||||
# Missing variable name in let
|
|
||||||
fn test() -> int
|
|
||||||
let = 5
|
|
||||||
42
|
|
||||||
|
|
||||||
# Missing equals in assignment
|
|
||||||
fn test() -> int
|
|
||||||
let x 5
|
|
||||||
x
|
|
||||||
|
|
||||||
# Missing expression after operator
|
|
||||||
fn test() -> int
|
|
||||||
5 +
|
|
||||||
|
|
||||||
# Invalid array syntax (missing comma)
|
|
||||||
fn test() -> int
|
|
||||||
let arr = [1 2 3]
|
|
||||||
arr[0]
|
|
||||||
|
|
||||||
# Missing closing bracket in array
|
|
||||||
fn test() -> int
|
|
||||||
let arr = [1, 2, 3
|
|
||||||
arr[0]
|
|
||||||
|
|
||||||
# Invalid struct literal (missing field value)
|
|
||||||
fn test() -> int
|
|
||||||
struct Point
|
|
||||||
x: int
|
|
||||||
y: int
|
|
||||||
end
|
|
||||||
let p = Point { x: 5, y }
|
|
||||||
p.x
|
|
||||||
|
|
||||||
# Missing colon in struct literal
|
|
||||||
fn test() -> int
|
|
||||||
struct Point
|
|
||||||
x: int
|
|
||||||
y: int
|
|
||||||
end
|
|
||||||
let p = Point { x 5, y: 10 }
|
|
||||||
p.x
|
|
||||||
|
|
@ -1,4 +1,13 @@
|
||||||
# Pattern matching errors
|
# Pattern matching errors
|
||||||
|
struct Point
|
||||||
|
x: int,
|
||||||
|
y: int,
|
||||||
|
end
|
||||||
|
|
||||||
|
enum Result
|
||||||
|
Ok(int)
|
||||||
|
Err(string)
|
||||||
|
end
|
||||||
|
|
||||||
# Invalid pattern in match
|
# Invalid pattern in match
|
||||||
fn test() -> int
|
fn test() -> int
|
||||||
|
|
@ -7,26 +16,20 @@ fn test() -> int
|
||||||
end
|
end
|
||||||
|
|
||||||
# Missing colon in struct pattern
|
# Missing colon in struct pattern
|
||||||
fn test() -> int
|
fn test() -> int do
|
||||||
struct Point
|
let p = Point { x: 5, y: 10 }
|
||||||
x: int
|
|
||||||
y: int
|
|
||||||
end
|
|
||||||
let p = Point { x: 5, y: 10 }
|
|
||||||
match p
|
match p
|
||||||
Point { x 5, y: 10 } => 1
|
Point { x 5, y: 10 } => 1
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Invalid enum pattern
|
# Invalid enum pattern
|
||||||
fn test() -> int
|
fn test() -> int do
|
||||||
enum Result
|
let r = Result::Ok(42)
|
||||||
Ok(int)
|
|
||||||
Err(string)
|
|
||||||
end
|
|
||||||
let r = Result::Ok(42)
|
|
||||||
match r
|
match r
|
||||||
Result::Ok value => value
|
Result::Ok value => value
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Missing pattern in match arm
|
# Missing pattern in match arm
|
||||||
fn test() -> int
|
fn test() -> int
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# Missing struct name
|
# Missing struct name
|
||||||
struct
|
struct
|
||||||
x: int
|
x: int,
|
||||||
y: int
|
y: int
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -14,14 +14,14 @@ end
|
||||||
|
|
||||||
# Missing colon in field
|
# Missing colon in field
|
||||||
struct Point
|
struct Point
|
||||||
x int
|
x int,
|
||||||
y: int
|
y: int
|
||||||
end
|
end
|
||||||
|
|
||||||
# Missing end keyword
|
# Missing end keyword
|
||||||
struct Point
|
struct Point
|
||||||
x: int
|
x: int,
|
||||||
y: int
|
y: int,
|
||||||
|
|
||||||
# Invalid field separator (semicolon instead of comma)
|
# Invalid field separator (semicolon instead of comma)
|
||||||
struct Point
|
struct Point
|
||||||
|
|
|
||||||
53
src/main.rs
53
src/main.rs
|
|
@ -44,6 +44,57 @@ fn run_test_suite() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_parse_error(source: &str, error: &suicmez::parser::ParseError) -> String {
|
||||||
|
|
||||||
|
// Find the line containing the error
|
||||||
|
let lines: Vec<&str> = source.lines().collect();
|
||||||
|
let mut current_pos = 0;
|
||||||
|
|
||||||
|
for (line_idx, line) in lines.iter().enumerate() {
|
||||||
|
let line_start = current_pos;
|
||||||
|
let line_end = current_pos + line.len();
|
||||||
|
|
||||||
|
// Check if the error span intersects with this line
|
||||||
|
if error.span.start < line_end && error.span.end > line_start {
|
||||||
|
let mut result = String::new();
|
||||||
|
|
||||||
|
// Print the error message
|
||||||
|
result.push_str(&format!("Parse error: {}\n", error.message));
|
||||||
|
|
||||||
|
// Print the line number and content
|
||||||
|
result.push_str(&format!("{} | {}\n", line_idx + 1, line));
|
||||||
|
|
||||||
|
// Calculate column positions within the line
|
||||||
|
let line_start_col = error.span.start.saturating_sub(line_start);
|
||||||
|
let line_end_col = (error.span.end - line_start).min(line.len());
|
||||||
|
|
||||||
|
// Print spaces and squiggly line for the span
|
||||||
|
result.push_str(&format!("{} | ", " ".repeat((line_idx + 1).to_string().len())));
|
||||||
|
for _ in 0..line_start_col {
|
||||||
|
result.push(' ');
|
||||||
|
}
|
||||||
|
for _ in line_start_col..line_end_col {
|
||||||
|
result.push('~');
|
||||||
|
}
|
||||||
|
result.push('\n');
|
||||||
|
|
||||||
|
// Print caret at the start position
|
||||||
|
result.push_str(&format!("{} | ", " ".repeat((line_idx + 1).to_string().len())));
|
||||||
|
for _ in 0..line_start_col {
|
||||||
|
result.push(' ');
|
||||||
|
}
|
||||||
|
result.push('^');
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_pos = line_end + 1; // +1 for the newline character
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback if we can't find the line
|
||||||
|
format!("Parse error: {} (at byte {})", error.message, error.span.start)
|
||||||
|
}
|
||||||
|
|
||||||
fn run_file(filename: &str) -> Result<(), String> {
|
fn run_file(filename: &str) -> Result<(), String> {
|
||||||
// Read the source file
|
// Read the source file
|
||||||
let source = fs::read_to_string(filename)
|
let source = fs::read_to_string(filename)
|
||||||
|
|
@ -69,7 +120,7 @@ fn run_file(filename: &str) -> Result<(), String> {
|
||||||
let mut parser = Parser::new(filename.to_string(), tokens);
|
let mut parser = Parser::new(filename.to_string(), tokens);
|
||||||
let ast_nodes = parser
|
let ast_nodes = parser
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|e| format!("Parse error: {}", e.message))?;
|
.map_err(|e| format_parse_error(&source, &e))?;
|
||||||
|
|
||||||
println!("Parsed {} AST nodes successfully", ast_nodes.len());
|
println!("Parsed {} AST nodes successfully", ast_nodes.len());
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue