better parser errors

This commit is contained in:
Masashi 2025-12-15 21:18:25 +05:30
commit f83a8e3ca1
13 changed files with 639 additions and 78 deletions

View file

@ -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

View file

@ -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
42
# Extra closing parenthesis
fn test() -> 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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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<string, int
{}
# Invalid pointer syntax
fn test() -> *int
42
# Invalid function type syntax
fn test() -> fn int -> int
42

View file

@ -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<T>(&self, msg: String, span: Range<usize>) -> Result<T, ParseError> {
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: <T, U>".to_string(),
span,
);
}
None => {
return self.error(
"Expected type parameter name. Example: <T, U>".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<int>"
.to_string(),
span,
);
}
None => {
return self.error(
"Expected type name. Examples: int, string, bool, MyStruct, Option<int>"
.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<int>, HashMap<string, int>"
.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,
),
}
}

View file

@ -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<Type> = types
.iter()

View file

@ -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