Compare commits
No commits in common. "dde1da8656ac70a9d577bfd7335b31114d606b37" and "872c8e356db86c9a3ee374b55eec58953ee56a9d" have entirely different histories.
dde1da8656
...
872c8e356d
12 changed files with 79 additions and 620 deletions
|
|
@ -1,22 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
# Bracket and parenthesis mismatch errors
|
|
||||||
|
|
||||||
# Missing closing parenthesis in function call
|
|
||||||
fn test() -> int do
|
|
||||||
let f = lambda(x) x
|
|
||||||
f(5
|
|
||||||
42
|
|
||||||
end
|
|
||||||
|
|
||||||
# Missing closing bracket in array access
|
|
||||||
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 do
|
|
||||||
let p = Point { x: 5, y: 10
|
|
||||||
p.x
|
|
||||||
end
|
|
||||||
|
|
||||||
# Missing closing parenthesis in tuple
|
|
||||||
fn test() -> int do
|
|
||||||
let t = (1, 2, 3
|
|
||||||
42
|
|
||||||
end
|
|
||||||
|
|
||||||
# Missing closing angle bracket in generic
|
|
||||||
fn test() -> int do
|
|
||||||
let v = Vec<int
|
|
||||||
42
|
|
||||||
end
|
|
||||||
|
|
||||||
# Extra closing parenthesis
|
|
||||||
fn test() -> int do
|
|
||||||
let x = (5))
|
|
||||||
x
|
|
||||||
end
|
|
||||||
|
|
||||||
# Missing opening parenthesis in expression
|
|
||||||
fn test() -> int do
|
|
||||||
let x = 5 + 3)
|
|
||||||
x
|
|
||||||
end
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
||||||
# Missing 'in' keyword in for loop
|
|
||||||
fn test() -> int
|
|
||||||
for item [1, 2, 3]
|
|
||||||
item
|
|
||||||
|
|
||||||
# Missing iterable in for loop
|
|
||||||
fn test() -> int
|
|
||||||
for item in
|
|
||||||
item
|
|
||||||
|
|
||||||
# Invalid while syntax
|
|
||||||
fn test() -> int
|
|
||||||
while
|
|
||||||
42
|
|
||||||
|
|
||||||
# Missing parameters in lambda
|
|
||||||
fn test() -> int
|
|
||||||
let f = lambda
|
|
||||||
42
|
|
||||||
|
|
||||||
# Missing closing parenthesis in lambda
|
|
||||||
fn test() -> int
|
|
||||||
let f = lambda(x
|
|
||||||
x
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
# 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
|
|
||||||
x => x
|
|
||||||
end
|
|
||||||
|
|
||||||
# Missing colon in struct pattern
|
|
||||||
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 do
|
|
||||||
let r = Result::Ok(42)
|
|
||||||
match r
|
|
||||||
Result::Ok value => value
|
|
||||||
end
|
|
||||||
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
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
# 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
|
|
||||||
53
src/main.rs
53
src/main.rs
|
|
@ -44,57 +44,6 @@ 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)
|
||||||
|
|
@ -120,7 +69,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(&source, &e))?;
|
.map_err(|e| format!("Parse error: {}", e.message))?;
|
||||||
|
|
||||||
println!("Parsed {} AST nodes successfully", ast_nodes.len());
|
println!("Parsed {} AST nodes successfully", ast_nodes.len());
|
||||||
|
|
||||||
|
|
|
||||||
348
src/parser.rs
348
src/parser.rs
|
|
@ -57,52 +57,16 @@ impl Parser {
|
||||||
Ok(span)
|
Ok(span)
|
||||||
}
|
}
|
||||||
Some((token, span)) => Err(ParseError {
|
Some((token, span)) => Err(ParseError {
|
||||||
message: self.expect_error_message(&expected, &token),
|
message: format!("Expected {:?}, found {:?}", expected, token),
|
||||||
span: Span::new(&span, self.file.clone()),
|
span: Span::new(&span, self.file.clone()),
|
||||||
}),
|
}),
|
||||||
None => Err(ParseError {
|
None => Err(ParseError {
|
||||||
message: self.expect_error_message(&expected, &Token::Variable("EOF".to_string())),
|
message: format!("Expected {:?}, found EOF", expected),
|
||||||
span: Span::new(&(0..0), self.file.clone()),
|
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> {
|
fn error<T>(&self, msg: String, span: Range<usize>) -> Result<T, ParseError> {
|
||||||
Err(ParseError {
|
Err(ParseError {
|
||||||
message: msg,
|
message: msg,
|
||||||
|
|
@ -126,10 +90,10 @@ impl Parser {
|
||||||
let path = match self.next() {
|
let path = match self.next() {
|
||||||
Some((Token::String(s), _)) => s,
|
Some((Token::String(s), _)) => s,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => {
|
||||||
return self.error("Expected library path after 'use'. Example: use \"std/io\"".to_string(), span);
|
return self.error("Expected string after 'use'".to_string(), span);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return self.error("Expected library path after 'use'. Example: use \"std/io\"".to_string(), start..start);
|
return self.error("Expected string after 'use'".to_string(), start..start);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let end = self.peek_span().unwrap_or(start..start).end;
|
let end = self.peek_span().unwrap_or(start..start).end;
|
||||||
|
|
@ -211,9 +175,9 @@ impl Parser {
|
||||||
}
|
}
|
||||||
Some(token) => {
|
Some(token) => {
|
||||||
let span = self.peek_span().unwrap_or(start..start);
|
let span = self.peek_span().unwrap_or(start..start);
|
||||||
self.error(format!("Unexpected token at top level: {:?}. Expected declarations like 'fn', 'struct', 'enum', 'impl', 'trait', 'use', 'load', or 'extern'", token), span)
|
self.error(format!("Unexpected token at top level: {:?}", token), span)
|
||||||
}
|
}
|
||||||
None => self.error("Unexpected end of file at top level. Expected declarations like 'fn', 'struct', 'enum', etc.".to_string(), start..start),
|
None => self.error("Unexpected EOF".to_string(), start..start),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,18 +186,8 @@ impl Parser {
|
||||||
let start = self.peek_span().unwrap_or(0..0).start;
|
let start = self.peek_span().unwrap_or(0..0).start;
|
||||||
let name = match self.next() {
|
let name = match self.next() {
|
||||||
Some((Token::Variable(name), _)) => name,
|
Some((Token::Variable(name), _)) => name,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => return self.error("Expected attribute name".to_string(), span),
|
||||||
return self.error(
|
None => return self.error("Expected attribute name".to_string(), start..start),
|
||||||
"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
|
// Parentheses are optional
|
||||||
|
|
@ -261,11 +215,11 @@ impl Parser {
|
||||||
args.push(AttributeArg::KeyValue(id, val))
|
args.push(AttributeArg::KeyValue(id, val))
|
||||||
}
|
}
|
||||||
Some((_, span)) => {
|
Some((_, span)) => {
|
||||||
return self.error("Expected attribute value after '='. Example: @version = \"1.0\"".to_string(), span);
|
return self.error("Expected value after =".to_string(), span);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return self
|
return self
|
||||||
.error("Expected attribute value after '='. Example: @version = \"1.0\"".to_string(), start..start);
|
.error("Expected value after =".to_string(), start..start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -278,7 +232,7 @@ impl Parser {
|
||||||
.error(format!("Unexpected token in attribute: {:?}", token), span);
|
.error(format!("Unexpected token in attribute: {:?}", token), span);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return self.error("Expected attribute argument. Examples: \"value\", key = \"value\", or just key".to_string(), start..start);
|
return self.error("Expected attribute argument".to_string(), start..start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let next_token = self.peek().cloned();
|
let next_token = self.peek().cloned();
|
||||||
|
|
@ -289,7 +243,7 @@ impl Parser {
|
||||||
} else {
|
} else {
|
||||||
{
|
{
|
||||||
let span = self.peek_span().unwrap_or(start..start);
|
let span = self.peek_span().unwrap_or(start..start);
|
||||||
return self.error("Expected ',' to separate arguments or ')' to close attribute. Example: @deprecated(\"old\", reason = \"use new\")".to_string(), span);
|
return self.error("Expected , or )".to_string(), span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -306,8 +260,8 @@ impl Parser {
|
||||||
let start = self.peek_span().unwrap_or(0..0).start;
|
let start = self.peek_span().unwrap_or(0..0).start;
|
||||||
let name = match self.next() {
|
let name = match self.next() {
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((_, span)) => return self.error("Expected function name after 'fn' keyword. Example: fn add(x: int, y: int) -> int x + y".to_string(), span),
|
Some((_, span)) => return self.error("Expected function name".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),
|
None => return self.error("Expected function name".to_string(), start..start),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse type parameters if present
|
// Parse type parameters if present
|
||||||
|
|
@ -329,20 +283,8 @@ impl Parser {
|
||||||
|
|
||||||
let arg_name = match self.next() {
|
let arg_name = match self.next() {
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => return self.error("Expected argument name".to_string(), span),
|
||||||
return self.error(
|
None => return self.error("Expected argument name".to_string(), start..start),
|
||||||
"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)) {
|
let arg_type = if matches!(self.peek(), Some(Token::Colon)) {
|
||||||
|
|
@ -358,7 +300,7 @@ impl Parser {
|
||||||
self.next();
|
self.next();
|
||||||
} else if !matches!(self.peek(), Some(Token::RParen)) {
|
} else if !matches!(self.peek(), Some(Token::RParen)) {
|
||||||
let span = self.peek_span().unwrap_or(start..start);
|
let span = self.peek_span().unwrap_or(start..start);
|
||||||
return self.error("Expected ',' between arguments or ')' to close parameter list. Example: fn add(x: int, y: int)".to_string(), span);
|
return self.error("Expected , or )".to_string(), span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -386,8 +328,8 @@ impl Parser {
|
||||||
let start = self.peek_span().unwrap_or(0..0).start;
|
let start = self.peek_span().unwrap_or(0..0).start;
|
||||||
let name = match self.next() {
|
let name = match self.next() {
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((_, span)) => return self.error("Expected struct name after 'struct' keyword. Example: struct Point { x: int, y: int }".to_string(), span),
|
Some((_, span)) => return self.error("Expected struct name".to_string(), span),
|
||||||
None => return self.error("Expected struct name after 'struct' keyword. Example: struct Point { x: int, y: int }".to_string(), start..start),
|
None => return self.error("Expected struct name".to_string(), start..start),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse type parameters if present
|
// Parse type parameters if present
|
||||||
|
|
@ -409,18 +351,8 @@ impl Parser {
|
||||||
let field_start = self.peek_span().unwrap_or(0..0).start;
|
let field_start = self.peek_span().unwrap_or(0..0).start;
|
||||||
let field_name = match self.next() {
|
let field_name = match self.next() {
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => return self.error("Expected field name".to_string(), span),
|
||||||
return self.error(
|
None => return self.error("Expected field name".to_string(), start..start),
|
||||||
"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)?;
|
self.expect(Token::Colon)?;
|
||||||
|
|
@ -449,16 +381,8 @@ impl Parser {
|
||||||
let start = self.peek_span().unwrap_or(0..0).start;
|
let start = self.peek_span().unwrap_or(0..0).start;
|
||||||
let name = match self.next() {
|
let name = match self.next() {
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((_, span)) => return self.error(
|
Some((_, span)) => return self.error("Expected enum name".to_string(), span),
|
||||||
"Expected enum name after 'enum' keyword. Example: enum Color { Red(int), Green(int), Blue(int) }"
|
None => return self.error("Expected enum name".to_string(), start..start),
|
||||||
.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
|
// Parse type parameters if present
|
||||||
|
|
@ -480,20 +404,8 @@ impl Parser {
|
||||||
let variant_start = self.peek_span().unwrap_or(0..0).start;
|
let variant_start = self.peek_span().unwrap_or(0..0).start;
|
||||||
let variant_name = match self.next() {
|
let variant_name = match self.next() {
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => return self.error("Expected variant name".to_string(), span),
|
||||||
return self.error(
|
None => return self.error("Expected variant name".to_string(), start..start),
|
||||||
"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();
|
let mut fields = Vec::new();
|
||||||
|
|
@ -546,32 +458,23 @@ impl Parser {
|
||||||
TypeAnnot::Cons(name, _) => name,
|
TypeAnnot::Cons(name, _) => name,
|
||||||
_ => {
|
_ => {
|
||||||
return self.error(
|
return self.error(
|
||||||
"Expected type name for impl target. Example: impl MyType { ... }".to_string(),
|
"Expected type name for impl target".to_string(),
|
||||||
start..start,
|
start..start,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse optional trait name
|
// Parse optional trait name
|
||||||
let trait_name =
|
let trait_name = if matches!(self.peek(), Some(Token::Colon)) {
|
||||||
if matches!(self.peek(), Some(Token::Colon)) {
|
self.next();
|
||||||
self.next();
|
match self.next() {
|
||||||
match self.next() {
|
Some((Token::Variable(n), _)) => Some(n),
|
||||||
Some((Token::Variable(n), _)) => Some(n),
|
Some((_, span)) => return self.error("Expected trait name".to_string(), span),
|
||||||
Some((_, span)) => return self.error(
|
None => return self.error("Expected trait name".to_string(), start..start),
|
||||||
"Expected trait name after colon. Example: impl MyType : MyTrait { ... }"
|
}
|
||||||
.to_string(),
|
} else {
|
||||||
span,
|
None
|
||||||
),
|
};
|
||||||
None => return self.error(
|
|
||||||
"Expected trait name after colon. Example: impl MyType : MyTrait { ... }"
|
|
||||||
.to_string(),
|
|
||||||
start..start,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse methods
|
// Parse methods
|
||||||
let mut methods = Vec::new();
|
let mut methods = Vec::new();
|
||||||
|
|
@ -596,8 +499,8 @@ impl Parser {
|
||||||
let start = self.peek_span().unwrap_or(0..0).start;
|
let start = self.peek_span().unwrap_or(0..0).start;
|
||||||
let name = match self.next() {
|
let name = match self.next() {
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((_, span)) => return self.error("Expected trait name after 'trait' keyword. Example: trait Display { fn to_string() -> string; }".to_string(), span),
|
Some((_, span)) => return self.error("Expected trait name".to_string(), span),
|
||||||
None => return self.error("Expected trait name after 'trait' keyword. Example: trait Display { fn to_string() -> string; }".to_string(), start..start),
|
None => return self.error("Expected trait name".to_string(), start..start),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse type parameters if present
|
// Parse type parameters if present
|
||||||
|
|
@ -642,18 +545,8 @@ impl Parser {
|
||||||
let start = self.peek_span().unwrap_or(0..0).start;
|
let start = self.peek_span().unwrap_or(0..0).start;
|
||||||
let name = match self.next() {
|
let name = match self.next() {
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => return self.error("Expected extern name".to_string(), span),
|
||||||
return self.error(
|
None => return self.error("Expected extern name".to_string(), start..start),
|
||||||
"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)
|
// Parse argument types (with optional parameter names)
|
||||||
|
|
@ -680,16 +573,8 @@ impl Parser {
|
||||||
self.expect(Token::KeywordFrom)?;
|
self.expect(Token::KeywordFrom)?;
|
||||||
let from = match self.next() {
|
let from = match self.next() {
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((_, span)) => return self.error(
|
Some((_, span)) => return self.error("Expected library identifier".to_string(), span),
|
||||||
"Expected library name after 'from'. Example: extern add() -> int from \"libc\""
|
None => return self.error("Expected library identifier".to_string(), start..start),
|
||||||
.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;
|
let end = self.peek_span().unwrap_or(start..start).end;
|
||||||
|
|
@ -706,37 +591,15 @@ impl Parser {
|
||||||
let start = self.peek_span().unwrap_or(0..0).start;
|
let start = self.peek_span().unwrap_or(0..0).start;
|
||||||
let library = match self.next() {
|
let library = match self.next() {
|
||||||
Some((Token::String(s), _)) => s,
|
Some((Token::String(s), _)) => s,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => return self.error("Expected library name".to_string(), span),
|
||||||
return self.error(
|
None => return self.error("Expected library name".to_string(), start..start),
|
||||||
"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)?;
|
self.expect(Token::KeywordAs)?;
|
||||||
let alias = match self.next() {
|
let alias = match self.next() {
|
||||||
Some((Token::Variable(a), _)) => a,
|
Some((Token::Variable(a), _)) => a,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => return self.error("Expected alias".to_string(), span),
|
||||||
return self.error(
|
None => return self.error("Expected alias".to_string(), start..start),
|
||||||
"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;
|
let end = self.peek_span().unwrap_or(start..start).end;
|
||||||
|
|
@ -760,18 +623,8 @@ impl Parser {
|
||||||
let param_start = self.peek_span().unwrap_or(0..0).start;
|
let param_start = self.peek_span().unwrap_or(0..0).start;
|
||||||
let param_name = match self.next() {
|
let param_name = match self.next() {
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => return self.error("Expected parameter name".to_string(), span),
|
||||||
return self.error(
|
None => return self.error("Expected parameter name".to_string(), start..start),
|
||||||
"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)) {
|
let bounds = if matches!(self.peek(), Some(Token::Colon)) {
|
||||||
|
|
@ -809,18 +662,8 @@ impl Parser {
|
||||||
loop {
|
loop {
|
||||||
match self.next() {
|
match self.next() {
|
||||||
Some((Token::Variable(n), _)) => bounds.push(n),
|
Some((Token::Variable(n), _)) => bounds.push(n),
|
||||||
Some((_, span)) => {
|
Some((_, span)) => return self.error("Expected trait name".to_string(), span),
|
||||||
return self.error(
|
None => return self.error("Expected trait name".to_string(), 0..0),
|
||||||
"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)) {
|
if !matches!(self.peek(), Some(Token::Plus)) {
|
||||||
|
|
@ -916,20 +759,8 @@ impl Parser {
|
||||||
TypeAnnot::Array(Box::new(inner))
|
TypeAnnot::Array(Box::new(inner))
|
||||||
}
|
}
|
||||||
Some((Token::Bang, _)) => TypeAnnot::Cons("never".to_string(), vec![]),
|
Some((Token::Bang, _)) => TypeAnnot::Cons("never".to_string(), vec![]),
|
||||||
Some((_, span)) => {
|
Some((_, span)) => return self.error("Expected type name".to_string(), span),
|
||||||
return self.error(
|
None => return self.error("Expected type name".to_string(), start..start),
|
||||||
"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
|
// Parse type arguments if present
|
||||||
|
|
@ -950,11 +781,7 @@ impl Parser {
|
||||||
base_type = match base_type {
|
base_type = match base_type {
|
||||||
TypeAnnot::Cons(name, _) => TypeAnnot::Cons(name, args),
|
TypeAnnot::Cons(name, _) => TypeAnnot::Cons(name, args),
|
||||||
_ => {
|
_ => {
|
||||||
return self.error(
|
return self.error("Expected type name for generic".to_string(), start..start);
|
||||||
"Expected type name for generic. Example: Vec<int>, HashMap<string, int>"
|
|
||||||
.to_string(),
|
|
||||||
start..start,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -973,20 +800,8 @@ impl Parser {
|
||||||
let start = self.peek_span().unwrap_or(0..0).start;
|
let start = self.peek_span().unwrap_or(0..0).start;
|
||||||
let name = match self.next() {
|
let name = match self.next() {
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => return self.error("Expected function name".to_string(), span),
|
||||||
return self.error(
|
None => return self.error("Expected function name".to_string(), start..start),
|
||||||
"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)?;
|
self.expect(Token::LParen)?;
|
||||||
|
|
@ -998,20 +813,11 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
let param_start = self.peek_span().unwrap_or(0..0).start;
|
let param_start = self.peek_span().unwrap_or(0..0).start;
|
||||||
let param_name =
|
let param_name = match self.next() {
|
||||||
match self.next() {
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((_, span)) => return self.error("Expected parameter name".to_string(), span),
|
||||||
Some((_, span)) => return self.error(
|
None => return self.error("Expected parameter name".to_string(), start..start),
|
||||||
"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
|
// Parameters in trait methods may have type annotations
|
||||||
if matches!(self.peek(), Some(Token::Colon)) {
|
if matches!(self.peek(), Some(Token::Colon)) {
|
||||||
|
|
@ -1325,7 +1131,7 @@ impl Parser {
|
||||||
let field = match self.next() {
|
let field = match self.next() {
|
||||||
Some((Token::Variable(f), _)) => f,
|
Some((Token::Variable(f), _)) => f,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => {
|
||||||
return self.error("Expected field name in struct pattern. Example: Point { x: 5, y: 10 }".to_string(), span);
|
return self.error("Expected field name".to_string(), span);
|
||||||
}
|
}
|
||||||
None => return self.error("Expected field name".to_string(), start..start),
|
None => return self.error("Expected field name".to_string(), start..start),
|
||||||
};
|
};
|
||||||
|
|
@ -1343,7 +1149,7 @@ impl Parser {
|
||||||
let field = match self.next() {
|
let field = match self.next() {
|
||||||
Some((Token::Variable(f), _)) => f,
|
Some((Token::Variable(f), _)) => f,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => {
|
||||||
return self.error("Expected field name in struct pattern. Example: Point { x: 5, y: 10 }".to_string(), span);
|
return self.error("Expected field name".to_string(), span);
|
||||||
}
|
}
|
||||||
None => return self.error("Expected field name".to_string(), start..start),
|
None => return self.error("Expected field name".to_string(), start..start),
|
||||||
};
|
};
|
||||||
|
|
@ -1440,7 +1246,7 @@ impl Parser {
|
||||||
let field_name = match self.next() {
|
let field_name = match self.next() {
|
||||||
Some((Token::Variable(f), _)) => f,
|
Some((Token::Variable(f), _)) => f,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => {
|
||||||
return self.error("Expected field name in struct pattern. Example: Point { x: 5, y: 10 }".to_string(), span);
|
return self.error("Expected field name".to_string(), span);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return self.error("Expected field name".to_string(), start..start);
|
return self.error("Expected field name".to_string(), start..start);
|
||||||
|
|
@ -1468,7 +1274,7 @@ impl Parser {
|
||||||
let variant = match self.next() {
|
let variant = match self.next() {
|
||||||
Some((Token::Variable(v), _)) => v,
|
Some((Token::Variable(v), _)) => v,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => {
|
||||||
return self.error("Expected variant name in enum pattern. Example: Result::Ok(value) or Color::Red()".to_string(), span);
|
return self.error("Expected variant name".to_string(), span);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return self.error("Expected variant name".to_string(), start..start);
|
return self.error("Expected variant name".to_string(), start..start);
|
||||||
|
|
@ -1597,9 +1403,9 @@ impl Parser {
|
||||||
let var_name = match self.next() {
|
let var_name = match self.next() {
|
||||||
Some((Token::Variable(n), _)) => n,
|
Some((Token::Variable(n), _)) => n,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => {
|
||||||
return self.error("Expected variable name after 'let'. Example: let x = 5; or let mut y = 10;".to_string(), span);
|
return self.error("Expected variable name".to_string(), span);
|
||||||
}
|
}
|
||||||
None => return self.error("Expected variable name after 'let'. Example: let x = 5; or let mut y = 10;".to_string(), start..start),
|
None => return self.error("Expected variable name".to_string(), start..start),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse optional type annotation
|
// Parse optional type annotation
|
||||||
|
|
@ -1686,7 +1492,7 @@ impl Parser {
|
||||||
let var = match self.next() {
|
let var = match self.next() {
|
||||||
Some((Token::Variable(v), _)) => v,
|
Some((Token::Variable(v), _)) => v,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => {
|
||||||
return self.error("Expected variable name in for loop. Example: for item in collection { ... }".to_string(), span);
|
return self.error("Expected variable name".to_string(), span);
|
||||||
}
|
}
|
||||||
None => return self.error("Expected variable name".to_string(), start..start),
|
None => return self.error("Expected variable name".to_string(), start..start),
|
||||||
};
|
};
|
||||||
|
|
@ -1739,7 +1545,7 @@ impl Parser {
|
||||||
let param_name = match self.next() {
|
let param_name = match self.next() {
|
||||||
Some((Token::Variable(p), _)) => p,
|
Some((Token::Variable(p), _)) => p,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => {
|
||||||
return self.error("Expected parameter name in lambda. Example: lambda(x, y) { x + y }".to_string(), span);
|
return self.error("Expected parameter name".to_string(), span);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return self.error("Expected parameter name".to_string(), start..start);
|
return self.error("Expected parameter name".to_string(), start..start);
|
||||||
|
|
@ -1809,12 +1615,9 @@ impl Parser {
|
||||||
}
|
}
|
||||||
Some(token) => {
|
Some(token) => {
|
||||||
let span = self.peek_span().unwrap_or(start..start);
|
let span = self.peek_span().unwrap_or(start..start);
|
||||||
self.error(format!("Unexpected token in pattern: {:?}. Expected variable names, struct patterns like Struct {{ field }}, or enum patterns like Enum::Variant", token), span)
|
self.error(format!("Unexpected token: {:?}", token), span)
|
||||||
}
|
}
|
||||||
None => self.error(
|
None => self.error("Unexpected EOF".to_string(), start..start),
|
||||||
"Unexpected end of file in pattern. Expected a complete pattern.".to_string(),
|
|
||||||
start..start,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1841,7 +1644,7 @@ impl Parser {
|
||||||
let field_name = match self.next() {
|
let field_name = match self.next() {
|
||||||
Some((Token::Variable(f), _)) => f,
|
Some((Token::Variable(f), _)) => f,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => {
|
||||||
return self.error("Expected field name in struct pattern. Example: Point { x: 5, y: 10 }".to_string(), span);
|
return self.error("Expected field name".to_string(), span);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return self.error("Expected field name".to_string(), start..start);
|
return self.error("Expected field name".to_string(), start..start);
|
||||||
|
|
@ -1868,7 +1671,7 @@ impl Parser {
|
||||||
let variant = match self.next() {
|
let variant = match self.next() {
|
||||||
Some((Token::Variable(v), _)) => v,
|
Some((Token::Variable(v), _)) => v,
|
||||||
Some((_, span)) => {
|
Some((_, span)) => {
|
||||||
return self.error("Expected variant name in enum pattern. Example: Result::Ok(value) or Color::Red()".to_string(), span);
|
return self.error("Expected variant name".to_string(), span);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return self.error("Expected variant name".to_string(), start..start);
|
return self.error("Expected variant name".to_string(), start..start);
|
||||||
|
|
@ -1966,12 +1769,9 @@ impl Parser {
|
||||||
}
|
}
|
||||||
Some(token) => {
|
Some(token) => {
|
||||||
let span = self.peek_span().unwrap_or(start..start);
|
let span = self.peek_span().unwrap_or(start..start);
|
||||||
self.error(format!("Unexpected token in expression: {:?}. Expected literals, variables, or keywords like 'let', 'if', etc.", token), span)
|
self.error(format!("Unexpected token in pattern: {:?}", token), span)
|
||||||
}
|
}
|
||||||
None => self.error(
|
None => self.error("Unexpected EOF".to_string(), start..start),
|
||||||
"Unexpected end of file in expression. Expected a complete expression.".to_string(),
|
|
||||||
start..start,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1629,7 +1629,9 @@ impl TypeChecker {
|
||||||
TypeAnnot::Array(inner) => {
|
TypeAnnot::Array(inner) => {
|
||||||
Type::Array(Box::new(self.substitute_type(inner, subst_map)))
|
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) => {
|
TypeAnnot::Tuple(types) => {
|
||||||
let substituted_types: Vec<Type> = types
|
let substituted_types: Vec<Type> = types
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,7 @@
|
||||||
fn test_scoping() -> int do
|
fn test_scoping() -> int do
|
||||||
let x = 5
|
let x = 5
|
||||||
let f = lambda (y) y + 1 # simple lambda
|
let f = lambda (y) y + 1 # simple lambda
|
||||||
# f = lambda (z) z+1
|
f = lambda (z) z+1
|
||||||
let x = 10 # shadow x
|
let x = 10 # shadow x
|
||||||
f(3) # should work
|
f(3) # should work
|
||||||
end
|
end
|
||||||
|
|
||||||
fn stuff(f: fn(int, int) -> int, v: int) -> int do
|
|
||||||
f(v, v)
|
|
||||||
end
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue