suicmez/src/parser.rs
2025-12-15 13:53:57 +05:30

1763 lines
64 KiB
Rust

use crate::ast::*;
use crate::lexer::Token;
use std::iter::Peekable;
use std::ops::Range;
use std::vec::IntoIter;
type TokenIter = Peekable<IntoIter<(Token, Range<usize>)>>;
pub struct Parser {
pub file: String,
pub tokens: TokenIter,
}
#[derive(Debug)]
pub struct ParseError {
pub message: String,
pub span: Span,
}
impl Parser {
pub fn new(file: String, tokens: Vec<(Token, Range<usize>)>) -> Self {
Parser {
file,
tokens: tokens.into_iter().peekable(),
}
}
// Parse the entire file into a list of AST nodes
pub fn parse(&mut self) -> Result<Vec<ASTNode>, ParseError> {
let mut nodes = Vec::new();
while self.peek().is_some() {
nodes.push(self.parse_top_level()?);
}
Ok(nodes)
}
fn peek(&mut self) -> Option<&Token> {
self.tokens.peek().map(|(token, _)| token)
}
fn peek_span(&mut self) -> Option<Range<usize>> {
self.tokens.peek().map(|(_, span)| span.clone())
}
fn next(&mut self) -> Option<(Token, Range<usize>)> {
self.tokens.next()
}
fn expect(&mut self, expected: Token) -> Result<Range<usize>, ParseError> {
match self.next() {
Some((token, span))
if std::mem::discriminant(&token) == std::mem::discriminant(&expected) =>
{
Ok(span)
}
Some((token, span)) => Err(ParseError {
message: format!("Expected {:?}, found {:?}", expected, token),
span: Span::new(&span, self.file.clone()),
}),
None => Err(ParseError {
message: format!("Expected {:?}, found EOF", expected),
span: Span::new(&(0..0), self.file.clone()),
}),
}
}
fn error<T>(&self, msg: String, span: Range<usize>) -> Result<T, ParseError> {
Err(ParseError {
message: msg,
span: Span::new(&span, self.file.clone()),
})
}
fn parse_top_level(&mut self) -> Result<ASTNode, ParseError> {
let mut attributes = Vec::new();
// Parse any leading attributes
while matches!(self.peek(), Some(Token::At)) {
attributes.push(self.parse_attribute()?);
}
let start = self.peek_span().unwrap_or(0..0).start;
let token = self.peek().cloned();
match token {
Some(Token::KeywordUse) => {
self.next();
let path = match self.next() {
Some((Token::String(s), _)) => s,
Some((_, span)) => {
return self.error("Expected string after 'use'".to_string(), span);
}
None => {
return self.error("Expected string after 'use'".to_string(), start..start);
}
};
let end = self.peek_span().unwrap_or(start..start).end;
Ok(ASTNode {
kind: ASTNodeKind::Use(path),
span: Span::new(&(start..end), self.file.clone()),
attributes,
})
}
Some(Token::KeywordFn) => {
self.next();
let func = self.parse_function()?;
let end = self.peek_span().unwrap_or(start..start).end;
Ok(ASTNode {
kind: ASTNodeKind::Function(func),
span: Span::new(&(start..end), self.file.clone()),
attributes,
})
}
Some(Token::KeywordStruct) => {
self.next();
let struct_def = self.parse_struct()?;
let end = self.peek_span().unwrap_or(start..start).end;
Ok(ASTNode {
kind: ASTNodeKind::Struct(struct_def),
span: Span::new(&(start..end), self.file.clone()),
attributes,
})
}
Some(Token::KeywordEnum) => {
self.next();
let enum_def = self.parse_enum()?;
let end = self.peek_span().unwrap_or(start..start).end;
Ok(ASTNode {
kind: ASTNodeKind::Enum(enum_def),
span: Span::new(&(start..end), self.file.clone()),
attributes,
})
}
Some(Token::KeywordImpl) => {
self.next();
let impl_def = self.parse_impl()?;
let end = self.peek_span().unwrap_or(start..start).end;
Ok(ASTNode {
kind: ASTNodeKind::Impl(impl_def),
span: Span::new(&(start..end), self.file.clone()),
attributes,
})
}
Some(Token::KeywordTrait) => {
self.next();
let trait_def = self.parse_trait()?;
let end = self.peek_span().unwrap_or(start..start).end;
Ok(ASTNode {
kind: ASTNodeKind::Trait(trait_def),
span: Span::new(&(start..end), self.file.clone()),
attributes,
})
}
Some(Token::KeywordExtern) => {
self.next();
let extern_def = self.parse_extern()?;
let end = self.peek_span().unwrap_or(start..start).end;
Ok(ASTNode {
kind: ASTNodeKind::Extern(extern_def),
span: Span::new(&(start..end), self.file.clone()),
attributes,
})
}
Some(Token::KeywordLoad) => {
self.next();
let load_def = self.parse_load()?;
let end = self.peek_span().unwrap_or(start..start).end;
Ok(ASTNode {
kind: ASTNodeKind::Load(load_def),
span: Span::new(&(start..end), self.file.clone()),
attributes,
})
}
Some(token) => {
let span = self.peek_span().unwrap_or(start..start);
self.error(format!("Unexpected token at top level: {:?}", token), span)
}
None => self.error("Unexpected EOF".to_string(), start..start),
}
}
fn parse_attribute(&mut self) -> Result<Attribute, ParseError> {
self.expect(Token::At)?;
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),
};
// Parentheses are optional
let mut args = vec![];
if matches!(self.peek(), Some(Token::LParen)) {
self.next();
loop {
let token = self.peek().cloned();
match token {
Some(Token::RParen) => {
self.next();
break;
}
Some(Token::String(s)) => {
self.next();
args.push(AttributeArg::Literal(s));
}
Some(Token::Variable(id)) => {
self.next();
let next_token = self.peek().cloned();
if matches!(next_token, Some(Token::Assign)) {
self.next();
match self.next() {
Some((Token::Variable(val), _)) => {
args.push(AttributeArg::KeyValue(id, val))
}
Some((_, span)) => {
return self.error("Expected value after =".to_string(), span);
}
None => {
return self
.error("Expected value after =".to_string(), start..start);
}
}
} else {
args.push(AttributeArg::Value(id));
}
}
Some(token) => {
let span = self.peek_span().unwrap_or(start..start);
return self
.error(format!("Unexpected token in attribute: {:?}", token), span);
}
None => {
return self.error("Expected attribute argument".to_string(), start..start);
}
}
let next_token = self.peek().cloned();
if matches!(next_token, Some(Token::Comma)) {
self.next();
} else if matches!(next_token, Some(Token::RParen)) {
// ok
} else {
{
let span = self.peek_span().unwrap_or(start..start);
return self.error("Expected , or )".to_string(), span);
}
}
}
}
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Attribute {
name,
args,
span: Span::new(&(start..end), self.file.clone()),
})
}
fn parse_function(&mut self) -> Result<Function, ParseError> {
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),
};
// Parse type parameters if present
let parameters = if matches!(self.peek(), Some(Token::Less)) {
self.next();
self.parse_parameters()?
} else {
Vec::new()
};
// Parse function arguments
self.expect(Token::LParen)?;
let mut args = Vec::new();
loop {
if matches!(self.peek(), Some(Token::RParen)) {
self.next();
break;
}
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),
};
let arg_type = if matches!(self.peek(), Some(Token::Colon)) {
self.next();
Some(self.parse_type_annot()?)
} else {
None
};
args.push((arg_name, arg_type));
if matches!(self.peek(), Some(Token::Comma)) {
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);
}
}
// Parse return type if present
let return_type = if matches!(self.peek(), Some(Token::Arrow)) {
self.next();
Some(self.parse_type_annot()?)
} else {
None
};
// Parse body expression
let body = self.parse_expr()?;
Ok(Function {
name,
parameters,
args,
return_type,
body,
})
}
fn parse_struct(&mut self) -> Result<Struct, ParseError> {
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),
};
// Parse type parameters if present
let parameters = if matches!(self.peek(), Some(Token::Less)) {
self.next();
self.parse_parameters()?
} else {
Vec::new()
};
// Parse fields
let mut fields = Vec::new();
loop {
if matches!(self.peek(), Some(Token::KeywordEnd)) {
self.next();
break;
}
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),
};
self.expect(Token::Colon)?;
let field_type = self.parse_type_annot()?;
let field_end = self.peek_span().unwrap_or(field_start..field_start).start;
fields.push(Field {
name: field_name,
field_type,
span: Span::new(&(field_start..field_end), self.file.clone()),
});
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
Ok(Struct {
name,
parameters,
fields,
})
}
fn parse_enum(&mut self) -> Result<Enum, ParseError> {
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),
};
// Parse type parameters if present
let parameters = if matches!(self.peek(), Some(Token::Less)) {
self.next();
self.parse_parameters()?
} else {
Vec::new()
};
// Parse variants
let mut variants = Vec::new();
loop {
if matches!(self.peek(), Some(Token::KeywordEnd)) {
self.next();
break;
}
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),
};
let mut fields = Vec::new();
if matches!(self.peek(), Some(Token::LParen)) {
self.next();
loop {
if matches!(self.peek(), Some(Token::RParen)) {
self.next();
break;
}
fields.push(self.parse_type_annot()?);
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
}
let variant_end = self
.peek_span()
.unwrap_or(variant_start..variant_start)
.start;
variants.push(Variant {
name: variant_name,
fields,
span: Span::new(&(variant_start..variant_end), self.file.clone()),
});
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
Ok(Enum {
name,
parameters,
variants,
})
}
fn parse_impl(&mut self) -> Result<Impl, ParseError> {
let start = self.peek_span().unwrap_or(0..0).start;
// Parse impl target as a type (could be generic like Option<int>)
let target_type = self.parse_type_annot()?;
// Extract the base type name from the type annotation
let target = match target_type {
TypeAnnot::Var(name) => name,
TypeAnnot::Cons(name, _) => name,
_ => {
return self.error(
"Expected type name for impl target".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
};
// Parse methods
let mut methods = Vec::new();
loop {
if matches!(self.peek(), Some(Token::KeywordEnd)) {
self.next();
break;
}
self.expect(Token::KeywordFn)?;
methods.push(self.parse_function()?);
}
Ok(Impl {
target,
trait_name,
methods,
})
}
fn parse_trait(&mut self) -> Result<Trait, ParseError> {
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),
};
// Parse type parameters if present
let parameters = if matches!(self.peek(), Some(Token::Less)) {
self.next();
self.parse_parameters()?
} else {
Vec::new()
};
// Parse methods
let mut methods = Vec::new();
loop {
if matches!(self.peek(), Some(Token::KeywordEnd)) {
self.next();
break;
}
if matches!(self.peek(), Some(Token::KeywordFn)) {
self.next();
methods.push(self.parse_function_signature()?);
// Optional comma between methods
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
} else {
break;
}
}
Ok(Trait {
name,
methods,
parameters,
associated_types: Vec::new(),
})
}
fn parse_extern(&mut self) -> Result<Extern, ParseError> {
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),
};
// Parse argument types (with optional parameter names)
self.expect(Token::LParen)?;
let mut args = Vec::new();
loop {
if matches!(self.peek(), Some(Token::RParen)) {
self.next();
break;
}
args.push(self.parse_type_annot()?);
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
// Parse return type
self.expect(Token::Arrow)?;
let return_type = self.parse_type_annot()?;
// Parse from clause
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),
};
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Extern {
name,
args,
return_type,
from,
span: Span::new(&(start..end), self.file.clone()),
})
}
fn parse_load(&mut self) -> Result<Load, ParseError> {
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),
};
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),
};
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Load {
library,
alias,
span: Span::new(&(start..end), self.file.clone()),
})
}
fn parse_parameters(&mut self) -> Result<Vec<Parameter>, ParseError> {
let start = self.peek_span().unwrap_or(0..0).start;
let mut params = Vec::new();
loop {
if matches!(self.peek(), Some(Token::Greater)) {
self.next();
break;
}
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 bounds = if matches!(self.peek(), Some(Token::Colon)) {
self.next();
self.parse_trait_bounds()?
} else {
Vec::new()
};
let kind = if matches!(self.peek(), Some(Token::Colon)) {
self.next();
Some(self.parse_kind()?)
} else {
None
};
let param_end = self.peek_span().unwrap_or(param_start..param_start).end;
params.push(Parameter {
name: param_name,
bounds,
kind,
span: Span::new(&(param_start..param_end), self.file.clone()),
});
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
Ok(params)
}
fn parse_trait_bounds(&mut self) -> Result<Vec<String>, ParseError> {
let mut bounds = Vec::new();
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),
}
if !matches!(self.peek(), Some(Token::Plus)) {
break;
}
self.next();
}
Ok(bounds)
}
fn parse_kind(&mut self) -> Result<Kind, ParseError> {
if matches!(self.peek(), Some(Token::Mul)) {
self.next();
Ok(Kind::Star)
} else {
let k1 = Box::new(self.parse_kind()?);
self.expect(Token::Arrow)?;
let k2 = Box::new(self.parse_kind()?);
Ok(Kind::Arrow(k1, k2))
}
}
fn parse_type_annot(&mut self) -> Result<TypeAnnot, ParseError> {
let start = self.peek_span().unwrap_or(0..0).start;
// Check for function type: fn (args)->ret
if matches!(self.peek(), Some(Token::KeywordFn)) {
self.next();
self.expect(Token::LParen)?;
let mut arg_types = Vec::new();
loop {
if matches!(self.peek(), Some(Token::RParen)) {
self.next();
break;
}
arg_types.push(self.parse_type_annot()?);
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
self.expect(Token::Arrow)?;
let ret_type = Box::new(self.parse_type_annot()?);
return Ok(TypeAnnot::Function(arg_types, ret_type));
}
let mut base_type = match self.next() {
Some((Token::Variable(n), _)) => TypeAnnot::Cons(n, vec![]),
Some((Token::KeywordBool, _)) => TypeAnnot::Cons("bool".to_string(), vec![]),
Some((Token::KeywordInt, _)) => TypeAnnot::Cons("int".to_string(), vec![]),
Some((Token::KeywordFloat, _)) => TypeAnnot::Cons("float".to_string(), vec![]),
Some((Token::KeywordString, _)) => TypeAnnot::Cons("string".to_string(), vec![]),
Some((Token::LParen, _)) => {
// Check for unit type: ()
if matches!(self.peek(), Some(Token::RParen)) {
self.next();
return Ok(TypeAnnot::Cons("unit".to_string(), vec![]));
}
let mut types = Vec::new();
loop {
if matches!(self.peek(), Some(Token::RParen)) {
self.next();
break;
}
types.push(self.parse_type_annot()?);
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
// Single element in parens is not a tuple, unwrap it
if types.len() == 1 {
types.pop().unwrap()
} else {
TypeAnnot::Tuple(types)
}
}
Some((Token::LBracket, _)) => {
let inner = self.parse_type_annot()?;
self.expect(Token::RBracket)?;
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),
};
// Parse type arguments if present
if matches!(self.peek(), Some(Token::Less)) {
self.next();
let mut args = Vec::new();
loop {
if matches!(self.peek(), Some(Token::Greater)) {
self.next();
break;
}
args.push(self.parse_type_annot()?);
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
base_type = match base_type {
TypeAnnot::Cons(name, _) => TypeAnnot::Cons(name, args),
_ => {
return self.error("Expected type name for generic".to_string(), start..start);
}
};
}
// Parse array types
while matches!(self.peek(), Some(Token::LBracket)) {
self.next();
self.expect(Token::RBracket)?;
base_type = TypeAnnot::Array(Box::new(base_type));
}
Ok(base_type)
}
fn parse_function_signature(&mut self) -> Result<FunctionSignature, ParseError> {
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),
};
self.expect(Token::LParen)?;
let mut params = Vec::new();
loop {
if matches!(self.peek(), Some(Token::RParen)) {
self.next();
break;
}
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),
};
// Parameters in trait methods may have type annotations
if matches!(self.peek(), Some(Token::Colon)) {
self.next();
let _param_type = self.parse_type_annot()?;
}
let param_end = self.peek_span().unwrap_or(param_start..param_start).end;
params.push(Parameter {
name: param_name,
bounds: Vec::new(),
kind: None,
span: Span::new(&(param_start..param_end), self.file.clone()),
});
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
self.expect(Token::Arrow)?;
let return_type = self.parse_type_annot()?;
Ok(FunctionSignature {
name,
params,
return_type,
})
}
fn parse_expr(&mut self) -> Result<Expr, ParseError> {
let mut attributes = Vec::new();
// Parse any leading attributes
while matches!(self.peek(), Some(Token::At)) {
attributes.push(self.parse_attribute()?);
}
let mut expr = self.parse_assignment()?;
expr.attributes = attributes;
Ok(expr)
}
fn parse_range_expr(&mut self) -> Result<Expr, ParseError> {
let left = self.parse_or_expr()?;
if matches!(self.peek(), Some(Token::DotDot)) {
let start = left.span.start;
self.next();
let right = self.parse_or_expr()?;
let end = right.span.end;
Ok(Expr {
kind: ExprKind::Range(Box::new(left), Box::new(right)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
} else {
Ok(left)
}
}
fn parse_assignment(&mut self) -> Result<Expr, ParseError> {
let left = self.parse_range_expr()?;
if matches!(self.peek(), Some(Token::Assign)) {
let start = left.span.start;
self.next();
let right = self.parse_assignment()?;
let end = right.span.end;
Ok(Expr {
kind: ExprKind::Assign(Box::new(left), Box::new(right)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
} else {
Ok(left)
}
}
fn parse_or_expr(&mut self) -> Result<Expr, ParseError> {
let mut left = self.parse_and_expr()?;
loop {
if matches!(self.peek(), Some(Token::Or)) {
let start = left.span.start;
self.next();
let right = self.parse_and_expr()?;
let end = right.span.end;
left = Expr {
kind: ExprKind::BinOp(Box::new(left), BinOp::Or, Box::new(right)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
} else {
break;
}
}
Ok(left)
}
fn parse_and_expr(&mut self) -> Result<Expr, ParseError> {
let mut left = self.parse_eq_expr()?;
loop {
if matches!(self.peek(), Some(Token::And)) {
let start = left.span.start;
self.next();
let right = self.parse_eq_expr()?;
let end = right.span.end;
left = Expr {
kind: ExprKind::BinOp(Box::new(left), BinOp::And, Box::new(right)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
} else {
break;
}
}
Ok(left)
}
fn parse_eq_expr(&mut self) -> Result<Expr, ParseError> {
let mut left = self.parse_comp_expr()?;
loop {
let op = match self.peek() {
Some(Token::Eq) => BinOp::Eq,
Some(Token::NotEq) => BinOp::Neq,
_ => break,
};
let start = left.span.start;
self.next();
let right = self.parse_comp_expr()?;
let end = right.span.end;
left = Expr {
kind: ExprKind::BinOp(Box::new(left), op, Box::new(right)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
}
Ok(left)
}
fn parse_comp_expr(&mut self) -> Result<Expr, ParseError> {
let mut left = self.parse_add_expr()?;
loop {
let op = match self.peek() {
Some(Token::Less) => BinOp::Lt,
Some(Token::Greater) => BinOp::Gt,
Some(Token::LessEq) => BinOp::Leq,
Some(Token::GreaterEq) => BinOp::Geq,
_ => break,
};
let start = left.span.start;
self.next();
let right = self.parse_add_expr()?;
let end = right.span.end;
left = Expr {
kind: ExprKind::BinOp(Box::new(left), op, Box::new(right)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
}
Ok(left)
}
fn parse_add_expr(&mut self) -> Result<Expr, ParseError> {
let mut left = self.parse_mul_expr()?;
loop {
let op = match self.peek() {
Some(Token::Plus) => BinOp::Add,
Some(Token::Minus) => BinOp::Sub,
_ => break,
};
let start = left.span.start;
self.next();
let right = self.parse_mul_expr()?;
let end = right.span.end;
left = Expr {
kind: ExprKind::BinOp(Box::new(left), op, Box::new(right)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
}
Ok(left)
}
fn parse_mul_expr(&mut self) -> Result<Expr, ParseError> {
let mut left = self.parse_unary_expr()?;
loop {
let op = match self.peek() {
Some(Token::Mul) => BinOp::Mul,
Some(Token::Div) => BinOp::Div,
Some(Token::Mod) => BinOp::Mod,
_ => break,
};
let start = left.span.start;
self.next();
let right = self.parse_unary_expr()?;
let end = right.span.end;
left = Expr {
kind: ExprKind::BinOp(Box::new(left), op, Box::new(right)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
}
Ok(left)
}
fn parse_unary_expr(&mut self) -> Result<Expr, ParseError> {
let start = self.peek_span().unwrap_or(0..0).start;
match self.peek() {
Some(Token::Not) => {
self.next();
let expr = self.parse_unary_expr()?;
let end = expr.span.end;
Ok(Expr {
kind: ExprKind::UnOp(UnOp::Not, Box::new(expr)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::Minus) => {
self.next();
let expr = self.parse_unary_expr()?;
let end = expr.span.end;
Ok(Expr {
kind: ExprKind::UnOp(UnOp::Neg, Box::new(expr)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
_ => self.parse_postfix_expr(),
}
}
fn parse_postfix_expr(&mut self) -> Result<Expr, ParseError> {
let mut expr = self.parse_primary_expr()?;
loop {
match self.peek() {
Some(Token::LParen) => {
// Function call
let start = expr.span.start;
self.next();
let mut args = Vec::new();
loop {
if matches!(self.peek(), Some(Token::RParen)) {
self.next();
break;
}
args.push(self.parse_expr()?);
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
let end = self.peek_span().unwrap_or(expr.span.end..expr.span.end).end;
expr = Expr {
kind: ExprKind::Call(Box::new(expr), args),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
}
Some(Token::LBracket) => {
// Index
let start = expr.span.start;
self.next();
let index = self.parse_expr()?;
self.expect(Token::RBracket)?;
let end = self.peek_span().unwrap_or(expr.span.end..expr.span.end).end;
expr = Expr {
kind: ExprKind::Index(Box::new(expr), Box::new(index)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
}
Some(Token::Dot) => {
// Field access
let start = expr.span.start;
self.next();
let field = match self.next() {
Some((Token::Variable(f), _)) => f,
Some((_, span)) => {
return self.error("Expected field name".to_string(), span);
}
None => return self.error("Expected field name".to_string(), start..start),
};
let end = self.peek_span().unwrap_or(expr.span.end..expr.span.end).end;
expr = Expr {
kind: ExprKind::Dot(Box::new(expr), field),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
}
Some(Token::OptionalChain) => {
// Optional chain
let start = expr.span.start;
self.next();
let field = match self.next() {
Some((Token::Variable(f), _)) => f,
Some((_, span)) => {
return self.error("Expected field name".to_string(), span);
}
None => return self.error("Expected field name".to_string(), start..start),
};
let end = self.peek_span().unwrap_or(expr.span.end..expr.span.end).end;
expr = Expr {
kind: ExprKind::OptionalChain(Some(Box::new(expr)), field),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
}
Some(Token::Unwrap) => {
// Early return / unwrap
let start = expr.span.start;
self.next();
let end = self.peek_span().unwrap_or(expr.span.end..expr.span.end).end;
expr = Expr {
kind: ExprKind::EarlyReturn(Some(Box::new(expr))),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
}
Some(Token::KeywordAs) => {
// Cast
let start = expr.span.start;
self.next();
let type_annot = self.parse_type_annot()?;
let end = self.peek_span().unwrap_or(expr.span.end..expr.span.end).end;
expr = Expr {
kind: ExprKind::Cast(Box::new(expr), type_annot),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
}
_ => break,
}
}
Ok(expr)
}
fn parse_primary_expr(&mut self) -> Result<Expr, ParseError> {
let start = self.peek_span().unwrap_or(0..0).start;
match self.peek().cloned() {
Some(Token::Int(n)) => {
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::Int(n),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::Float(f)) => {
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::Float(f),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::Bool(b)) => {
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::Bool(b),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::String(s)) => {
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::String(s),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::Variable(name)) => {
self.next();
// Check for struct literal or enum variant
if matches!(self.peek(), Some(Token::LBrace)) {
// Struct literal
self.next();
let mut fields = Vec::new();
loop {
if matches!(self.peek(), Some(Token::RBrace)) {
self.next();
break;
}
let field_name = match self.next() {
Some((Token::Variable(f), _)) => f,
Some((_, span)) => {
return self.error("Expected field name".to_string(), span);
}
None => {
return self.error("Expected field name".to_string(), start..start);
}
};
self.expect(Token::Colon)?;
let field_expr = self.parse_expr()?;
fields.push((field_name, field_expr));
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::StructLit(name, fields),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
} else if matches!(self.peek(), Some(Token::Access)) {
// Enum variant
self.next();
let variant = match self.next() {
Some((Token::Variable(v), _)) => v,
Some((_, span)) => {
return self.error("Expected variant name".to_string(), span);
}
None => {
return self.error("Expected variant name".to_string(), start..start);
}
};
let mut args = Vec::new();
if matches!(self.peek(), Some(Token::LParen)) {
self.next();
loop {
if matches!(self.peek(), Some(Token::RParen)) {
self.next();
break;
}
args.push(self.parse_expr()?);
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
}
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::EnumLit(name, variant, args),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
} else {
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::Variable(name),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
}
Some(Token::LParen) => {
self.next();
if matches!(self.peek(), Some(Token::RParen)) {
// Empty tuple
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::Tuple(vec![]),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
} else {
let first = self.parse_expr()?;
if matches!(self.peek(), Some(Token::Comma)) {
// Tuple
let mut elements = vec![first];
self.next();
loop {
if matches!(self.peek(), Some(Token::RParen)) {
break;
}
elements.push(self.parse_expr()?);
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
self.expect(Token::RParen)?;
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::Tuple(elements),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
} else {
self.expect(Token::RParen)?;
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: first.kind,
span: Span::new(&(start..end), self.file.clone()),
attributes: first.attributes,
})
}
}
}
Some(Token::LBracket) => {
self.next();
let mut elements = Vec::new();
loop {
if matches!(self.peek(), Some(Token::RBracket)) {
self.next();
break;
}
elements.push(self.parse_expr()?);
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::Array(elements),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::KeywordLet) => {
self.next();
// Parse binding kind (mut, uniq, once) - comes AFTER let
let binding_kind = match self.peek() {
Some(Token::KeywordMut) => {
self.next();
BindingKind::Mutable
}
Some(Token::KeywordUniq) => {
self.next();
BindingKind::Affine
}
Some(Token::KeywordOnce) => {
self.next();
BindingKind::Linear
}
_ => BindingKind::Default,
};
// Now parse the variable name
let var_name = match self.next() {
Some((Token::Variable(n), _)) => n,
Some((_, span)) => {
return self.error("Expected variable name".to_string(), span);
}
None => return self.error("Expected variable name".to_string(), start..start),
};
// Parse optional type annotation
let type_annot = if matches!(self.peek(), Some(Token::Colon)) {
self.next();
Some(self.parse_type_annot()?)
} else {
None
};
self.expect(Token::Assign)?;
let expr = self.parse_expr()?;
let end = expr.span.end;
Ok(Expr {
kind: ExprKind::Let(var_name, binding_kind, type_annot, Box::new(expr)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::KeywordIf) => {
self.next();
let cond = self.parse_expr()?;
let then_expr = self.parse_expr()?;
let else_expr = if matches!(self.peek(), Some(Token::KeywordElse)) {
self.next();
Some(Box::new(self.parse_expr()?))
} else {
None
};
let end = else_expr
.as_ref()
.map(|e| e.span.end)
.unwrap_or(then_expr.span.end);
Ok(Expr {
kind: ExprKind::If(Box::new(cond), Box::new(then_expr), else_expr),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::KeywordMatch) => {
self.next();
let expr = self.parse_expr()?;
let mut arms = Vec::new();
loop {
if matches!(self.peek(), Some(Token::KeywordEnd)) {
self.next();
break;
}
let pattern = self.parse_pattern()?;
self.expect(Token::FatArrow)?;
let body = self.parse_expr()?;
arms.push((pattern, body));
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::Match(Box::new(expr), arms),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::KeywordWhile) => {
self.next();
let cond = self.parse_expr()?;
let body = self.parse_expr()?;
let end = body.span.end;
Ok(Expr {
kind: ExprKind::While(Box::new(cond), Box::new(body)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::KeywordFor) => {
self.next();
let var = match self.next() {
Some((Token::Variable(v), _)) => v,
Some((_, span)) => {
return self.error("Expected variable name".to_string(), span);
}
None => return self.error("Expected variable name".to_string(), start..start),
};
self.expect(Token::KeywordIn)?;
let iterable = self.parse_expr()?;
let body = self.parse_expr()?;
let end = body.span.end;
Ok(Expr {
kind: ExprKind::For(var, Box::new(iterable), Box::new(body)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::KeywordDo) => {
self.next();
let mut exprs = Vec::new();
loop {
if matches!(self.peek(), Some(Token::KeywordEnd)) {
self.next();
break;
}
exprs.push(self.parse_expr()?);
if matches!(self.peek(), Some(Token::Semicolon)) {
self.next();
}
}
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::Do(exprs),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::KeywordLambda) => {
let start = self.peek_span().unwrap_or(0..0).start;
self.next();
self.expect(Token::LParen)?;
let mut params = Vec::new();
loop {
if matches!(self.peek(), Some(Token::RParen)) {
self.next();
break;
}
let param_name = match self.next() {
Some((Token::Variable(p), _)) => p,
Some((_, span)) => {
return self.error("Expected parameter name".to_string(), span);
}
None => {
return self.error("Expected parameter name".to_string(), start..start);
}
};
// Check for optional type annotation
let param_type = if matches!(self.peek(), Some(Token::Colon)) {
self.next(); // consume ':'
Some(self.parse_type_annot()?)
} else {
None
};
params.push((param_name, param_type));
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
let body = self.parse_expr()?;
let end = body.span.end;
Ok(Expr {
kind: ExprKind::Lambda(params, Box::new(body)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::KeywordReturn) => {
self.next();
let expr = if self.is_expr_end() {
None
} else {
Some(Box::new(self.parse_expr()?))
};
let end = expr
.as_ref()
.map(|e| e.span.end)
.unwrap_or(self.peek_span().unwrap_or(start..start).end);
Ok(Expr {
kind: ExprKind::Return(expr),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::KeywordBreak) => {
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::Break,
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(Token::KeywordContinue) => {
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Expr {
kind: ExprKind::Continue,
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
Some(token) => {
let span = self.peek_span().unwrap_or(start..start);
self.error(format!("Unexpected token: {:?}", token), span)
}
None => self.error("Unexpected EOF".to_string(), start..start),
}
}
fn parse_pattern(&mut self) -> Result<Pattern, ParseError> {
let start = self.peek_span().unwrap_or(0..0).start;
match self.peek().cloned() {
Some(Token::Variable(name)) => {
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
// Check for struct or enum pattern
if matches!(self.peek(), Some(Token::LBrace)) {
// Struct pattern
self.next();
let mut fields = Vec::new();
loop {
if matches!(self.peek(), Some(Token::RBrace)) {
self.next();
break;
}
let field_name = match self.next() {
Some((Token::Variable(f), _)) => f,
Some((_, span)) => {
return self.error("Expected field name".to_string(), span);
}
None => {
return self.error("Expected field name".to_string(), start..start);
}
};
self.expect(Token::Colon)?;
let pattern = self.parse_pattern()?;
fields.push((field_name, pattern));
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Pattern {
kind: PatternKind::Struct(name, fields),
span: Span::new(&(start..end), self.file.clone()),
})
} else if matches!(self.peek(), Some(Token::Access)) {
// Enum pattern
self.next();
let variant = match self.next() {
Some((Token::Variable(v), _)) => v,
Some((_, span)) => {
return self.error("Expected variant name".to_string(), span);
}
None => {
return self.error("Expected variant name".to_string(), start..start);
}
};
let mut patterns = Vec::new();
if matches!(self.peek(), Some(Token::LParen)) {
self.next();
loop {
if matches!(self.peek(), Some(Token::RParen)) {
self.next();
break;
}
patterns.push(self.parse_pattern()?);
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
}
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Pattern {
kind: PatternKind::Enum(name, variant, patterns),
span: Span::new(&(start..end), self.file.clone()),
})
} else {
Ok(Pattern {
kind: PatternKind::Variable(name),
span: Span::new(&(start..end), self.file.clone()),
})
}
}
Some(Token::Union) => {
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Pattern {
kind: PatternKind::Wildcard,
span: Span::new(&(start..end), self.file.clone()),
})
}
Some(Token::LParen) => {
self.next();
let mut patterns = Vec::new();
loop {
if matches!(self.peek(), Some(Token::RParen)) {
self.next();
break;
}
patterns.push(self.parse_pattern()?);
if matches!(self.peek(), Some(Token::Comma)) {
self.next();
}
}
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Pattern {
kind: PatternKind::Tuple(patterns),
span: Span::new(&(start..end), self.file.clone()),
})
}
Some(Token::String(s)) => {
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Pattern {
kind: PatternKind::Literal(s),
span: Span::new(&(start..end), self.file.clone()),
})
}
Some(Token::Int(n)) => {
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Pattern {
kind: PatternKind::Literal(n.to_string()),
span: Span::new(&(start..end), self.file.clone()),
})
}
Some(Token::Float(f)) => {
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Pattern {
kind: PatternKind::Literal(f.to_string()),
span: Span::new(&(start..end), self.file.clone()),
})
}
Some(Token::Bool(b)) => {
self.next();
let end = self.peek_span().unwrap_or(start..start).end;
Ok(Pattern {
kind: PatternKind::Literal(b.to_string()),
span: Span::new(&(start..end), self.file.clone()),
})
}
Some(token) => {
let span = self.peek_span().unwrap_or(start..start);
self.error(format!("Unexpected token in pattern: {:?}", token), span)
}
None => self.error("Unexpected EOF".to_string(), start..start),
}
}
fn is_expr_end(&mut self) -> bool {
matches!(
self.peek(),
Some(Token::RParen)
| Some(Token::RBracket)
| Some(Token::RBrace)
| Some(Token::Comma)
| Some(Token::Semicolon)
| Some(Token::KeywordEnd)
| Some(Token::FatArrow)
)
}
}