diff --git a/error_test/parser/attribute_errors.sui b/error_test/parser/attribute_errors.sui new file mode 100644 index 0000000..dddb682 --- /dev/null +++ b/error_test/parser/attribute_errors.sui @@ -0,0 +1,22 @@ +# Attribute errors + +# Missing attribute name +@ 42 + +# Invalid attribute argument +@deprecated invalid + +# Missing equals in key-value attribute +@version "1.0" + +# Missing closing parenthesis in attribute +@deprecated("old", reason = "new" + +# Invalid attribute syntax (missing value after =) +@version = + +# Attribute on invalid location +fn test() -> int + @inline + let x = 5 + x \ No newline at end of file diff --git a/error_test/parser/bracket_errors.sui b/error_test/parser/bracket_errors.sui new file mode 100644 index 0000000..35b03ac --- /dev/null +++ b/error_test/parser/bracket_errors.sui @@ -0,0 +1,47 @@ +# Bracket and parenthesis mismatch errors + +# Missing closing parenthesis in function call +fn test() -> int + let f = lambda(x) x + f(5 + 42 + +# Missing closing bracket in array access +fn test() -> int + let arr = [1, 2, 3] + arr[0 + 42 + +# Missing closing brace in struct literal +fn test() -> int + struct Point + x: int + y: int + end + let p = Point { x: 5, y: 10 + p.x + +# Missing closing parenthesis in tuple +fn test() -> int + let t = (1, 2, 3 + 42 + +# Missing closing angle bracket in generic +fn test() -> int + let v = Vec int + let x = (5)) + x + +# Mismatched brackets +fn test() -> int + let x = [1, 2, 3} + x[0] + +# Missing opening parenthesis in expression +fn test() -> int + let x = 5 + 3) + x \ No newline at end of file diff --git a/error_test/parser/control_flow_errors.sui b/error_test/parser/control_flow_errors.sui new file mode 100644 index 0000000..bae1a39 --- /dev/null +++ b/error_test/parser/control_flow_errors.sui @@ -0,0 +1,49 @@ +# Control flow errors + +# Missing condition in if +fn test() -> int + if + 42 + else + 0 + +# Missing body in if +fn test() -> int + if true + else + 0 + +# Missing variable in for loop +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 + while + 42 + +# Missing parameters in lambda +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 new file mode 100644 index 0000000..e7552cf --- /dev/null +++ b/error_test/parser/enum_errors.sui @@ -0,0 +1,29 @@ +# 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 new file mode 100644 index 0000000..caabd3a --- /dev/null +++ b/error_test/parser/expression_errors.sui @@ -0,0 +1,43 @@ +# 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/function_errors.sui b/error_test/parser/function_errors.sui new file mode 100644 index 0000000..9142456 --- /dev/null +++ b/error_test/parser/function_errors.sui @@ -0,0 +1,24 @@ +# Function syntax errors + +# Missing function name +fn -> int + 42 + +# Missing parameter type annotation +fn add(x, y: int) -> int + x + y + +# Missing comma in parameters +fn add(x: int y: int) -> int + x + y + +# Missing closing parenthesis +fn add(x: int, y: int -> int + x + y + +# Missing return type arrow +fn add(x: int, y: int) int + x + y + +# Invalid function body (missing expression) +fn test() -> int \ No newline at end of file diff --git a/error_test/parser/pattern_errors.sui b/error_test/parser/pattern_errors.sui new file mode 100644 index 0000000..3cd1e6b --- /dev/null +++ b/error_test/parser/pattern_errors.sui @@ -0,0 +1,41 @@ +# Pattern matching errors + +# Invalid pattern in match +fn test() -> int + match 42 + x => x + end + +# Missing colon in struct pattern +fn test() -> int + struct Point + x: int + y: int + end + let p = Point { x: 5, y: 10 } + match p + Point { x 5, y: 10 } => 1 + end + +# Invalid enum pattern +fn test() -> int + enum Result + Ok(int) + Err(string) + end + let r = Result::Ok(42) + match r + Result::Ok value => value + end + +# Missing pattern in match arm +fn test() -> int + match 42 + => 0 + end + +# Missing fat arrow in match arm +fn test() -> int + match 42 + x 0 + end \ No newline at end of file diff --git a/error_test/parser/struct_errors.sui b/error_test/parser/struct_errors.sui new file mode 100644 index 0000000..375f2ae --- /dev/null +++ b/error_test/parser/struct_errors.sui @@ -0,0 +1,30 @@ +# Struct syntax errors + +# Missing struct name +struct + x: int + y: int +end + +# Missing field type +struct Point + x + y: int +end + +# Missing colon in field +struct Point + x int + y: int +end + +# Missing end keyword +struct Point + x: int + y: int + +# Invalid field separator (semicolon instead of comma) +struct Point + x: int; + y: int +end \ No newline at end of file diff --git a/error_test/parser/top_level_errors.sui b/error_test/parser/top_level_errors.sui new file mode 100644 index 0000000..da67f81 --- /dev/null +++ b/error_test/parser/top_level_errors.sui @@ -0,0 +1,45 @@ +# Top-level declaration errors + +# Invalid top-level token +invalid_token + +# Incomplete use statement +use + +# Missing path in use +use as alias + +# Invalid use syntax +use "path" invalid + +# Incomplete load statement +load + +# Missing alias in load +load "lib" + +# Invalid load syntax +load "lib" invalid alias + +# Incomplete extern declaration +extern + +# Missing return type in extern +extern add(x: int, y: int) + +# Invalid extern syntax +extern add(x: int, y: int) -> int invalid + +# Incomplete impl declaration +impl + +# Missing methods in impl +impl MyType +end + +# Incomplete trait declaration +trait + +# Missing methods in trait +trait MyTrait +end \ No newline at end of file diff --git a/error_test/parser/type_errors.sui b/error_test/parser/type_errors.sui new file mode 100644 index 0000000..4612a06 --- /dev/null +++ b/error_test/parser/type_errors.sui @@ -0,0 +1,29 @@ +# Type annotation errors + +# Invalid type name +fn test() -> invalidtype + 42 + +# Missing closing bracket in array type +fn test() -> [int + [] + +# Missing type parameter +fn test() -> Option + none + +# Invalid generic syntax +fn test() -> Vec int + [] + +# Missing closing angle bracket +fn test() -> HashMap *int + 42 + +# Invalid function type syntax +fn test() -> fn int -> int + 42 \ No newline at end of file diff --git a/src/parser.rs b/src/parser.rs index db7026b..b5c67e4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -57,16 +57,52 @@ impl Parser { Ok(span) } Some((token, span)) => Err(ParseError { - message: format!("Expected {:?}, found {:?}", expected, token), + message: self.expect_error_message(&expected, &token), span: Span::new(&span, self.file.clone()), }), None => Err(ParseError { - message: format!("Expected {:?}, found EOF", expected), + message: self.expect_error_message(&expected, &Token::Variable("EOF".to_string())), span: Span::new(&(0..0), self.file.clone()), }), } } + fn expect_error_message(&self, expected: &Token, found: &Token) -> String { + match expected { + Token::LParen => format!( + "Expected '(' to start parameter list or grouping. Found {:?}", + found + ), + Token::RParen => format!( + "Expected ')' to close parameter list or grouping. Found {:?}", + found + ), + Token::LBrace => format!( + "Expected '{{' to start block or struct literal. Found {:?}", + found + ), + Token::RBrace => format!( + "Expected '}}' to close block or struct literal. Found {:?}", + found + ), + Token::LBracket => format!("Expected '[' to start array literal. Found {:?}", found), + Token::RBracket => format!("Expected ']' to close array literal. Found {:?}", found), + Token::Colon => format!( + "Expected ':' for type annotation or struct field. Found {:?}", + found + ), + Token::Semicolon => format!("Expected ';' to end statement. Found {:?}", found), + Token::Comma => format!("Expected ',' to separate items. Found {:?}", found), + Token::Arrow => format!("Expected '->' for function return type. Found {:?}", found), + Token::Assign => format!( + "Expected '=' for assignment or initialization. Found {:?}", + found + ), + Token::KeywordEnd => format!("Expected 'end' to close block. Found {:?}", found), + _ => format!("Expected {:?}, found {:?}", expected, found), + } + } + fn error(&self, msg: String, span: Range) -> Result { Err(ParseError { message: msg, @@ -90,10 +126,10 @@ impl Parser { let path = match self.next() { Some((Token::String(s), _)) => s, Some((_, span)) => { - return self.error("Expected string after 'use'".to_string(), span); + return self.error("Expected library path after 'use'. Example: use \"std/io\"".to_string(), span); } None => { - return self.error("Expected string after 'use'".to_string(), start..start); + return self.error("Expected library path after 'use'. Example: use \"std/io\"".to_string(), start..start); } }; let end = self.peek_span().unwrap_or(start..start).end; @@ -175,9 +211,9 @@ impl Parser { } Some(token) => { let span = self.peek_span().unwrap_or(start..start); - self.error(format!("Unexpected token at top level: {:?}", token), span) + self.error(format!("Unexpected token at top level: {:?}. Expected declarations like 'fn', 'struct', 'enum', 'impl', 'trait', 'use', 'load', or 'extern'", token), span) } - None => self.error("Unexpected EOF".to_string(), start..start), + None => self.error("Unexpected end of file at top level. Expected declarations like 'fn', 'struct', 'enum', etc.".to_string(), start..start), } } @@ -186,8 +222,18 @@ impl Parser { let start = self.peek_span().unwrap_or(0..0).start; let name = match self.next() { Some((Token::Variable(name), _)) => name, - Some((_, span)) => return self.error("Expected attribute name".to_string(), span), - None => return self.error("Expected attribute name".to_string(), start..start), + Some((_, span)) => { + return self.error( + "Expected attribute name after '@'. Example: @deprecated".to_string(), + span, + ); + } + None => { + return self.error( + "Expected attribute name after '@'. Example: @deprecated".to_string(), + start..start, + ); + } }; // Parentheses are optional @@ -215,11 +261,11 @@ impl Parser { args.push(AttributeArg::KeyValue(id, val)) } Some((_, span)) => { - return self.error("Expected value after =".to_string(), span); + return self.error("Expected attribute value after '='. Example: @version = \"1.0\"".to_string(), span); } None => { return self - .error("Expected value after =".to_string(), start..start); + .error("Expected attribute value after '='. Example: @version = \"1.0\"".to_string(), start..start); } } } else { @@ -232,7 +278,7 @@ impl Parser { .error(format!("Unexpected token in attribute: {:?}", token), span); } None => { - return self.error("Expected attribute argument".to_string(), start..start); + return self.error("Expected attribute argument. Examples: \"value\", key = \"value\", or just key".to_string(), start..start); } } let next_token = self.peek().cloned(); @@ -243,7 +289,7 @@ impl Parser { } else { { let span = self.peek_span().unwrap_or(start..start); - return self.error("Expected , or )".to_string(), span); + return self.error("Expected ',' to separate arguments or ')' to close attribute. Example: @deprecated(\"old\", reason = \"use new\")".to_string(), span); } } } @@ -260,8 +306,8 @@ impl Parser { let start = self.peek_span().unwrap_or(0..0).start; let name = match self.next() { Some((Token::Variable(n), _)) => n, - Some((_, span)) => return self.error("Expected function name".to_string(), span), - None => return self.error("Expected function name".to_string(), start..start), + Some((_, span)) => return self.error("Expected function name after 'fn' keyword. Example: fn add(x: int, y: int) -> int x + y".to_string(), span), + None => return self.error("Expected function name after 'fn' keyword. Example: fn add(x: int, y: int) -> int x + y ".to_string(), start..start), }; // Parse type parameters if present @@ -283,8 +329,20 @@ impl Parser { let arg_name = match self.next() { Some((Token::Variable(n), _)) => n, - Some((_, span)) => return self.error("Expected argument name".to_string(), span), - None => return self.error("Expected argument name".to_string(), start..start), + Some((_, span)) => { + return self.error( + "Expected argument name. Arguments should be like: x: int, y: int" + .to_string(), + span, + ); + } + None => { + return self.error( + "Expected argument name. Arguments should be like: x: int, y: int" + .to_string(), + start..start, + ); + } }; let arg_type = if matches!(self.peek(), Some(Token::Colon)) { @@ -300,7 +358,7 @@ impl Parser { self.next(); } else if !matches!(self.peek(), Some(Token::RParen)) { let span = self.peek_span().unwrap_or(start..start); - return self.error("Expected , or )".to_string(), span); + return self.error("Expected ',' between arguments or ')' to close parameter list. Example: fn add(x: int, y: int)".to_string(), span); } } @@ -328,8 +386,8 @@ impl Parser { let start = self.peek_span().unwrap_or(0..0).start; let name = match self.next() { Some((Token::Variable(n), _)) => n, - Some((_, span)) => return self.error("Expected struct name".to_string(), span), - None => return self.error("Expected struct name".to_string(), start..start), + Some((_, span)) => return self.error("Expected struct name after 'struct' keyword. Example: struct Point { x: int, y: int }".to_string(), span), + None => return self.error("Expected struct name after 'struct' keyword. Example: struct Point { x: int, y: int }".to_string(), start..start), }; // Parse type parameters if present @@ -351,8 +409,18 @@ impl Parser { let field_start = self.peek_span().unwrap_or(0..0).start; let field_name = match self.next() { Some((Token::Variable(n), _)) => n, - Some((_, span)) => return self.error("Expected field name".to_string(), span), - None => return self.error("Expected field name".to_string(), start..start), + Some((_, span)) => { + return self.error( + "Expected field name. Fields should be like: name: string,".to_string(), + span, + ); + } + None => { + return self.error( + "Expected field name. Fields should be like: name: string,".to_string(), + start..start, + ); + } }; self.expect(Token::Colon)?; @@ -381,8 +449,16 @@ impl Parser { let start = self.peek_span().unwrap_or(0..0).start; let name = match self.next() { Some((Token::Variable(n), _)) => n, - Some((_, span)) => return self.error("Expected enum name".to_string(), span), - None => return self.error("Expected enum name".to_string(), start..start), + Some((_, span)) => return self.error( + "Expected enum name after 'enum' keyword. Example: enum Color { Red(int), Green(int), Blue(int) }" + .to_string(), + span, + ), + None => return self.error( + "Expected enum name after 'enum' keyword. Example: enum Color { Red(int), Green(int), Blue(int) }" + .to_string(), + start..start, + ), }; // Parse type parameters if present @@ -404,8 +480,20 @@ impl Parser { let variant_start = self.peek_span().unwrap_or(0..0).start; let variant_name = match self.next() { Some((Token::Variable(n), _)) => n, - Some((_, span)) => return self.error("Expected variant name".to_string(), span), - None => return self.error("Expected variant name".to_string(), start..start), + Some((_, span)) => { + return self.error( + "Expected variant name. Variants should be like: Red, or Ok(T)," + .to_string(), + span, + ); + } + None => { + return self.error( + "Expected variant name. Variants should be like: Red, or Ok(T)," + .to_string(), + start..start, + ); + } }; let mut fields = Vec::new(); @@ -458,23 +546,32 @@ impl Parser { TypeAnnot::Cons(name, _) => name, _ => { return self.error( - "Expected type name for impl target".to_string(), + "Expected type name for impl target. Example: impl MyType { ... }".to_string(), start..start, ); } }; // Parse optional trait name - let trait_name = if matches!(self.peek(), Some(Token::Colon)) { - self.next(); - match self.next() { - Some((Token::Variable(n), _)) => Some(n), - Some((_, span)) => return self.error("Expected trait name".to_string(), span), - None => return self.error("Expected trait name".to_string(), start..start), - } - } else { - None - }; + let trait_name = + if matches!(self.peek(), Some(Token::Colon)) { + self.next(); + match self.next() { + Some((Token::Variable(n), _)) => Some(n), + Some((_, span)) => return self.error( + "Expected trait name after colon. Example: impl MyType : MyTrait { ... }" + .to_string(), + span, + ), + None => return self.error( + "Expected trait name after colon. Example: impl MyType : MyTrait { ... }" + .to_string(), + start..start, + ), + } + } else { + None + }; // Parse methods let mut methods = Vec::new(); @@ -499,8 +596,8 @@ impl Parser { let start = self.peek_span().unwrap_or(0..0).start; let name = match self.next() { Some((Token::Variable(n), _)) => n, - Some((_, span)) => return self.error("Expected trait name".to_string(), span), - None => return self.error("Expected trait name".to_string(), start..start), + Some((_, span)) => return self.error("Expected trait name after 'trait' keyword. Example: trait Display { fn to_string() -> string; }".to_string(), span), + None => return self.error("Expected trait name after 'trait' keyword. Example: trait Display { fn to_string() -> string; }".to_string(), start..start), }; // Parse type parameters if present @@ -545,8 +642,18 @@ impl Parser { let start = self.peek_span().unwrap_or(0..0).start; let name = match self.next() { Some((Token::Variable(n), _)) => n, - Some((_, span)) => return self.error("Expected extern name".to_string(), span), - None => return self.error("Expected extern name".to_string(), start..start), + Some((_, span)) => { + return self.error( + "Expected function name after 'extern'. Example: extern add".to_string(), + span, + ); + } + None => { + return self.error( + "Expected function name after 'extern'. Example: extern add".to_string(), + start..start, + ); + } }; // Parse argument types (with optional parameter names) @@ -573,8 +680,16 @@ impl Parser { self.expect(Token::KeywordFrom)?; let from = match self.next() { Some((Token::Variable(n), _)) => n, - Some((_, span)) => return self.error("Expected library identifier".to_string(), span), - None => return self.error("Expected library identifier".to_string(), start..start), + Some((_, span)) => return self.error( + "Expected library name after 'from'. Example: extern add() -> int from \"libc\"" + .to_string(), + span, + ), + None => return self.error( + "Expected library name after 'from'. Example: extern add() -> int from \"libc\"" + .to_string(), + start..start, + ), }; let end = self.peek_span().unwrap_or(start..start).end; @@ -591,15 +706,37 @@ impl Parser { let start = self.peek_span().unwrap_or(0..0).start; let library = match self.next() { Some((Token::String(s), _)) => s, - Some((_, span)) => return self.error("Expected library name".to_string(), span), - None => return self.error("Expected library name".to_string(), start..start), + Some((_, span)) => { + return self.error( + "Expected library name after 'load'. Example: load \"mylib\" as mylib" + .to_string(), + span, + ); + } + None => { + return self.error( + "Expected library name after 'load'. Example: load \"mylib\" as mylib" + .to_string(), + start..start, + ); + } }; self.expect(Token::KeywordAs)?; let alias = match self.next() { Some((Token::Variable(a), _)) => a, - Some((_, span)) => return self.error("Expected alias".to_string(), span), - None => return self.error("Expected alias".to_string(), start..start), + Some((_, span)) => { + return self.error( + "Expected alias after 'as'. Example: load \"mylib\" as mylib".to_string(), + span, + ); + } + None => { + return self.error( + "Expected alias after 'as'. Example: load \"mylib\" as mylib".to_string(), + start..start, + ); + } }; let end = self.peek_span().unwrap_or(start..start).end; @@ -623,8 +760,18 @@ impl Parser { let param_start = self.peek_span().unwrap_or(0..0).start; let param_name = match self.next() { Some((Token::Variable(n), _)) => n, - Some((_, span)) => return self.error("Expected parameter name".to_string(), span), - None => return self.error("Expected parameter name".to_string(), start..start), + Some((_, span)) => { + return self.error( + "Expected type parameter name. Example: ".to_string(), + span, + ); + } + None => { + return self.error( + "Expected type parameter name. Example: ".to_string(), + start..start, + ); + } }; let bounds = if matches!(self.peek(), Some(Token::Colon)) { @@ -662,8 +809,18 @@ impl Parser { loop { match self.next() { Some((Token::Variable(n), _)) => bounds.push(n), - Some((_, span)) => return self.error("Expected trait name".to_string(), span), - None => return self.error("Expected trait name".to_string(), 0..0), + Some((_, span)) => { + return self.error( + "Expected trait name in bounds. Example: T: Clone + Debug".to_string(), + span, + ); + } + None => { + return self.error( + "Expected trait name in bounds. Example: T: Clone + Debug".to_string(), + 0..0, + ); + } } if !matches!(self.peek(), Some(Token::Plus)) { @@ -759,8 +916,20 @@ impl Parser { TypeAnnot::Array(Box::new(inner)) } Some((Token::Bang, _)) => TypeAnnot::Cons("never".to_string(), vec![]), - Some((_, span)) => return self.error("Expected type name".to_string(), span), - None => return self.error("Expected type name".to_string(), start..start), + Some((_, span)) => { + return self.error( + "Expected type name. Examples: int, string, bool, MyStruct, Option" + .to_string(), + span, + ); + } + None => { + return self.error( + "Expected type name. Examples: int, string, bool, MyStruct, Option" + .to_string(), + start..start, + ); + } }; // Parse type arguments if present @@ -781,7 +950,11 @@ impl Parser { base_type = match base_type { TypeAnnot::Cons(name, _) => TypeAnnot::Cons(name, args), _ => { - return self.error("Expected type name for generic".to_string(), start..start); + return self.error( + "Expected type name for generic. Example: Vec, HashMap" + .to_string(), + start..start, + ); } }; } @@ -800,8 +973,20 @@ impl Parser { let start = self.peek_span().unwrap_or(0..0).start; let name = match self.next() { Some((Token::Variable(n), _)) => n, - Some((_, span)) => return self.error("Expected function name".to_string(), span), - None => return self.error("Expected function name".to_string(), start..start), + Some((_, span)) => { + return self.error( + "Expected function name in signature. Example: fn to_string() -> string" + .to_string(), + span, + ); + } + None => { + return self.error( + "Expected function name in signature. Example: fn to_string() -> string" + .to_string(), + start..start, + ); + } }; self.expect(Token::LParen)?; @@ -813,11 +998,20 @@ impl Parser { } let param_start = self.peek_span().unwrap_or(0..0).start; - let param_name = match self.next() { - Some((Token::Variable(n), _)) => n, - Some((_, span)) => return self.error("Expected parameter name".to_string(), span), - None => return self.error("Expected parameter name".to_string(), start..start), - }; + let param_name = + match self.next() { + Some((Token::Variable(n), _)) => n, + Some((_, span)) => return self.error( + "Expected parameter name in trait method. Example: fn method(self, x: int)" + .to_string(), + span, + ), + None => return self.error( + "Expected parameter name in trait method. Example: fn method(self, x: int)" + .to_string(), + start..start, + ), + }; // Parameters in trait methods may have type annotations if matches!(self.peek(), Some(Token::Colon)) { @@ -1131,7 +1325,7 @@ impl Parser { let field = match self.next() { Some((Token::Variable(f), _)) => f, Some((_, span)) => { - return self.error("Expected field name".to_string(), span); + return self.error("Expected field name in struct pattern. Example: Point { x: 5, y: 10 }".to_string(), span); } None => return self.error("Expected field name".to_string(), start..start), }; @@ -1149,7 +1343,7 @@ impl Parser { let field = match self.next() { Some((Token::Variable(f), _)) => f, Some((_, span)) => { - return self.error("Expected field name".to_string(), span); + return self.error("Expected field name in struct pattern. Example: Point { x: 5, y: 10 }".to_string(), span); } None => return self.error("Expected field name".to_string(), start..start), }; @@ -1246,7 +1440,7 @@ impl Parser { let field_name = match self.next() { Some((Token::Variable(f), _)) => f, Some((_, span)) => { - return self.error("Expected field name".to_string(), span); + return self.error("Expected field name in struct pattern. Example: Point { x: 5, y: 10 }".to_string(), span); } None => { return self.error("Expected field name".to_string(), start..start); @@ -1274,7 +1468,7 @@ impl Parser { let variant = match self.next() { Some((Token::Variable(v), _)) => v, Some((_, span)) => { - return self.error("Expected variant name".to_string(), span); + return self.error("Expected variant name in enum pattern. Example: Result::Ok(value) or Color::Red()".to_string(), span); } None => { return self.error("Expected variant name".to_string(), start..start); @@ -1403,9 +1597,9 @@ impl Parser { let var_name = match self.next() { Some((Token::Variable(n), _)) => n, Some((_, span)) => { - return self.error("Expected variable name".to_string(), span); + return self.error("Expected variable name after 'let'. Example: let x = 5; or let mut y = 10;".to_string(), span); } - None => return self.error("Expected variable name".to_string(), start..start), + None => return self.error("Expected variable name after 'let'. Example: let x = 5; or let mut y = 10;".to_string(), start..start), }; // Parse optional type annotation @@ -1492,7 +1686,7 @@ impl Parser { let var = match self.next() { Some((Token::Variable(v), _)) => v, Some((_, span)) => { - return self.error("Expected variable name".to_string(), span); + return self.error("Expected variable name in for loop. Example: for item in collection { ... }".to_string(), span); } None => return self.error("Expected variable name".to_string(), start..start), }; @@ -1545,7 +1739,7 @@ impl Parser { let param_name = match self.next() { Some((Token::Variable(p), _)) => p, Some((_, span)) => { - return self.error("Expected parameter name".to_string(), span); + return self.error("Expected parameter name in lambda. Example: lambda(x, y) { x + y }".to_string(), span); } None => { return self.error("Expected parameter name".to_string(), start..start); @@ -1615,9 +1809,12 @@ impl Parser { } Some(token) => { let span = self.peek_span().unwrap_or(start..start); - self.error(format!("Unexpected token: {:?}", token), span) + self.error(format!("Unexpected token in pattern: {:?}. Expected variable names, struct patterns like Struct {{ field }}, or enum patterns like Enum::Variant", token), span) } - None => self.error("Unexpected EOF".to_string(), start..start), + None => self.error( + "Unexpected end of file in pattern. Expected a complete pattern.".to_string(), + start..start, + ), } } @@ -1644,7 +1841,7 @@ impl Parser { let field_name = match self.next() { Some((Token::Variable(f), _)) => f, Some((_, span)) => { - return self.error("Expected field name".to_string(), span); + return self.error("Expected field name in struct pattern. Example: Point { x: 5, y: 10 }".to_string(), span); } None => { return self.error("Expected field name".to_string(), start..start); @@ -1671,7 +1868,7 @@ impl Parser { let variant = match self.next() { Some((Token::Variable(v), _)) => v, Some((_, span)) => { - return self.error("Expected variant name".to_string(), span); + return self.error("Expected variant name in enum pattern. Example: Result::Ok(value) or Color::Red()".to_string(), span); } None => { return self.error("Expected variant name".to_string(), start..start); @@ -1769,9 +1966,12 @@ impl Parser { } Some(token) => { let span = self.peek_span().unwrap_or(start..start); - self.error(format!("Unexpected token in pattern: {:?}", token), span) + self.error(format!("Unexpected token in expression: {:?}. Expected literals, variables, or keywords like 'let', 'if', etc.", token), span) } - None => self.error("Unexpected EOF".to_string(), start..start), + None => self.error( + "Unexpected end of file in expression. Expected a complete expression.".to_string(), + start..start, + ), } } diff --git a/src/typechecker.rs b/src/typechecker.rs index 26f904b..5c594ef 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -1629,9 +1629,7 @@ impl TypeChecker { TypeAnnot::Array(inner) => { Type::Array(Box::new(self.substitute_type(inner, subst_map))) } - TypeAnnot::Ptr(inner) => { - Type::Ptr(Box::new(self.substitute_type(inner, subst_map))) - } + TypeAnnot::Ptr(inner) => Type::Ptr(Box::new(self.substitute_type(inner, subst_map))), TypeAnnot::Tuple(types) => { let substituted_types: Vec = types .iter() diff --git a/test_scoping.sui b/test_scoping.sui index 6f3438f..f06fc52 100644 --- a/test_scoping.sui +++ b/test_scoping.sui @@ -1,7 +1,11 @@ fn test_scoping() -> int do let x = 5 let f = lambda (y) y + 1 # simple lambda - f = lambda (z) z+1 + # f = lambda (z) z+1 let x = 10 # shadow x f(3) # should work end + +fn stuff(f: fn(int, int) -> int, v: int) -> int do + f(v, v) +end