diff --git a/error_test/parser/bracket_errors.sui b/error_test/parser/bracket_errors.sui index 35b03ac..07f7a37 100644 --- a/error_test/parser/bracket_errors.sui +++ b/error_test/parser/bracket_errors.sui @@ -1,47 +1,50 @@ # Bracket and parenthesis mismatch errors # Missing closing parenthesis in function call -fn test() -> int +fn test() -> int do let f = lambda(x) x f(5 42 +end # Missing closing bracket in array access -fn test() -> int +fn test() -> int do let arr = [1, 2, 3] arr[0 42 +end + +struct Point + x: int, + y: int +end # Missing closing brace in struct literal -fn test() -> int - struct Point - x: int - y: int - end +fn test() -> int do let p = Point { x: 5, y: 10 p.x +end # Missing closing parenthesis in tuple -fn test() -> int +fn test() -> int do let t = (1, 2, 3 42 +end # Missing closing angle bracket in generic -fn test() -> int +fn test() -> int do let v = Vec int +fn test() -> int do let x = (5)) x - -# Mismatched brackets -fn test() -> int - let x = [1, 2, 3} - x[0] +end # Missing opening parenthesis in expression -fn test() -> int +fn test() -> int do let x = 5 + 3) - x \ No newline at end of file + x +end diff --git a/error_test/parser/control_flow_errors.sui b/error_test/parser/control_flow_errors.sui index bae1a39..3730643 100644 --- a/error_test/parser/control_flow_errors.sui +++ b/error_test/parser/control_flow_errors.sui @@ -17,19 +17,16 @@ fn test() -> int fn test() -> int for in [1, 2, 3] item - 0 # Missing 'in' keyword in for loop fn test() -> int for item [1, 2, 3] item - 0 # Missing iterable in for loop fn test() -> int for item in item - 0 # Invalid while syntax fn test() -> int @@ -40,10 +37,8 @@ fn test() -> int fn test() -> int let f = lambda 42 - f() # Missing closing parenthesis in lambda fn test() -> int let f = lambda(x x - f(5) \ No newline at end of file diff --git a/error_test/parser/enum_errors.sui b/error_test/parser/enum_errors.sui deleted file mode 100644 index e7552cf..0000000 --- a/error_test/parser/enum_errors.sui +++ /dev/null @@ -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 \ No newline at end of file diff --git a/error_test/parser/expression_errors.sui b/error_test/parser/expression_errors.sui deleted file mode 100644 index caabd3a..0000000 --- a/error_test/parser/expression_errors.sui +++ /dev/null @@ -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 \ No newline at end of file diff --git a/error_test/parser/pattern_errors.sui b/error_test/parser/pattern_errors.sui index 3cd1e6b..f152024 100644 --- a/error_test/parser/pattern_errors.sui +++ b/error_test/parser/pattern_errors.sui @@ -1,5 +1,14 @@ # Pattern matching errors +struct Point + x: int, + y: int, +end +enum Result + Ok(int) + Err(string) +end + # Invalid pattern in match fn test() -> int match 42 @@ -7,26 +16,20 @@ fn test() -> int end # Missing colon in struct pattern -fn test() -> int - struct Point - x: int - y: int - end - let p = Point { x: 5, y: 10 } +fn test() -> int do + let p = Point { x: 5, y: 10 } match p Point { x 5, y: 10 } => 1 end +end # Invalid enum pattern -fn test() -> int - enum Result - Ok(int) - Err(string) - end - let r = Result::Ok(42) +fn test() -> int do + let r = Result::Ok(42) match r Result::Ok value => value end +end # Missing pattern in match arm fn test() -> int @@ -38,4 +41,4 @@ fn test() -> int fn test() -> int match 42 x 0 - end \ No newline at end of file + end diff --git a/error_test/parser/struct_errors.sui b/error_test/parser/struct_errors.sui index 375f2ae..9a3f4d0 100644 --- a/error_test/parser/struct_errors.sui +++ b/error_test/parser/struct_errors.sui @@ -2,7 +2,7 @@ # Missing struct name struct - x: int + x: int, y: int end @@ -14,17 +14,17 @@ end # Missing colon in field struct Point - x int + x int, y: int end # Missing end keyword struct Point - x: int - y: int + x: int, + y: int, # Invalid field separator (semicolon instead of comma) struct Point x: int; y: int -end \ No newline at end of file +end diff --git a/src/main.rs b/src/main.rs index 67af040..3dc3ed4 100644 --- a/src/main.rs +++ b/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> { // Read the source file 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 ast_nodes = parser .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());