diff --git a/output.md b/output.md new file mode 100644 index 0000000..338d02d --- /dev/null +++ b/output.md @@ -0,0 +1,8036 @@ +```rust +// src/lib.rs +pub const EXTENSION: &str = ".sui"; + +pub mod ast; +pub mod c_ir; +pub mod codegen; +pub mod lambda_lower; +pub mod lexer; +pub mod monomorphize; +pub mod parser; +pub mod typechecker; + +``` + +```rust +// src/ast.rs +use crate::typechecker::Type; +use std::ops::Range; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct BindingId(pub usize); + +#[derive(Debug, Clone)] +pub enum TypeAnnot { + Var(String), + Cons(String, Vec), + Function(Vec, Box), + Tuple(Vec), + Array(Box), + Ptr(Box), +} + +#[derive(Debug, Clone)] +pub struct Span { + pub start: usize, + pub end: usize, + pub file: String, +} + +impl Span { + pub fn new(range: &Range, file: String) -> Self { + Span { + start: range.start, + end: range.end, + file, + } + } + + pub fn merge(&self, other: &Span) -> Span { + Span { + start: self.start.min(other.start), + end: self.end.max(other.end), + file: self.file.clone(), + } + } +} + +// @attribute +#[derive(Debug, Clone)] +pub struct Attribute { + pub name: String, + pub args: Vec, + pub span: Span, +} + +#[derive(Debug, Clone)] +pub enum AttributeArg { + Value(String), // some_identifier + KeyValue(String, String), // some_key = some_identifier + Literal(String), // some literal value +} + +#[derive(Debug, Clone)] +pub struct ASTNode { + pub kind: ASTNodeKind, + pub span: Span, + pub attributes: Vec, +} + +#[derive(Debug, Clone)] +pub enum ASTNodeKind { + Function(Function), + Extern(Extern), + Load(Load), + Struct(Struct), + Enum(Enum), + Impl(Impl), + Trait(Trait), + Use(String), +} + +// ? implies OPTIONAL here +// \( implies the presence of (. same for /) + +#[derive(Debug, Clone)] +/// fn name\( (arg: type?,)* \) -> return_type? body +pub struct Function { + pub name: String, + pub parameters: Vec, // type params + pub args: Vec<(String, Option)>, + pub return_type: Option, + pub body: Expr, +} + +/// extern name\( type?,* \) -> return_type from library_alias +#[derive(Debug, Clone)] +pub struct Extern { + pub name: String, + pub args: Vec, + pub return_type: TypeAnnot, + pub from: String, + pub span: Span, +} + +/// load "library" as alias +#[derive(Debug, Clone)] +pub struct Load { + pub library: String, + pub alias: String, + pub span: Span, +} + +/// struct name ? +/// (field_name: field_type,)* +/// end +#[derive(Debug, Clone)] +pub struct Struct { + pub name: String, + pub parameters: Vec, // type parameters + pub fields: Vec, +} + +#[derive(Debug, Clone)] +pub struct Field { + pub name: String, + pub field_type: TypeAnnot, + pub span: Span, +} + +/// enum name ? +/// VariantName\(field_type,\)* +/// end +#[derive(Debug, Clone)] +pub struct Enum { + pub name: String, + pub parameters: Vec, // type parameters + pub variants: Vec, +} + +#[derive(Debug, Clone)] +pub struct Parameter { + pub name: String, + pub bounds: Vec, // trait bounds + pub kind: Option, // for HKTs + pub span: Span, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum Kind { + Star, // * + Arrow(Box, Box), // k1 -> k2 +} + +#[derive(Debug, Clone)] +pub struct Variant { + pub name: String, + pub fields: Vec, + pub span: Span, +} + +/// impl TypeName ? (: TraitName)? +/// functions* +/// end +#[derive(Debug, Clone)] +pub struct Impl { + pub target: String, + pub trait_name: Option, + pub methods: Vec, +} + +/// trait TraitName ? +/// function_signatures* +/// end +#[derive(Debug, Clone)] +pub struct Trait { + pub name: String, + pub methods: Vec, + + pub parameters: Vec, + pub associated_types: Vec, +} + +#[derive(Debug, Clone)] +pub struct AssociatedType { + pub name: String, + pub bounds: Vec, + pub span: Span, +} + +#[derive(Debug, Clone)] +pub struct FunctionSignature { + pub name: String, + pub params: Vec, + pub return_type: TypeAnnot, +} + +#[derive(Debug, Clone)] +pub struct Expr { + pub kind: ExprKind, + pub span: Span, + pub attributes: Vec, +} + +#[derive(Debug, Clone)] +pub enum ExprKind { + Int(i64), + Float(f64), + Bool(bool), + String(String), + Array(Vec), + Tuple(Vec), + + StructLit(String, Vec<(String, Expr)>), // Name { a: expr, b: expr } + EnumLit(String, String, Vec), // Name::Variant(expr, expr) + + Variable(String), + + Call(Box, Vec), + Index(Box, Box), + Dot(Box, String), + EarlyReturn(Option>), // eg: myresultoroption? + OptionalChain(Option>, String), // a?.b + + Lambda(Vec<(String, Option)>, Box), // lambda (arg, arg: optionalty, ...) body + Let(String, BindingKind, Option, Box), // no patterns for now + Assign(Box, Box), // NOTE: check for valid lvalue during typechecking + Cast(Box, TypeAnnot), + + If(Box, Box, Option>), // if cond expr (else expr)? + Match(Box, Vec<(Pattern, Expr)>), // match expr pattern => expr* end + While(Box, Box), // while cond expr + + For(String, Box, Box), // for i in expr body + Range(Box, Box), // 0..10 + + Do(Vec), // do expr* end + BinOp(Box, BinOp, Box), + UnOp(UnOp, Box), + + Return(Option>), + Break, + Continue, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum BindingKind { + Default, // immutable but infinite usages + Mutable, // mutable but infinite usages + Affine, + Linear, +} + +#[derive(Debug, Clone)] +pub enum BinOp { + Add, + Sub, + Mul, + Div, + Mod, + And, + Or, + Eq, + Neq, + Lt, + Gt, + Leq, + Geq, +} + +#[derive(Debug, Clone)] +pub enum UnOp { + Neg, + Not, + Ref, + Deref, +} + +#[derive(Debug, Clone)] +pub struct Pattern { + pub kind: PatternKind, + pub span: Span, +} + +#[derive(Debug, Clone)] +pub enum PatternKind { + Wildcard, // _ + Variable(String), + Literal(String), + Tuple(Vec), + Struct(String, Vec<(String, Pattern)>), + Enum(String, String, Vec), + Range(i64, i64), +} + +// Typed variants + +#[derive(Debug, Clone)] +pub struct TypedASTNode { + pub kind: TypedASTNodeKind, + pub span: Span, + pub attributes: Vec, + pub ty: Type, +} + +#[derive(Debug, Clone)] +pub enum TypedASTNodeKind { + Function(TypedFunction), + Extern(TypedExtern), + Load(TypedLoad), + Struct(TypedStruct), + Enum(TypedEnum), + Impl(TypedImpl), + Trait(TypedTrait), + Use(String), +} + +#[derive(Debug, Clone)] +pub struct TypedFunction { + pub name: String, + pub parameters: Vec, + pub args: Vec<(BindingId, String, Option)>, + pub return_type: Option, + pub body: TypedExpr, + pub ty: Type, +} + +#[derive(Debug, Clone)] +pub struct TypedExtern { + pub name: String, + pub args: Vec, + pub return_type: TypeAnnot, + pub from: String, + pub span: Span, +} + +#[derive(Debug, Clone)] +pub struct TypedLoad { + pub library: String, + pub alias: String, + pub span: Span, +} + +#[derive(Debug, Clone)] +pub struct TypedStruct { + pub name: String, + pub parameters: Vec, + pub fields: Vec, +} + +#[derive(Debug, Clone)] +pub struct TypedField { + pub name: String, + pub field_type: TypeAnnot, + pub span: Span, +} + +#[derive(Debug, Clone)] +pub struct TypedEnum { + pub name: String, + pub parameters: Vec, + pub variants: Vec, +} + +#[derive(Debug, Clone)] +pub struct TypedVariant { + pub name: String, + pub fields: Vec, + pub span: Span, +} + +#[derive(Debug, Clone)] +pub struct TypedImpl { + pub target: String, + pub trait_name: Option, + pub methods: Vec, +} + +#[derive(Debug, Clone)] +pub struct TypedTrait { + pub name: String, + pub methods: Vec, + pub parameters: Vec, + pub associated_types: Vec, +} + +#[derive(Debug, Clone)] +pub struct TypedExpr { + pub kind: TypedExprKind, + pub span: Span, + pub attributes: Vec, + pub ty: Type, +} + +#[derive(Debug, Clone)] +pub enum TypedExprKind { + Int(i64), + Float(f64), + Bool(bool), + String(String), + Array(Vec), + Tuple(Vec), + StructLit(String, Vec<(String, TypedExpr)>), + EnumLit(String, String, Vec), + Variable(String), + Call(Box, Vec), + Index(Box, Box), + Dot(Box, String), + EarlyReturn(Option>), + OptionalChain(Option>, String), + Lambda(Vec<(BindingId, String, Option)>, Box), + Let( + BindingId, + String, + BindingKind, + Option, + Box, + ), + Assign(Box, Box), + Cast(Box, TypeAnnot), + If(Box, Box, Option>), + Match(Box, Vec<(TypedPattern, TypedExpr)>), + While(Box, Box), + Do(Vec), + BinOp(Box, BinOp, Box), + UnOp(UnOp, Box), + For(BindingId, String, Box, Box), + Range(Box, Box), + Return(Option>), + Break, + Continue, +} + +#[derive(Debug, Clone)] +pub struct TypedPattern { + pub kind: TypedPatternKind, + pub span: Span, + pub ty: Type, +} + +#[derive(Debug, Clone)] +pub enum TypedPatternKind { + Wildcard, + Variable(BindingId, String), + Literal(String), + Tuple(Vec), + Struct(String, Vec<(String, TypedPattern)>), + Enum(String, String, Vec), +} + +``` + +```rust +// src/lambda_lower.rs +use crate::ast::*; +use std::cell::RefCell; +use std::rc::Rc; + +/// LambdaLowerer converts lambda expressions into generated functions +/// that are hoisted to the top level of the program. +pub struct LambdaLowerer { + lambda_counter: Rc>, + generated_functions: Rc>>, +} + +impl LambdaLowerer { + pub fn new() -> Self { + LambdaLowerer { + lambda_counter: Rc::new(RefCell::new(0)), + generated_functions: Rc::new(RefCell::new(Vec::new())), + } + } + + fn collect_free_vars( + &self, + expr: &Expr, + lambda_params: &[String], + ) -> std::collections::HashSet { + let mut free_vars = std::collections::HashSet::new(); + let mut local_scope = std::collections::HashSet::new(); + self.collect_free_vars_expr(expr, lambda_params, &mut free_vars, &mut local_scope); + free_vars + } + + fn collect_free_vars_expr( + &self, + expr: &Expr, + lambda_params: &[String], + free_vars: &mut std::collections::HashSet, + local_scope: &mut std::collections::HashSet, + ) { + match &expr.kind { + ExprKind::Variable(name) => { + if !lambda_params.contains(name) && !local_scope.contains(name) { + free_vars.insert(name.clone()); + } + } + ExprKind::Lambda(args, body) => { + let param_names: Vec = args.iter().map(|(name, _)| name.clone()).collect(); + // For nested lambdas, we don't enter a new scope here since we're just collecting free vars + self.collect_free_vars_expr(body, ¶m_names, free_vars, local_scope); + } + ExprKind::Let(name, _, _, body) => { + // Collect from body before adding the binding + self.collect_free_vars_expr(body, lambda_params, free_vars, local_scope); + // Add to local scope + local_scope.insert(name.clone()); + } + ExprKind::Call(func, args) => { + self.collect_free_vars_expr(func, lambda_params, free_vars, local_scope); + for arg in args { + self.collect_free_vars_expr(arg, lambda_params, free_vars, local_scope); + } + } + // Handle other expression types that contain subexpressions + ExprKind::If(cond, then_expr, else_expr) => { + self.collect_free_vars_expr(cond, lambda_params, free_vars, local_scope); + self.collect_free_vars_expr(then_expr, lambda_params, free_vars, local_scope); + if let Some(else_expr) = else_expr { + self.collect_free_vars_expr(else_expr, lambda_params, free_vars, local_scope); + } + } + ExprKind::Match(scrutinee, arms) => { + self.collect_free_vars_expr(scrutinee, lambda_params, free_vars, local_scope); + for (_, expr) in arms { + self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope); + } + } + ExprKind::While(cond, body) => { + self.collect_free_vars_expr(cond, lambda_params, free_vars, local_scope); + self.collect_free_vars_expr(body, lambda_params, free_vars, local_scope); + } + ExprKind::For(_, iter, body) => { + self.collect_free_vars_expr(iter, lambda_params, free_vars, local_scope); + self.collect_free_vars_expr(body, lambda_params, free_vars, local_scope); + } + ExprKind::Do(exprs) => { + for expr in exprs { + self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope); + } + } + ExprKind::BinOp(left, _, right) => { + self.collect_free_vars_expr(left, lambda_params, free_vars, local_scope); + self.collect_free_vars_expr(right, lambda_params, free_vars, local_scope); + } + ExprKind::UnOp(_, operand) => { + self.collect_free_vars_expr(operand, lambda_params, free_vars, local_scope); + } + ExprKind::Assign(target, value) => { + self.collect_free_vars_expr(target, lambda_params, free_vars, local_scope); + self.collect_free_vars_expr(value, lambda_params, free_vars, local_scope); + } + ExprKind::Cast(operand, _) => { + self.collect_free_vars_expr(operand, lambda_params, free_vars, local_scope); + } + ExprKind::Index(obj, index) => { + self.collect_free_vars_expr(obj, lambda_params, free_vars, local_scope); + self.collect_free_vars_expr(index, lambda_params, free_vars, local_scope); + } + ExprKind::Dot(obj, _) => { + self.collect_free_vars_expr(obj, lambda_params, free_vars, local_scope); + } + ExprKind::EarlyReturn(expr) => { + if let Some(expr) = expr { + self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope); + } + } + ExprKind::OptionalChain(obj, _) => { + if let Some(obj) = obj { + self.collect_free_vars_expr(obj, lambda_params, free_vars, local_scope); + } + } + ExprKind::Return(expr) => { + if let Some(expr) = expr { + self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope); + } + } + ExprKind::Array(exprs) => { + for expr in exprs { + self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope); + } + } + ExprKind::Tuple(exprs) => { + for expr in exprs { + self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope); + } + } + ExprKind::StructLit(_, fields) => { + for (_, expr) in fields { + self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope); + } + } + ExprKind::EnumLit(_, _, args) => { + for arg in args { + self.collect_free_vars_expr(arg, lambda_params, free_vars, local_scope); + } + } + ExprKind::Range(start, end) => { + self.collect_free_vars_expr(start, lambda_params, free_vars, local_scope); + self.collect_free_vars_expr(end, lambda_params, free_vars, local_scope); + } + // Terminal expressions don't contain variables + ExprKind::Int(_) + | ExprKind::Float(_) + | ExprKind::Bool(_) + | ExprKind::String(_) + | ExprKind::Break + | ExprKind::Continue => {} + } + } + + /// Lower all lambdas in a program by hoisting them to functions + pub fn lower_program(&self, nodes: &[ASTNode]) -> Result, String> { + let mut lowered_nodes = Vec::new(); + + // Process each top-level node + for node in nodes { + let lowered = self.lower_node(node)?; + lowered_nodes.push(lowered); + } + + // Add all generated lambda functions to the end + let generated = self.generated_functions.borrow(); + lowered_nodes.extend(generated.iter().cloned()); + + Ok(lowered_nodes) + } + + fn lower_node(&self, node: &ASTNode) -> Result { + let new_kind = match &node.kind { + ASTNodeKind::Function(func) => { + let lowered_body = self.lower_expr(&func.body)?; + ASTNodeKind::Function(Function { + name: func.name.clone(), + parameters: func.parameters.clone(), + args: func.args.clone(), + return_type: func.return_type.clone(), + body: lowered_body, + }) + } + other => other.clone(), + }; + + Ok(ASTNode { + kind: new_kind, + span: node.span.clone(), + attributes: node.attributes.clone(), + }) + } + + fn lower_expr(&self, expr: &Expr) -> Result { + let new_kind = match &expr.kind { + ExprKind::Lambda(args, body) => { + // Collect free variables (captured variables) + let lambda_params: Vec = + args.iter().map(|(name, _)| name.clone()).collect(); + let free_vars = self.collect_free_vars(body, &lambda_params); + + if free_vars.is_empty() { + // No captures - hoist to function like the original implementation + let lambda_id = { + let mut counter = self.lambda_counter.borrow_mut(); + *counter += 1; + *counter + }; + let lambda_name = format!("__suic_gen_lambda_{}", lambda_id); + + // Lower the lambda body recursively + let lowered_body = self.lower_expr(body)?; + + // Create a new function for this lambda + let lambda_func = ASTNode { + kind: ASTNodeKind::Function(Function { + name: lambda_name.clone(), + parameters: Vec::new(), // No type parameters for now + args: args.clone(), + return_type: None, // Let typechecker infer return type + body: lowered_body, + }), + span: expr.span.clone(), + attributes: Vec::new(), + }; + + // Store the generated function + self.generated_functions.borrow_mut().push(lambda_func); + + // Replace the lambda with a reference to the generated function + ExprKind::Variable(lambda_name) + } else { + // Has captures - keep as lambda, but recursively lower the body + let lowered_body = self.lower_expr(body)?; + ExprKind::Lambda(args.clone(), Box::new(lowered_body)) + } + } + ExprKind::Call(func, args) => { + let lowered_func = self.lower_expr(func)?; + let lowered_args = args + .iter() + .map(|arg| self.lower_expr(arg)) + .collect::, _>>()?; + ExprKind::Call(Box::new(lowered_func), lowered_args) + } + ExprKind::Let(name, kind, type_annot, body) => { + let lowered_body = self.lower_expr(body)?; + ExprKind::Let( + name.clone(), + kind.clone(), + type_annot.clone(), + Box::new(lowered_body), + ) + } + ExprKind::If(cond, then_expr, else_expr) => { + let lowered_cond = self.lower_expr(cond)?; + let lowered_then = self.lower_expr(then_expr)?; + let lowered_else = else_expr.as_ref().map(|e| self.lower_expr(e)).transpose()?; + ExprKind::If( + Box::new(lowered_cond), + Box::new(lowered_then), + lowered_else.map(Box::new), + ) + } + ExprKind::Match(scrutinee, arms) => { + let lowered_scrutinee = self.lower_expr(scrutinee)?; + let mut lowered_arms = Vec::new(); + for (pattern, expr) in arms { + let lowered_expr = self.lower_expr(expr)?; + lowered_arms.push((pattern.clone(), lowered_expr)); + } + ExprKind::Match(Box::new(lowered_scrutinee), lowered_arms) + } + ExprKind::While(cond, body) => { + let lowered_cond = self.lower_expr(cond)?; + let lowered_body = self.lower_expr(body)?; + ExprKind::While(Box::new(lowered_cond), Box::new(lowered_body)) + } + ExprKind::For(var, iter, body) => { + let lowered_iter = self.lower_expr(iter)?; + let lowered_body = self.lower_expr(body)?; + ExprKind::For(var.clone(), Box::new(lowered_iter), Box::new(lowered_body)) + } + ExprKind::Do(exprs) => { + let lowered_exprs = exprs + .iter() + .map(|e| self.lower_expr(e)) + .collect::, _>>()?; + ExprKind::Do(lowered_exprs) + } + ExprKind::BinOp(left, op, right) => { + let lowered_left = self.lower_expr(left)?; + let lowered_right = self.lower_expr(right)?; + ExprKind::BinOp(Box::new(lowered_left), op.clone(), Box::new(lowered_right)) + } + ExprKind::UnOp(op, operand) => { + let lowered_operand = self.lower_expr(operand)?; + ExprKind::UnOp(op.clone(), Box::new(lowered_operand)) + } + ExprKind::Assign(target, value) => { + let lowered_target = self.lower_expr(target)?; + let lowered_value = self.lower_expr(value)?; + ExprKind::Assign(Box::new(lowered_target), Box::new(lowered_value)) + } + ExprKind::Cast(operand, type_annot) => { + let lowered_operand = self.lower_expr(operand)?; + ExprKind::Cast(Box::new(lowered_operand), type_annot.clone()) + } + ExprKind::Index(obj, index) => { + let lowered_obj = self.lower_expr(obj)?; + let lowered_index = self.lower_expr(index)?; + ExprKind::Index(Box::new(lowered_obj), Box::new(lowered_index)) + } + ExprKind::Dot(obj, field) => { + let lowered_obj = self.lower_expr(obj)?; + ExprKind::Dot(Box::new(lowered_obj), field.clone()) + } + ExprKind::EarlyReturn(expr) => { + let lowered_expr = expr.as_ref().map(|e| self.lower_expr(e)).transpose()?; + ExprKind::EarlyReturn(lowered_expr.map(Box::new)) + } + ExprKind::OptionalChain(obj, field) => { + let lowered_obj = obj.as_ref().map(|e| self.lower_expr(e)).transpose()?; + ExprKind::OptionalChain(lowered_obj.map(Box::new), field.clone()) + } + ExprKind::Return(expr) => { + let lowered_expr = expr.as_ref().map(|e| self.lower_expr(e)).transpose()?; + ExprKind::Return(lowered_expr.map(Box::new)) + } + ExprKind::Array(exprs) => { + let lowered_exprs = exprs + .iter() + .map(|e| self.lower_expr(e)) + .collect::, _>>()?; + ExprKind::Array(lowered_exprs) + } + ExprKind::Tuple(exprs) => { + let lowered_exprs = exprs + .iter() + .map(|e| self.lower_expr(e)) + .collect::, _>>()?; + ExprKind::Tuple(lowered_exprs) + } + ExprKind::StructLit(name, fields) => { + let mut lowered_fields = Vec::new(); + for (field_name, field_expr) in fields { + let lowered_expr = self.lower_expr(field_expr)?; + lowered_fields.push((field_name.clone(), lowered_expr)); + } + ExprKind::StructLit(name.clone(), lowered_fields) + } + ExprKind::EnumLit(enum_name, variant, args) => { + let lowered_args = args + .iter() + .map(|arg| self.lower_expr(arg)) + .collect::, _>>()?; + ExprKind::EnumLit(enum_name.clone(), variant.clone(), lowered_args) + } + ExprKind::Range(start, end) => { + let lowered_start = self.lower_expr(start)?; + let lowered_end = self.lower_expr(end)?; + ExprKind::Range(Box::new(lowered_start), Box::new(lowered_end)) + } + // Terminal expressions that don't contain other expressions + ExprKind::Int(_) + | ExprKind::Float(_) + | ExprKind::Bool(_) + | ExprKind::String(_) + | ExprKind::Variable(_) + | ExprKind::Break + | ExprKind::Continue => expr.kind.clone(), + }; + + Ok(Expr { + kind: new_kind, + span: expr.span.clone(), + attributes: expr.attributes.clone(), + }) + } +} + +``` + +```rust +// src/parser.rs +use crate::ast::*; +use crate::lexer::Token; + +use std::iter::Peekable; +use std::ops::Range; +use std::vec::IntoIter; + +type TokenIter = Peekable)>>; + +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)>) -> Self { + Parser { + file, + tokens: tokens.into_iter().peekable(), + } + } + + // Parse the entire file into a list of AST nodes + pub fn parse(&mut self) -> Result, 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> { + self.tokens.peek().map(|(_, span)| span.clone()) + } + + fn next(&mut self) -> Option<(Token, Range)> { + self.tokens.next() + } + + fn expect(&mut self, expected: Token) -> Result, ParseError> { + match self.next() { + Some((token, span)) + if std::mem::discriminant(&token) == std::mem::discriminant(&expected) => + { + Ok(span) + } + Some((token, span)) => Err(ParseError { + message: self.expect_error_message(&expected, &token), + span: Span::new(&span, self.file.clone()), + }), + None => Err(ParseError { + message: self.expect_error_message(&expected, &Token::Variable("EOF".to_string())), + span: Span::new(&(0..0), self.file.clone()), + }), + } + } + + fn expect_error_message(&self, expected: &Token, found: &Token) -> String { + match expected { + Token::LParen => format!( + "Expected '(' to start parameter list or grouping. Found {:?}", + found + ), + Token::RParen => format!( + "Expected ')' to close parameter list or grouping. Found {:?}", + found + ), + Token::LBrace => format!( + "Expected '{{' to start block or struct literal. Found {:?}", + found + ), + Token::RBrace => format!( + "Expected '}}' to close block or struct literal. Found {:?}", + found + ), + Token::LBracket => format!("Expected '[' to start array literal. Found {:?}", found), + Token::RBracket => format!("Expected ']' to close array literal. Found {:?}", found), + Token::Colon => format!( + "Expected ':' for type annotation or struct field. Found {:?}", + found + ), + Token::Semicolon => format!("Expected ';' to end statement. Found {:?}", found), + Token::Comma => format!("Expected ',' to separate items. Found {:?}", found), + Token::Arrow => format!("Expected '->' for function return type. Found {:?}", found), + Token::Assign => format!( + "Expected '=' for assignment or initialization. Found {:?}", + found + ), + Token::KeywordEnd => format!("Expected 'end' to close block. Found {:?}", found), + _ => format!("Expected {:?}, found {:?}", expected, found), + } + } + + fn error(&self, msg: String, span: Range) -> Result { + Err(ParseError { + message: msg, + span: Span::new(&span, self.file.clone()), + }) + } + + fn parse_top_level(&mut self) -> Result { + 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 library path after 'use'. Example: use \"std/io\"".to_string(), span); + } + None => { + 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; + 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: {:?}. Expected declarations like 'fn', 'struct', 'enum', 'impl', 'trait', 'use', 'load', or 'extern'", token), span) + } + None => self.error("Unexpected end of file at top level. Expected declarations like 'fn', 'struct', 'enum', etc.".to_string(), start..start), + } + } + + fn parse_attribute(&mut self) -> Result { + 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 after '@'. Example: @deprecated".to_string(), + span, + ); + } + None => { + return self.error( + "Expected attribute name after '@'. Example: @deprecated".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 attribute value after '='. Example: @version = \"1.0\"".to_string(), span); + } + None => { + return self + .error("Expected attribute value after '='. Example: @version = \"1.0\"".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. Examples: \"value\", key = \"value\", or just key".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 ',' to separate arguments or ')' to close attribute. Example: @deprecated(\"old\", reason = \"use new\")".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 { + 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 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 + 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. 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)) { + 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 ',' between arguments or ')' to close parameter list. Example: fn add(x: int, y: int)".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 { + 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 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 + 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. 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)?; + 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 { + 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 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 + 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. 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(); + 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 { + let start = self.peek_span().unwrap_or(0..0).start; + + // Parse impl target as a type (could be generic like Option) + 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. 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 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(); + 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 { + 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 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 + 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 { + 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 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) + 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 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; + Ok(Extern { + name, + args, + return_type, + from, + span: Span::new(&(start..end), self.file.clone()), + }) + } + + fn parse_load(&mut self) -> Result { + 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 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 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; + Ok(Load { + library, + alias, + span: Span::new(&(start..end), self.file.clone()), + }) + } + + fn parse_parameters(&mut self) -> Result, 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 type parameter name. Example: ".to_string(), + span, + ); + } + None => { + return self.error( + "Expected type parameter name. Example: ".to_string(), + start..start, + ); + } + }; + + let bounds = if matches!(self.peek(), Some(Token::Colon)) { + 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, 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 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)) { + break; + } + self.next(); + } + + Ok(bounds) + } + + fn parse_kind(&mut self) -> Result { + 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 { + let start = self.peek_span().unwrap_or(0..0).start; + + // Check for pointer type: *T + if matches!(self.peek(), Some(Token::Mul)) { + self.next(); + let inner = self.parse_type_annot()?; + return Ok(TypeAnnot::Ptr(Box::new(inner))); + } + + // 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. Examples: int, string, bool, MyStruct, Option" + .to_string(), + span, + ); + } + None => { + return self.error( + "Expected type name. Examples: int, string, bool, MyStruct, Option" + .to_string(), + start..start, + ); + } + }; + + // Parse type arguments if present + 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. Example: Vec, HashMap" + .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 { + 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 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)?; + 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 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)) { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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(), + }) + } + Some(Token::Amp) => { + self.next(); + let expr = self.parse_unary_expr()?; + let end = expr.span.end; + Ok(Expr { + kind: ExprKind::UnOp(UnOp::Ref, Box::new(expr)), + span: Span::new(&(start..end), self.file.clone()), + attributes: Vec::new(), + }) + } + Some(Token::Mul) => { + self.next(); + let expr = self.parse_unary_expr()?; + let end = expr.span.end; + Ok(Expr { + kind: ExprKind::UnOp(UnOp::Deref, 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 { + 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 in struct pattern. Example: Point { x: 5, y: 10 }".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 in struct pattern. Example: Point { x: 5, y: 10 }".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 { + 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 in struct pattern. Example: Point { x: 5, y: 10 }".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 in enum pattern. Example: Result::Ok(value) or Color::Red()".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 after 'let'. Example: let x = 5; or let mut y = 10;".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), + }; + + // 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 in for loop. Example: for item in collection { ... }".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 in lambda. Example: lambda(x, y) { x + y }".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 in pattern: {:?}. Expected variable names, struct patterns like Struct {{ field }}, or enum patterns like Enum::Variant", token), span) + } + None => self.error( + "Unexpected end of file in pattern. Expected a complete pattern.".to_string(), + start..start, + ), + } + } + + fn parse_pattern(&mut self) -> Result { + 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 in struct pattern. Example: Point { x: 5, y: 10 }".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 in enum pattern. Example: Result::Ok(value) or Color::Red()".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 expression: {:?}. Expected literals, variables, or keywords like 'let', 'if', etc.", token), span) + } + None => self.error( + "Unexpected end of file in expression. Expected a complete expression.".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) + ) + } +} + +``` + +```rust +// src/typechecker.rs +// src/typechecker.rs +use crate::ast::*; +use std::collections::HashMap; +use std::fmt; + +#[derive(Debug, Clone, PartialEq)] +pub enum Type { + Int, + Float, + Bool, + String, + Unit, + Never, + Array(Box), + Ptr(Box), + Tuple(Vec), + Function(Vec, Box), + Struct(String, Vec), // name and type arguments + Enum(String, Vec), + TypeVar(String), + Generic(String, Vec), // Generic type constructor + Unknown, // For type inference +} + +impl Type { + pub fn to_string(&self) -> String { + match self { + Type::Int => "int".to_string(), + Type::Float => "float".to_string(), + Type::Bool => "bool".to_string(), + Type::String => "string".to_string(), + Type::Unit => "()".to_string(), + Type::Never => "!".to_string(), + Type::Array(inner) => format!("[{}]", inner.to_string()), + Type::Ptr(inner) => format!("*{}", inner.to_string()), + Type::Tuple(types) => { + let type_strs: Vec = types.iter().map(|t| t.to_string()).collect(); + format!("({})", type_strs.join(", ")) + } + Type::Function(args, ret) => { + let arg_strs: Vec = args.iter().map(|t| t.to_string()).collect(); + format!("fn({}) -> {}", arg_strs.join(", "), ret.to_string()) + } + Type::Struct(name, args) if args.is_empty() => name.clone(), + Type::Struct(name, args) => { + let arg_strs: Vec = args.iter().map(|t| t.to_string()).collect(); + format!("{}<{}>", name, arg_strs.join(", ")) + } + Type::Enum(name, args) if args.is_empty() => name.clone(), + Type::Enum(name, args) => { + let arg_strs: Vec = args.iter().map(|t| t.to_string()).collect(); + format!("{}<{}>", name, arg_strs.join(", ")) + } + Type::TypeVar(name) => name.clone(), + Type::Generic(name, args) => { + let arg_strs: Vec = args.iter().map(|t| t.to_string()).collect(); + format!("{}<{}>", name, arg_strs.join(", ")) + } + Type::Unknown => "?".to_string(), + } + } +} + +#[derive(Debug)] +pub struct TypeError { + pub kind: TypeErrorKind, + pub span: Span, +} + +#[derive(Debug)] +pub enum TypeErrorKind { + TypeMismatch(Type, Type), + UndefinedVariable(String), + UndefinedType(String), + UndefinedFunction(String), + UndefinedField(String, Type), + UndefinedVariant(String, String), + ArityMismatch(usize, usize), + NotAFunction(Type), + NotAnArray(Type), + NotAStruct(Type), + NotAnEnum(Type), + InvalidCast(Type, Type), + InvalidPattern(String), + MutableityError(String), + LinearityError(String), + Other(String), +} + +impl fmt::Display for TypeErrorKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TypeErrorKind::TypeMismatch(expected, actual) => { + write!( + f, + "Type mismatch: expected {}, found {}", + expected.to_string(), + actual.to_string() + ) + } + TypeErrorKind::UndefinedVariable(name) => { + write!(f, "Undefined variable '{}'", name) + } + TypeErrorKind::UndefinedType(name) => { + write!(f, "Undefined type '{}'", name) + } + TypeErrorKind::UndefinedFunction(name) => { + write!(f, "Undefined function '{}'", name) + } + TypeErrorKind::UndefinedField(field, ty) => { + write!(f, "Undefined field '{}' on type {}", field, ty.to_string()) + } + TypeErrorKind::UndefinedVariant(enum_name, variant) => { + write!(f, "Undefined variant '{}' in enum '{}'", variant, enum_name) + } + TypeErrorKind::ArityMismatch(expected, actual) => { + write!( + f, + "Function expects {} arguments, but {} were provided", + expected, actual + ) + } + TypeErrorKind::NotAFunction(ty) => { + write!(f, "Expected a function, but found {}", ty.to_string()) + } + TypeErrorKind::NotAnArray(ty) => { + write!(f, "Expected an array, but found {}", ty.to_string()) + } + TypeErrorKind::NotAStruct(ty) => { + write!(f, "Expected a struct, but found {}", ty.to_string()) + } + TypeErrorKind::NotAnEnum(ty) => { + write!(f, "Expected an enum, but found {}", ty.to_string()) + } + TypeErrorKind::InvalidCast(from, to) => { + write!( + f, + "Invalid cast from {} to {}", + from.to_string(), + to.to_string() + ) + } + TypeErrorKind::InvalidPattern(msg) => { + write!(f, "Invalid pattern: {}", msg) + } + TypeErrorKind::MutableityError(msg) => { + write!(f, "Mutability error: {}", msg) + } + TypeErrorKind::LinearityError(msg) => { + write!(f, "Linearity error: {}", msg) + } + TypeErrorKind::Other(msg) => { + write!(f, "{}", msg) + } + } + } +} + +#[derive(Clone)] +struct VarInfo { + ty: Type, + kind: BindingKind, + name: String, + usage: usize, + span: Span, +} + +#[derive(Clone)] +struct TypeEnv { + vars: HashMap, + name_to_id: HashMap, + types: HashMap, + functions: HashMap, + traits: HashMap, + impls: Vec, + type_vars: HashMap, + scopes: Vec>, +} + +#[derive(Clone, Debug)] +struct TypeInfo { + kind: TypeInfoKind, + parameters: Vec, +} + +#[derive(Clone, Debug)] +enum TypeInfoKind { + Struct(Vec<(String, TypeAnnot)>), + Enum(Vec<(String, Vec)>), +} + +#[derive(Clone, Debug)] +struct FunctionType { + type_params: Vec, + params: Vec, + return_type: Type, +} + +#[derive(Clone, Debug)] +struct TraitInfo { + methods: HashMap, + parameters: Vec, +} + +#[derive(Clone, Debug)] +struct ImplInfo { + target: String, + trait_name: Option, + methods: HashMap, +} + +impl TypeEnv { + fn new() -> Self { + TypeEnv { + vars: HashMap::new(), + name_to_id: HashMap::new(), + types: HashMap::new(), + functions: HashMap::new(), + traits: HashMap::new(), + impls: Vec::new(), + type_vars: HashMap::new(), + scopes: Vec::new(), + } + } + + fn enter_scope(&mut self) { + self.scopes.push(Vec::new()); + } + + fn exit_scope(&mut self) -> Result<(), TypeError> { + if let Some(scope) = self.scopes.pop() { + for &id in &scope { + if let Some(var_info) = self.vars.get(&id) { + match var_info.kind { + BindingKind::Linear => { + if var_info.usage != 1 { + return Err(TypeError { + kind: TypeErrorKind::LinearityError(format!( + "Linear variable '{}' used {} times, must be exactly 1", + var_info.name, var_info.usage + )), + span: var_info.span.clone(), + }); + } + } + BindingKind::Affine => { + if var_info.usage > 1 { + return Err(TypeError { + kind: TypeErrorKind::LinearityError(format!( + "Affine variable '{}' used {} times, must be at most 1", + var_info.name, var_info.usage + )), + span: var_info.span.clone(), + }); + } + } + _ => {} + } + let name = var_info.name.clone(); + self.vars.remove(&id); + self.name_to_id.remove(&name); + } + } + } + Ok(()) + } + + fn add_var( + &mut self, + id: crate::ast::BindingId, + name: String, + ty: Type, + kind: BindingKind, + span: Span, + ) { + let var_info = VarInfo { + ty, + kind, + name: name.clone(), + usage: 0, + span, + }; + self.vars.insert(id, var_info); + if let Some(current) = self.scopes.last_mut() { + current.push(id); + } + self.name_to_id.insert(name, id); + } + + fn get_var(&self, id: &crate::ast::BindingId) -> Option<&VarInfo> { + self.vars.get(id) + } + + fn get_var_by_name(&self, name: &str) -> Option<(crate::ast::BindingId, &VarInfo)> { + if let Some(id) = self.name_to_id.get(name) { + if let Some(var_info) = self.vars.get(id) { + Some((*id, var_info)) + } else { + None + } + } else { + None + } + } + + fn increment_usage(&mut self, id: &crate::ast::BindingId) { + if let Some(var_info) = self.vars.get_mut(id) { + var_info.usage += 1; + } + } + + fn add_type(&mut self, name: String, info: TypeInfo) { + self.types.insert(name, info); + } + + fn get_type(&self, name: &str) -> Option<&TypeInfo> { + self.types.get(name) + } + + fn add_function(&mut self, name: String, ty: FunctionType) { + self.functions.insert(name, ty); + } + + fn get_function(&self, name: &str) -> Option<&FunctionType> { + self.functions.get(name) + } +} + +pub struct TypeChecker { + env: TypeEnv, + binding_id_counter: usize, +} + +impl TypeChecker { + pub fn new() -> Self { + TypeChecker { + env: TypeEnv::new(), + binding_id_counter: 0, + } + } + + fn next_binding_id(&mut self) -> crate::ast::BindingId { + let id = crate::ast::BindingId(self.binding_id_counter); + self.binding_id_counter += 1; + id + } + + pub fn typecheck_program(&mut self, nodes: &[ASTNode]) -> Result, TypeError> { + // First pass: collect all type definitions, function signatures, etc. + for node in nodes { + self.collect_definitions(node)?; + } + + // Second pass: typecheck everything + self.env.enter_scope(); + let mut typed_nodes = Vec::new(); + for node in nodes { + typed_nodes.push(self.typecheck_node(node)?); + } + self.env.exit_scope()?; + + Ok(typed_nodes) + } + + fn collect_definitions(&mut self, node: &ASTNode) -> Result<(), TypeError> { + match &node.kind { + ASTNodeKind::Struct(s) => { + let info = TypeInfo { + kind: TypeInfoKind::Struct( + s.fields + .iter() + .map(|f| (f.name.clone(), f.field_type.clone())) + .collect(), + ), + parameters: s.parameters.iter().map(|p| p.name.clone()).collect(), + }; + self.env.add_type(s.name.clone(), info); + } + ASTNodeKind::Enum(e) => { + let info = TypeInfo { + kind: TypeInfoKind::Enum( + e.variants + .iter() + .map(|v| (v.name.clone(), v.fields.clone())) + .collect(), + ), + parameters: e.parameters.iter().map(|p| p.name.clone()).collect(), + }; + self.env.add_type(e.name.clone(), info); + } + ASTNodeKind::Function(f) => { + let param_types: Vec = f + .args + .iter() + .map(|(_, ty)| { + ty.as_ref() + .map(|t| self.type_annot_to_type(t)) + .unwrap_or(Type::Unknown) + }) + .collect(); + let return_type = f + .return_type + .as_ref() + .map(|t| self.type_annot_to_type(t)) + .unwrap_or_else(|| { + if f.name.starts_with("__suic_gen_lambda_") { + Type::Unknown + } else { + Type::Unit + } + }); + + let func_type = FunctionType { + type_params: f.parameters.iter().map(|p| p.name.clone()).collect(), + params: param_types, + return_type, + }; + self.env.add_function(f.name.clone(), func_type); + } + ASTNodeKind::Trait(t) => { + let mut methods = HashMap::new(); + for sig in &t.methods { + let param_types: Vec = sig.params.iter().map(|_| Type::Unknown).collect(); + let return_type = self.type_annot_to_type(&sig.return_type); + methods.insert( + sig.name.clone(), + FunctionType { + type_params: Vec::new(), + params: param_types, + return_type, + }, + ); + } + let trait_info = TraitInfo { + methods, + parameters: t.parameters.iter().map(|p| p.name.clone()).collect(), + }; + self.env.traits.insert(t.name.clone(), trait_info); + } + ASTNodeKind::Impl(impl_def) => { + let mut methods = HashMap::new(); + for method in &impl_def.methods { + let param_types: Vec = method + .args + .iter() + .map(|(_, ty)| { + ty.as_ref() + .map(|t| self.type_annot_to_type(t)) + .unwrap_or(Type::Unknown) + }) + .collect(); + let return_type = method + .return_type + .as_ref() + .map(|t| self.type_annot_to_type(t)) + .unwrap_or(Type::Unit); + + methods.insert( + method.name.clone(), + FunctionType { + type_params: method.parameters.iter().map(|p| p.name.clone()).collect(), + params: param_types, + return_type, + }, + ); + } + self.env.impls.push(ImplInfo { + target: impl_def.target.clone(), + trait_name: impl_def.trait_name.clone(), + methods, + }); + } + _ => {} + } + Ok(()) + } + + fn typecheck_node(&mut self, node: &ASTNode) -> Result { + let ty = match &node.kind { + ASTNodeKind::Function(f) => { + let typed_func = self.typecheck_function(f)?; + let ty = typed_func.ty.clone(); + return Ok(TypedASTNode { + kind: TypedASTNodeKind::Function(typed_func), + span: node.span.clone(), + attributes: node.attributes.clone(), + ty, + }); + } + ASTNodeKind::Struct(s) => { + // Return the typed struct + return Ok(TypedASTNode { + kind: TypedASTNodeKind::Struct(TypedStruct { + name: s.name.clone(), + parameters: s.parameters.clone(), + fields: s + .fields + .iter() + .map(|f| TypedField { + name: f.name.clone(), + field_type: f.field_type.clone(), + span: f.span.clone(), + }) + .collect(), + }), + span: node.span.clone(), + attributes: node.attributes.clone(), + ty: Type::Unit, + }); + } + ASTNodeKind::Enum(e) => { + // Return the typed enum + return Ok(TypedASTNode { + kind: TypedASTNodeKind::Enum(TypedEnum { + name: e.name.clone(), + parameters: e.parameters.clone(), + variants: e + .variants + .iter() + .map(|v| TypedVariant { + name: v.name.clone(), + fields: v.fields.clone(), + span: v.span.clone(), + }) + .collect(), + }), + span: node.span.clone(), + attributes: node.attributes.clone(), + ty: Type::Unit, + }); + } + ASTNodeKind::Trait(t) => { + // Return the typed trait + return Ok(TypedASTNode { + kind: TypedASTNodeKind::Trait(TypedTrait { + name: t.name.clone(), + methods: t.methods.clone(), + parameters: t.parameters.clone(), + associated_types: t.associated_types.clone(), + }), + span: node.span.clone(), + attributes: node.attributes.clone(), + ty: Type::Unit, + }); + } + ASTNodeKind::Impl(impl_def) => { + let mut typed_methods = Vec::new(); + for method in &impl_def.methods { + let mut method_clone = method.clone(); + if !method_clone.args.is_empty() + && method_clone.args[0].0 == "self" + && method_clone.args[0].1.is_none() + { + method_clone.args[0].1 = + Some(TypeAnnot::Cons(impl_def.target.clone(), vec![])); + } + typed_methods.push(self.typecheck_function(&method_clone)?); + } + return Ok(TypedASTNode { + kind: TypedASTNodeKind::Impl(TypedImpl { + target: impl_def.target.clone(), + trait_name: impl_def.trait_name.clone(), + methods: typed_methods, + }), + span: node.span.clone(), + attributes: node.attributes.clone(), + ty: Type::Unit, + }); + } + ASTNodeKind::Extern(ext) => { + return Ok(TypedASTNode { + kind: TypedASTNodeKind::Extern(TypedExtern { + name: ext.name.clone(), + args: ext.args.clone(), + return_type: ext.return_type.clone(), + from: ext.from.clone(), + span: ext.span.clone(), + }), + span: node.span.clone(), + attributes: node.attributes.clone(), + ty: Type::Unit, + }); + } + ASTNodeKind::Load(load) => { + return Ok(TypedASTNode { + kind: TypedASTNodeKind::Load(TypedLoad { + library: load.library.clone(), + alias: load.alias.clone(), + span: load.span.clone(), + }), + span: node.span.clone(), + attributes: node.attributes.clone(), + ty: Type::Unit, + }); + } + ASTNodeKind::Use(path) => Type::Unit, + }; + + Ok(TypedASTNode { + kind: TypedASTNodeKind::Use(match &node.kind { + ASTNodeKind::Use(p) => p.clone(), + _ => String::new(), + }), + span: node.span.clone(), + attributes: node.attributes.clone(), + ty, + }) + } + + fn typecheck_function(&mut self, func: &Function) -> Result { + // Enter new scope for function + self.env.enter_scope(); + + // Add type parameters to environment + for param in &func.parameters { + self.env + .type_vars + .insert(param.name.clone(), Type::TypeVar(param.name.clone())); + } + + // Add function parameters to environment + let mut param_types = Vec::new(); + let mut typed_args = Vec::new(); + for (arg_name, arg_type_annot) in &func.args { + let arg_id = self.next_binding_id(); + let arg_type = arg_type_annot + .as_ref() + .map(|t| self.type_annot_to_type(t)) + .unwrap_or(Type::Unknown); + param_types.push(arg_type.clone()); + self.env.add_var( + arg_id, + arg_name.clone(), + arg_type, + BindingKind::Default, + func.body.span.clone(), + ); + typed_args.push((arg_id, arg_name.clone(), arg_type_annot.clone())); + } + + // Typecheck function body + let typed_body = self.typecheck_expr(&func.body)?; + + // Exit scope, checking usages + self.env.exit_scope()?; + + // Check return type + let expected_return = + if func.name.starts_with("__suic_gen_lambda_") && func.return_type.is_none() { + // For generated lambda functions, infer return type from body + typed_body.ty.clone() + } else { + func.return_type + .as_ref() + .map(|t| self.type_annot_to_type(t)) + .unwrap_or(Type::Unit) + }; + + if !self.types_compatible(&typed_body.ty, &expected_return) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch(expected_return, typed_body.ty), + span: func.body.span.clone(), + }); + } + + let func_type = Type::Function(param_types, Box::new(expected_return)); + + Ok(TypedFunction { + name: func.name.clone(), + parameters: func.parameters.clone(), + args: typed_args, + return_type: func.return_type.clone(), + body: typed_body, + ty: func_type, + }) + } + + fn typecheck_expr(&mut self, expr: &Expr) -> Result { + let (kind, ty) = match &expr.kind { + ExprKind::Int(n) => (TypedExprKind::Int(*n), Type::Int), + ExprKind::Float(f) => (TypedExprKind::Float(*f), Type::Float), + ExprKind::Bool(b) => (TypedExprKind::Bool(*b), Type::Bool), + ExprKind::String(s) => (TypedExprKind::String(s.clone()), Type::String), + + ExprKind::Variable(name) => { + // First check if it's a variable + if let Some((id, var_info)) = self.env.get_var_by_name(name) { + let ty = var_info.ty.clone(); + self.env.increment_usage(&id); + (TypedExprKind::Variable(name.clone()), ty) + } else if let Some(func_type) = self.env.get_function(name) { + // If not a variable, check if it's a function + let func_type_clone = func_type.clone(); + let fn_type = Type::Function( + func_type_clone.params, + Box::new(func_type_clone.return_type), + ); + (TypedExprKind::Variable(name.clone()), fn_type) + } else { + return Err(TypeError { + kind: TypeErrorKind::UndefinedVariable(name.clone()), + span: expr.span.clone(), + }); + } + } + + ExprKind::Array(elements) => { + let mut typed_elements = Vec::new(); + let mut element_type = Type::Unknown; + + for (i, elem) in elements.iter().enumerate() { + let typed_elem = self.typecheck_expr(elem)?; + if i == 0 { + element_type = typed_elem.ty.clone(); + } else if !self.types_compatible(&typed_elem.ty, &element_type) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch(element_type, typed_elem.ty), + span: elem.span.clone(), + }); + } + typed_elements.push(typed_elem); + } + + if elements.is_empty() { + element_type = Type::Unknown; + } + + ( + TypedExprKind::Array(typed_elements), + Type::Array(Box::new(element_type)), + ) + } + + ExprKind::Tuple(elements) => { + let mut typed_elements = Vec::new(); + let mut types = Vec::new(); + + for elem in elements { + let typed_elem = self.typecheck_expr(elem)?; + types.push(typed_elem.ty.clone()); + typed_elements.push(typed_elem); + } + + (TypedExprKind::Tuple(typed_elements), Type::Tuple(types)) + } + + ExprKind::BinOp(left, op, right) => { + let typed_left = self.typecheck_expr(left)?; + let typed_right = self.typecheck_expr(right)?; + + let result_type = match op { + BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Mod => { + if !self.types_compatible(&typed_left.ty, &typed_right.ty) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch( + typed_left.ty.clone(), + typed_right.ty.clone(), + ), + span: right.span.clone(), + }); + } + typed_left.ty.clone() + } + BinOp::Eq | BinOp::Neq | BinOp::Lt | BinOp::Gt | BinOp::Leq | BinOp::Geq => { + Type::Bool + } + BinOp::And | BinOp::Or => { + if !matches!(typed_left.ty, Type::Bool) + || !matches!(typed_right.ty, Type::Bool) + { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch( + Type::Bool, + typed_right.ty.clone(), + ), + span: expr.span.clone(), + }); + } + Type::Bool + } + }; + + ( + TypedExprKind::BinOp(Box::new(typed_left), op.clone(), Box::new(typed_right)), + result_type, + ) + } + + ExprKind::UnOp(op, inner) => { + let typed_inner = self.typecheck_expr(inner)?; + let result_type = match op { + UnOp::Neg => { + if !matches!(typed_inner.ty, Type::Int | Type::Float) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch( + Type::Int, + typed_inner.ty.clone(), + ), + span: inner.span.clone(), + }); + } + typed_inner.ty.clone() + } + UnOp::Not => { + if !matches!(typed_inner.ty, Type::Bool) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch( + Type::Bool, + typed_inner.ty.clone(), + ), + span: inner.span.clone(), + }); + } + Type::Bool + } + UnOp::Ref => { + // &expr creates a pointer to expr + Type::Ptr(Box::new(typed_inner.ty.clone())) + } + UnOp::Deref => { + // *expr dereferences a pointer + match &typed_inner.ty { + Type::Ptr(inner_ty) => (**inner_ty).clone(), + _ => { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch( + Type::Ptr(Box::new(Type::Unknown)), + typed_inner.ty.clone(), + ), + span: inner.span.clone(), + }); + } + } + } + }; + ( + TypedExprKind::UnOp(op.clone(), Box::new(typed_inner)), + result_type, + ) + } + + ExprKind::Call(func_expr, args) => { + let (typed_func, typed_args) = if let ExprKind::Dot(_, _) = &func_expr.kind { + // Method call: insert self as first argument + let typed_method = self.typecheck_expr(func_expr)?; + let typed_obj = if let TypedExprKind::Dot(obj, _) = &typed_method.kind { + obj.as_ref().clone() + } else { + unreachable!() + }; + let mut args_with_self = vec![typed_obj]; + for arg in args { + args_with_self.push(self.typecheck_expr(arg)?); + } + (typed_method, args_with_self) + } else { + let typed_func = self.typecheck_expr(func_expr)?; + let typed_args = args + .iter() + .map(|arg| self.typecheck_expr(arg)) + .collect::, _>>()?; + (typed_func, typed_args) + }; + + let return_type = match &typed_func.ty { + Type::Function(param_types, ret) => { + if param_types.len() != typed_args.len() { + return Err(TypeError { + kind: TypeErrorKind::ArityMismatch( + param_types.len(), + typed_args.len(), + ), + span: expr.span.clone(), + }); + } + + for (i, (expected, actual)) in + param_types.iter().zip(typed_args.iter()).enumerate() + { + if !self.types_compatible(&actual.ty, expected) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch( + expected.clone(), + actual.ty.clone(), + ), + span: args + .get(i) + .map(|a| a.span.clone()) + .unwrap_or(expr.span.clone()), + }); + } + } + + (**ret).clone() + } + ty => { + return Err(TypeError { + kind: TypeErrorKind::NotAFunction(ty.clone()), + span: func_expr.span.clone(), + }); + } + }; + + ( + TypedExprKind::Call(Box::new(typed_func), typed_args), + return_type, + ) + } + + ExprKind::Let(name, binding_kind, type_annot, value) => { + let typed_value = self.typecheck_expr(value)?; + let var_type = if let Some(annot) = type_annot { + let annotated_type = self.type_annot_to_type(annot); + if !self.types_compatible(&typed_value.ty, &annotated_type) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch(annotated_type, typed_value.ty), + span: value.span.clone(), + }); + } + annotated_type + } else { + typed_value.ty.clone() + }; + + let var_id = self.next_binding_id(); + self.env.add_var( + var_id, + name.clone(), + var_type.clone(), + binding_kind.clone(), + expr.span.clone(), + ); + + ( + TypedExprKind::Let( + var_id, + name.clone(), + binding_kind.clone(), + type_annot.clone(), + Box::new(typed_value), + ), + var_type, + ) + } + + ExprKind::If(cond, then_expr, else_expr) => { + let typed_cond = self.typecheck_expr(cond)?; + if !matches!(typed_cond.ty, Type::Bool) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch(Type::Bool, typed_cond.ty), + span: cond.span.clone(), + }); + } + + let typed_then = self.typecheck_expr(then_expr)?; + let result_type = if let Some(else_expr) = else_expr { + let typed_else = self.typecheck_expr(else_expr)?; + if !self.types_compatible(&typed_then.ty, &typed_else.ty) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch(typed_then.ty.clone(), typed_else.ty), + span: else_expr.span.clone(), + }); + } + ( + TypedExprKind::If( + Box::new(typed_cond), + Box::new(typed_then.clone()), + Some(Box::new(typed_else)), + ), + typed_then.ty, + ) + } else { + ( + TypedExprKind::If(Box::new(typed_cond), Box::new(typed_then), None), + Type::Unit, + ) + }; + + result_type + } + + ExprKind::Do(exprs) => { + let mut typed_exprs = Vec::new(); + let mut last_type = Type::Unit; + + for e in exprs { + let typed_e = self.typecheck_expr(e)?; + last_type = typed_e.ty.clone(); + typed_exprs.push(typed_e); + } + + (TypedExprKind::Do(typed_exprs), last_type) + } + + ExprKind::While(cond, body) => { + let typed_cond = self.typecheck_expr(cond)?; + if !matches!(typed_cond.ty, Type::Bool) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch(Type::Bool, typed_cond.ty), + span: cond.span.clone(), + }); + } + + let typed_body = self.typecheck_expr(body)?; + ( + TypedExprKind::While(Box::new(typed_cond), Box::new(typed_body)), + Type::Unit, + ) + } + + ExprKind::For(var, iterable, body) => { + let typed_iterable = self.typecheck_expr(iterable)?; + + let element_type = match &typed_iterable.ty { + Type::Array(elem_ty) => (**elem_ty).clone(), + _ => Type::Unknown, + }; + + self.env.enter_scope(); + let var_id = self.next_binding_id(); + self.env.add_var( + var_id, + var.clone(), + element_type, + BindingKind::Default, + expr.span.clone(), + ); + + let typed_body = self.typecheck_expr(body)?; + self.env.exit_scope()?; + ( + TypedExprKind::For( + var_id, + var.clone(), + Box::new(typed_iterable), + Box::new(typed_body), + ), + Type::Unit, + ) + } + + ExprKind::Range(start, end) => { + let typed_start = self.typecheck_expr(start)?; + let typed_end = self.typecheck_expr(end)?; + + if !matches!(typed_start.ty, Type::Int) || !matches!(typed_end.ty, Type::Int) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch(Type::Int, typed_end.ty.clone()), + span: expr.span.clone(), + }); + } + + ( + TypedExprKind::Range(Box::new(typed_start), Box::new(typed_end)), + Type::Array(Box::new(Type::Int)), + ) + } + + ExprKind::Index(array, index) => { + let typed_array = self.typecheck_expr(array)?; + let typed_index = self.typecheck_expr(index)?; + + if !matches!(typed_index.ty, Type::Int) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch(Type::Int, typed_index.ty), + span: index.span.clone(), + }); + } + + let element_type = match &typed_array.ty { + Type::Array(elem_ty) => (**elem_ty).clone(), + ty => { + return Err(TypeError { + kind: TypeErrorKind::NotAnArray(ty.clone()), + span: array.span.clone(), + }); + } + }; + + ( + TypedExprKind::Index(Box::new(typed_array), Box::new(typed_index)), + element_type, + ) + } + + ExprKind::Dot(obj, field) => { + let typed_obj = self.typecheck_expr(obj)?; + + let field_type = match &typed_obj.ty { + Type::Struct(name, _) => { + if let Some(type_info) = self.env.get_type(name) { + if let TypeInfoKind::Struct(fields) = &type_info.kind { + if let Some(field_ty) = fields + .iter() + .find(|(f, _)| f == field) + .map(|(_, ty)| self.type_annot_to_type(ty)) + { + field_ty + } else { + // Check for methods in impls + let mut method_type = None; + for impl_info in &self.env.impls { + if impl_info.target == *name { + if let Some(func_type) = impl_info.methods.get(field) { + method_type = Some(Type::Function( + func_type.params.clone(), + Box::new(func_type.return_type.clone()), + )); + break; + } + } + } + method_type.ok_or_else(|| TypeError { + kind: TypeErrorKind::UndefinedField( + field.clone(), + typed_obj.ty.clone(), + ), + span: expr.span.clone(), + })? + } + } else { + return Err(TypeError { + kind: TypeErrorKind::NotAStruct(typed_obj.ty.clone()), + span: obj.span.clone(), + }); + } + } else { + return Err(TypeError { + kind: TypeErrorKind::UndefinedType(name.clone()), + span: obj.span.clone(), + }); + } + } + ty => { + return Err(TypeError { + kind: TypeErrorKind::NotAStruct(ty.clone()), + span: obj.span.clone(), + }); + } + }; + + ( + TypedExprKind::Dot(Box::new(typed_obj), field.clone()), + field_type, + ) + } + + ExprKind::StructLit(name, fields) => { + // Clone the struct info we need before borrowing self mutably + let (struct_info_clone, type_params) = { + let struct_type = self.env.get_type(name).ok_or_else(|| TypeError { + kind: TypeErrorKind::UndefinedType(name.clone()), + span: expr.span.clone(), + })?; + (struct_type.clone(), struct_type.parameters.clone()) + }; + + let mut typed_fields = Vec::new(); + let mut type_arg_map: HashMap = HashMap::new(); + + if let TypeInfoKind::Struct(expected_fields) = &struct_info_clone.kind { + for (field_name, field_expr) in fields { + let typed_field_expr = self.typecheck_expr(field_expr)?; + + let expected_type_annot = expected_fields + .iter() + .find(|(n, _)| n == field_name) + .map(|(_, ty)| ty.clone()) + .ok_or_else(|| TypeError { + kind: TypeErrorKind::UndefinedField( + field_name.clone(), + Type::Struct(name.clone(), vec![]), + ), + span: field_expr.span.clone(), + })?; + + // Infer generic type parameters + self.infer_type_args( + &expected_type_annot, + &typed_field_expr.ty, + &type_params, + &mut type_arg_map, + ); + + typed_fields.push((field_name.clone(), typed_field_expr)); + } + } else { + return Err(TypeError { + kind: TypeErrorKind::NotAStruct(Type::Struct(name.clone(), vec![])), + span: expr.span.clone(), + }); + } + + // Build concrete type arguments + let concrete_type_args: Vec = type_params + .iter() + .map(|param| type_arg_map.get(param).cloned().unwrap_or(Type::Unknown)) + .collect(); + + ( + TypedExprKind::StructLit(name.clone(), typed_fields), + Type::Struct(name.clone(), concrete_type_args), + ) + } + + ExprKind::EnumLit(enum_name, variant_name, args) => { + // Clone the enum info we need before borrowing self mutably + let (variant_fields, variant_name_clone, type_params) = { + let enum_type = self.env.get_type(enum_name).ok_or_else(|| TypeError { + kind: TypeErrorKind::UndefinedType(enum_name.clone()), + span: expr.span.clone(), + })?; + + let type_params = enum_type.parameters.clone(); + + if let TypeInfoKind::Enum(variants) = &enum_type.kind { + let variant = variants + .iter() + .find(|(n, _)| n == variant_name) + .ok_or_else(|| TypeError { + kind: TypeErrorKind::UndefinedVariant( + enum_name.clone(), + variant_name.clone(), + ), + span: expr.span.clone(), + })?; + + if variant.1.len() != args.len() { + return Err(TypeError { + kind: TypeErrorKind::ArityMismatch(variant.1.len(), args.len()), + span: expr.span.clone(), + }); + } + + (variant.1.clone(), variant_name.clone(), type_params) + } else { + return Err(TypeError { + kind: TypeErrorKind::NotAnEnum(Type::Enum(enum_name.clone(), vec![])), + span: expr.span.clone(), + }); + } + }; + + let mut typed_args = Vec::new(); + let mut type_arg_map: HashMap = HashMap::new(); + + for (i, arg) in args.iter().enumerate() { + let typed_arg = self.typecheck_expr(arg)?; + + // Infer generic type parameters + self.infer_type_args( + &variant_fields[i], + &typed_arg.ty, + &type_params, + &mut type_arg_map, + ); + + typed_args.push(typed_arg); + } + + // Build concrete type arguments + let concrete_type_args: Vec = type_params + .iter() + .map(|param| type_arg_map.get(param).cloned().unwrap_or(Type::Unknown)) + .collect(); + + ( + TypedExprKind::EnumLit(enum_name.clone(), variant_name_clone, typed_args), + Type::Enum(enum_name.clone(), concrete_type_args), + ) + } + + ExprKind::Match(scrutinee, arms) => { + let typed_scrutinee = self.typecheck_expr(scrutinee)?; + let mut typed_arms = Vec::new(); + let mut result_type = Type::Unknown; + + for (i, (pattern, body)) in arms.iter().enumerate() { + self.env.enter_scope(); + let typed_pattern = self.typecheck_pattern(pattern, &typed_scrutinee.ty)?; + let typed_body = self.typecheck_expr(body)?; + self.env.exit_scope()?; + + if i == 0 { + result_type = typed_body.ty.clone(); + } else if !self.types_compatible(&typed_body.ty, &result_type) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch(result_type, typed_body.ty), + span: body.span.clone(), + }); + } + + typed_arms.push((typed_pattern, typed_body)); + } + + ( + TypedExprKind::Match(Box::new(typed_scrutinee), typed_arms), + result_type, + ) + } + + ExprKind::Lambda(params, body) => { + // Enter scope for lambda parameters + self.env.enter_scope(); + let mut param_types = Vec::new(); + let mut typed_params = Vec::new(); + for (param_name, param_type_annot) in params { + let param_id = self.next_binding_id(); + let param_type = param_type_annot + .as_ref() + .map(|t| self.type_annot_to_type(t)) + .unwrap_or(Type::Unknown); + param_types.push(param_type.clone()); + self.env.add_var( + param_id, + param_name.clone(), + param_type, + BindingKind::Default, + expr.span.clone(), + ); + typed_params.push((param_id, param_name.clone(), param_type_annot.clone())); + } + + let typed_body = self.typecheck_expr(body)?; + let func_type = Type::Function(param_types, Box::new(typed_body.ty.clone())); + + // Exit scope, checking usages + self.env.exit_scope()?; + + ( + TypedExprKind::Lambda(typed_params, Box::new(typed_body)), + func_type, + ) + } + + ExprKind::Assign(lhs, rhs) => { + // Check if lhs is a mutable variable + if let ExprKind::Variable(name) = &lhs.kind { + if let Some((_, var_info)) = self.env.get_var_by_name(name) { + if var_info.kind != BindingKind::Mutable { + return Err(TypeError { + kind: TypeErrorKind::MutableityError(format!( + "Cannot assign to immutable variable '{}'", + name + )), + span: lhs.span.clone(), + }); + } + } + } else { + return Err(TypeError { + kind: TypeErrorKind::MutableityError( + "Invalid left-hand side of assignment".to_string(), + ), + span: lhs.span.clone(), + }); + } + + let typed_lhs = self.typecheck_expr(lhs)?; + let typed_rhs = self.typecheck_expr(rhs)?; + + if !self.types_compatible(&typed_rhs.ty, &typed_lhs.ty) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch(typed_lhs.ty.clone(), typed_rhs.ty), + span: rhs.span.clone(), + }); + } + + ( + TypedExprKind::Assign(Box::new(typed_lhs), Box::new(typed_rhs)), + Type::Unit, + ) + } + + ExprKind::Cast(expr_inner, target_type) => { + let typed_expr = self.typecheck_expr(expr_inner)?; + let target_ty = self.type_annot_to_type(target_type); + + ( + TypedExprKind::Cast(Box::new(typed_expr), target_type.clone()), + target_ty, + ) + } + + ExprKind::Return(value) => { + let typed_value = if let Some(v) = value { + Some(Box::new(self.typecheck_expr(v)?)) + } else { + None + }; + let return_type = typed_value + .as_ref() + .map(|v| v.ty.clone()) + .unwrap_or(Type::Unit); + (TypedExprKind::Return(typed_value), return_type) + } + + ExprKind::Break => (TypedExprKind::Break, Type::Never), + ExprKind::Continue => (TypedExprKind::Continue, Type::Never), + + ExprKind::EarlyReturn(value) => { + let typed_value = if let Some(v) = value { + Some(Box::new(self.typecheck_expr(v)?)) + } else { + None + }; + let return_type = typed_value + .as_ref() + .map(|v| v.ty.clone()) + .unwrap_or(Type::Unit); + (TypedExprKind::EarlyReturn(typed_value), return_type) + } + + ExprKind::OptionalChain(obj, field) => { + let typed_obj = if let Some(o) = obj { + Some(Box::new(self.typecheck_expr(o)?)) + } else { + None + }; + // Simplified - would need proper Option type handling + ( + TypedExprKind::OptionalChain(typed_obj, field.clone()), + Type::Unknown, + ) + } + }; + + Ok(TypedExpr { + kind, + span: expr.span.clone(), + attributes: expr.attributes.clone(), + ty, + }) + } + + // Helper function to infer generic type arguments + fn infer_type_args( + &self, + expected: &TypeAnnot, + actual: &Type, + type_params: &[String], + type_map: &mut HashMap, + ) { + match (expected, actual) { + (TypeAnnot::Var(param_name), actual_type) => { + // Check if this is actually a type parameter + if type_params.contains(param_name) { + type_map + .entry(param_name.clone()) + .or_insert(actual_type.clone()); + } + } + (TypeAnnot::Cons(_, args), _) if args.is_empty() => { + // No generic args to infer + } + (TypeAnnot::Array(inner), Type::Array(actual_inner)) => { + self.infer_type_args(inner, actual_inner, type_params, type_map); + } + (TypeAnnot::Ptr(inner), Type::Ptr(actual_inner)) => { + self.infer_type_args(inner, actual_inner, type_params, type_map); + } + (TypeAnnot::Tuple(expected_types), Type::Tuple(actual_types)) => { + for (e, a) in expected_types.iter().zip(actual_types.iter()) { + self.infer_type_args(e, a, type_params, type_map); + } + } + _ => {} + } + } + + fn typecheck_pattern( + &mut self, + pattern: &Pattern, + scrutinee_type: &Type, + ) -> Result { + let (kind, ty) = match &pattern.kind { + PatternKind::Wildcard => (TypedPatternKind::Wildcard, scrutinee_type.clone()), + + PatternKind::Variable(name) => { + let var_id = self.next_binding_id(); + self.env.add_var( + var_id, + name.clone(), + scrutinee_type.clone(), + BindingKind::Default, + pattern.span.clone(), + ); + ( + TypedPatternKind::Variable(var_id, name.clone()), + scrutinee_type.clone(), + ) + } + + PatternKind::Literal(lit) => { + // Infer type from literal + let lit_type = if lit.parse::().is_ok() { + Type::Int + } else if lit.parse::().is_ok() { + Type::Float + } else if lit == "true" || lit == "false" { + Type::Bool + } else { + Type::String + }; + + if !self.types_compatible(&lit_type, scrutinee_type) { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch(scrutinee_type.clone(), lit_type), + span: pattern.span.clone(), + }); + } + + (TypedPatternKind::Literal(lit.clone()), lit_type) + } + + PatternKind::Tuple(patterns) => { + let mut typed_patterns = Vec::new(); + let mut types = Vec::new(); + + if let Type::Tuple(tuple_types) = scrutinee_type { + if patterns.len() != tuple_types.len() { + return Err(TypeError { + kind: TypeErrorKind::ArityMismatch(tuple_types.len(), patterns.len()), + span: pattern.span.clone(), + }); + } + + for (p, t) in patterns.iter().zip(tuple_types.iter()) { + let typed_p = self.typecheck_pattern(p, t)?; + types.push(typed_p.ty.clone()); + typed_patterns.push(typed_p); + } + } else { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch( + scrutinee_type.clone(), + Type::Tuple(vec![]), + ), + span: pattern.span.clone(), + }); + } + + (TypedPatternKind::Tuple(typed_patterns), Type::Tuple(types)) + } + + PatternKind::Struct(name, fields) => { + if let Type::Struct(struct_name, type_args) = scrutinee_type { + if name != struct_name { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch( + scrutinee_type.clone(), + Type::Struct(name.clone(), vec![]), + ), + span: pattern.span.clone(), + }); + } + + // Clone the struct fields we need before borrowing self mutably + let (struct_fields_clone, type_params) = { + let struct_info = self.env.get_type(name).ok_or_else(|| TypeError { + kind: TypeErrorKind::UndefinedType(name.clone()), + span: pattern.span.clone(), + })?; + + if let TypeInfoKind::Struct(struct_fields) = &struct_info.kind { + (struct_fields.clone(), struct_info.parameters.clone()) + } else { + return Err(TypeError { + kind: TypeErrorKind::NotAStruct(scrutinee_type.clone()), + span: pattern.span.clone(), + }); + } + }; + + // Create substitution map for type parameters + let mut subst_map: HashMap = HashMap::new(); + for (param, arg) in type_params.iter().zip(type_args.iter()) { + subst_map.insert(param.clone(), arg.clone()); + } + + let mut typed_fields = Vec::new(); + for (field_name, field_pattern) in fields { + let field_type_annot = struct_fields_clone + .iter() + .find(|(n, _)| n == field_name) + .map(|(_, ty)| ty.clone()) + .ok_or_else(|| TypeError { + kind: TypeErrorKind::UndefinedField( + field_name.clone(), + scrutinee_type.clone(), + ), + span: pattern.span.clone(), + })?; + + let field_type = self.substitute_type(&field_type_annot, &subst_map); + + let typed_field_pattern = + self.typecheck_pattern(field_pattern, &field_type)?; + typed_fields.push((field_name.clone(), typed_field_pattern)); + } + + ( + TypedPatternKind::Struct(name.clone(), typed_fields), + scrutinee_type.clone(), + ) + } else { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch( + scrutinee_type.clone(), + Type::Struct(name.clone(), vec![]), + ), + span: pattern.span.clone(), + }); + } + } + + PatternKind::Enum(enum_name, variant_name, patterns) => { + if let Type::Enum(scrutinee_enum_name, type_args) = scrutinee_type { + if enum_name != scrutinee_enum_name { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch( + scrutinee_type.clone(), + Type::Enum(enum_name.clone(), vec![]), + ), + span: pattern.span.clone(), + }); + } + + // Clone the variant fields we need before borrowing self mutably + let (variant_fields_clone, type_params) = { + let enum_info = self.env.get_type(enum_name).ok_or_else(|| TypeError { + kind: TypeErrorKind::UndefinedType(enum_name.clone()), + span: pattern.span.clone(), + })?; + + if let TypeInfoKind::Enum(variants) = &enum_info.kind { + let variant = variants + .iter() + .find(|(n, _)| n == variant_name) + .ok_or_else(|| TypeError { + kind: TypeErrorKind::UndefinedVariant( + enum_name.clone(), + variant_name.clone(), + ), + span: pattern.span.clone(), + })?; + + if variant.1.len() != patterns.len() { + return Err(TypeError { + kind: TypeErrorKind::ArityMismatch( + variant.1.len(), + patterns.len(), + ), + span: pattern.span.clone(), + }); + } + + (variant.1.clone(), enum_info.parameters.clone()) + } else { + return Err(TypeError { + kind: TypeErrorKind::NotAnEnum(scrutinee_type.clone()), + span: pattern.span.clone(), + }); + } + }; + + // Create substitution map for type parameters + let mut subst_map: HashMap = HashMap::new(); + for (param, arg) in type_params.iter().zip(type_args.iter()) { + subst_map.insert(param.clone(), arg.clone()); + } + + let mut typed_patterns = Vec::new(); + for (p, field_type_annot) in patterns.iter().zip(variant_fields_clone.iter()) { + let field_type = self.substitute_type(field_type_annot, &subst_map); + let typed_p = self.typecheck_pattern(p, &field_type)?; + typed_patterns.push(typed_p); + } + + ( + TypedPatternKind::Enum( + enum_name.clone(), + variant_name.clone(), + typed_patterns, + ), + scrutinee_type.clone(), + ) + } else { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch( + scrutinee_type.clone(), + Type::Enum(enum_name.clone(), vec![]), + ), + span: pattern.span.clone(), + }); + } + } + + PatternKind::Range(_, _) => (TypedPatternKind::Wildcard, Type::Int), + }; + + Ok(TypedPattern { + kind, + span: pattern.span.clone(), + ty, + }) + } + + // Substitute type variables in a type annotation + fn substitute_type(&self, annot: &TypeAnnot, subst_map: &HashMap) -> Type { + match annot { + TypeAnnot::Var(name) => { + if let Some(ty) = subst_map.get(name) { + ty.clone() + } else { + self.type_annot_to_type(annot) + } + } + TypeAnnot::Cons(name, args) => { + let substituted_args: Vec = args + .iter() + .map(|arg| self.substitute_type(arg, subst_map)) + .collect(); + + if let Some(type_info) = self.env.get_type(name) { + match &type_info.kind { + TypeInfoKind::Struct(_) => Type::Struct(name.clone(), substituted_args), + TypeInfoKind::Enum(_) => Type::Enum(name.clone(), substituted_args), + } + } else { + match name.as_str() { + "int" => Type::Int, + "float" => Type::Float, + "bool" => Type::Bool, + "string" => Type::String, + "unit" => Type::Unit, + "never" => Type::Never, + _ => Type::Generic(name.clone(), substituted_args), + } + } + } + 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::Tuple(types) => { + let substituted_types: Vec = types + .iter() + .map(|t| self.substitute_type(t, subst_map)) + .collect(); + Type::Tuple(substituted_types) + } + TypeAnnot::Function(args, ret) => { + let arg_types: Vec = args + .iter() + .map(|a| self.substitute_type(a, subst_map)) + .collect(); + let ret_type = Box::new(self.substitute_type(ret, subst_map)); + Type::Function(arg_types, ret_type) + } + } + } + + fn type_annot_to_type(&self, annot: &TypeAnnot) -> Type { + match annot { + TypeAnnot::Var(name) => { + // Check if it's a type variable + if let Some(ty) = self.env.type_vars.get(name) { + return ty.clone(); + } + + match name.as_str() { + "int" => Type::Int, + "float" => Type::Float, + "bool" => Type::Bool, + "string" => Type::String, + "unit" => Type::Unit, + "never" => Type::Never, + _ => Type::TypeVar(name.clone()), + } + } + TypeAnnot::Cons(name, args) => { + let type_args: Vec = + args.iter().map(|a| self.type_annot_to_type(a)).collect(); + + match name.as_str() { + "int" => Type::Int, + "float" => Type::Float, + "bool" => Type::Bool, + "string" => Type::String, + "unit" => Type::Unit, + "never" => Type::Never, + _ => { + // Check if it's a struct or enum + if let Some(type_info) = self.env.get_type(name) { + match &type_info.kind { + TypeInfoKind::Struct(_) => Type::Struct(name.clone(), type_args), + TypeInfoKind::Enum(_) => Type::Enum(name.clone(), type_args), + } + } else { + Type::Generic(name.clone(), type_args) + } + } + } + } + TypeAnnot::Function(args, ret) => { + let arg_types: Vec = + args.iter().map(|a| self.type_annot_to_type(a)).collect(); + let ret_type = Box::new(self.type_annot_to_type(ret)); + Type::Function(arg_types, ret_type) + } + TypeAnnot::Tuple(types) => { + let tuple_types: Vec = + types.iter().map(|t| self.type_annot_to_type(t)).collect(); + Type::Tuple(tuple_types) + } + TypeAnnot::Array(inner) => Type::Array(Box::new(self.type_annot_to_type(inner))), + TypeAnnot::Ptr(inner) => Type::Ptr(Box::new(self.type_annot_to_type(inner))), + } + } + + fn types_compatible(&self, t1: &Type, t2: &Type) -> bool { + match (t1, t2) { + (Type::Unknown, _) | (_, Type::Unknown) => true, + (Type::Int, Type::Int) => true, + (Type::Float, Type::Float) => true, + (Type::Bool, Type::Bool) => true, + (Type::String, Type::String) => true, + (Type::Unit, Type::Unit) => true, + (Type::Never, _) | (_, Type::Never) => true, + (Type::Array(a), Type::Array(b)) => self.types_compatible(a, b), + (Type::Ptr(a), Type::Ptr(b)) => self.types_compatible(a, b), + (Type::Tuple(a), Type::Tuple(b)) => { + a.len() == b.len() + && a.iter() + .zip(b.iter()) + .all(|(x, y)| self.types_compatible(x, y)) + } + (Type::Function(args1, ret1), Type::Function(args2, ret2)) => { + args1.len() == args2.len() + && args1 + .iter() + .zip(args2.iter()) + .all(|(x, y)| self.types_compatible(x, y)) + && self.types_compatible(ret1, ret2) + } + (Type::Struct(name1, args1), Type::Struct(name2, args2)) => { + name1 == name2 + && args1.len() == args2.len() + && args1 + .iter() + .zip(args2.iter()) + .all(|(x, y)| self.types_compatible(x, y)) + } + (Type::Enum(name1, args1), Type::Enum(name2, args2)) => { + name1 == name2 + && args1.len() == args2.len() + && args1 + .iter() + .zip(args2.iter()) + .all(|(x, y)| self.types_compatible(x, y)) + } + (Type::Generic(name1, args1), Type::Generic(name2, args2)) => { + name1 == name2 + && args1.len() == args2.len() + && args1 + .iter() + .zip(args2.iter()) + .all(|(x, y)| self.types_compatible(x, y)) + } + (Type::TypeVar(a), Type::TypeVar(b)) => a == b, + (Type::TypeVar(_), _) | (_, Type::TypeVar(_)) => true, // Type variables are compatible with anything + (Type::Generic(_, _), _) | (_, Type::Generic(_, _)) => true, // Generic types are compatible with anything (for now) + _ => false, + } + } +} + +``` + +```rust +// src/main.rs +use logos::Logos; +use std::fs; +use suicmez::{ + codegen::transpiler::Transpiler, + lambda_lower::LambdaLowerer, + lexer::Token, + monomorphize::{Monomorphizer, check_no_typevars}, + parser::Parser, + typechecker::TypeChecker, +}; + +fn main() { + // Check if a file was provided as argument + let args: Vec = std::env::args().collect(); + if args.len() < 2 { + // Run all test files in the tests directory + run_test_suite(); + return; + } + + let filename = &args[1]; + println!("Type checking file: {}", filename); + + if let Err(e) = run_file(filename) { + eprintln!("Error: {}", e); + } +} + +fn run_test_suite() { + println!("Running test suite...\n"); + + let test_files = vec![ + "tests/basic_types.sui", + "tests/structs.sui", + "tests/enums.sui", + "tests/functions.sui", + "tests/arrays.sui", + "tests/traits.sui", + "tests/control_flow.sui", + ]; + + for file in test_files { + println!("Testing: {}", file); + match run_file(file) { + Ok(_) => println!("✓ Passed\n"), + Err(e) => println!("✗ Failed: {}\n", e), + } + } +} + +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 format_type_error(source: &str, error: &suicmez::typechecker::TypeError) -> 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!("Type error: {}\n", error.kind)); + + // 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!("Type error: {} (at byte {})", error.kind, error.span.start) +} + +fn run_file(filename: &str) -> Result<(), String> { + // Read the source file + let source = fs::read_to_string(filename) + .map_err(|e| format!("Error reading file {}: {}", filename, e))?; + + // First, we need to parse the source code + let mut tokens = Vec::new(); + let mut lexer = Token::lexer(&source); + + loop { + match lexer.next() { + Some(Ok(token)) => { + let span = lexer.span(); + tokens.push((token, span)); + } + Some(Err(_)) => { + return Err("Lexing error".to_string()); + } + None => break, + } + } + + let mut parser = Parser::new(filename.to_string(), tokens); + let ast_nodes = parser + .parse() + .map_err(|e| format_parse_error(&source, &e))?; + + println!("Parsed {} AST nodes successfully", ast_nodes.len()); + + // Lower lambdas to generated functions + let lowerer = LambdaLowerer::new(); + let lowered_nodes = lowerer + .lower_program(&ast_nodes) + .map_err(|e| format!("Lambda lowering error: {}", e))?; + + println!( + "Lambda lowering passed! {} nodes after lowering.", + lowered_nodes.len() + ); + + // Typecheck the AST + let mut typechecker = TypeChecker::new(); + let typed_nodes = typechecker + .typecheck_program(&lowered_nodes) + .map_err(|e| format_type_error(&source, &e))?; + + println!( + "Type checking passed! {} nodes typechecked.", + typed_nodes.len() + ); + + // Debug: show typed nodes + println!("\nTyped AST nodes before monomorphization:"); + for (i, node) in typed_nodes.iter().enumerate() { + let node_type = match &node.kind { + suicmez::ast::TypedASTNodeKind::Function(f) => { + format!("Function({})", f.name) + } + suicmez::ast::TypedASTNodeKind::Struct(s) => { + format!("Struct({}) with {} params", s.name, s.parameters.len()) + } + suicmez::ast::TypedASTNodeKind::Enum(e) => { + format!("Enum({}) with {} params", e.name, e.parameters.len()) + } + suicmez::ast::TypedASTNodeKind::Impl(imp) => { + format!("Impl({})", imp.target) + } + suicmez::ast::TypedASTNodeKind::Trait(t) => { + format!("Trait({})", t.name) + } + suicmez::ast::TypedASTNodeKind::Extern(e) => { + format!("Extern({})", e.name) + } + suicmez::ast::TypedASTNodeKind::Load(l) => { + format!("Load({})", l.alias) + } + suicmez::ast::TypedASTNodeKind::Use(u) => { + format!("Use({})", u) + } + }; + println!(" [{}] {}", i, node_type); + } + + // Monomorphize the AST + let monomorphizer = Monomorphizer::new(); + let mono_nodes = monomorphizer + .monomorphize_program(&typed_nodes) + .map_err(|e| { + format!( + "Monomorphization error: {}{}", + e.message, + if let Some(span) = &e.span { + format!(" at {}:{}", span.file, span.start) + } else { + String::new() + } + ) + })?; + + println!( + "Monomorphization passed! {} nodes after specialization.", + mono_nodes.len() + ); + + // Print detailed info about each node + println!("\nMonomorphized AST nodes:"); + for (i, node) in mono_nodes.iter().enumerate() { + let node_type = match &node.kind { + suicmez::ast::TypedASTNodeKind::Function(f) => { + format!("Function({})", f.name) + } + suicmez::ast::TypedASTNodeKind::Struct(s) => { + format!("Struct({}) with {} params", s.name, s.parameters.len()) + } + suicmez::ast::TypedASTNodeKind::Enum(e) => { + format!("Enum({}) with {} params", e.name, e.parameters.len()) + } + suicmez::ast::TypedASTNodeKind::Impl(imp) => { + format!("Impl({})", imp.target) + } + suicmez::ast::TypedASTNodeKind::Trait(t) => { + format!("Trait({})", t.name) + } + suicmez::ast::TypedASTNodeKind::Extern(e) => { + format!("Extern({})", e.name) + } + suicmez::ast::TypedASTNodeKind::Load(l) => { + format!("Load({})", l.alias) + } + suicmez::ast::TypedASTNodeKind::Use(u) => { + format!("Use({})", u) + } + }; + println!(" [{}] {}", i, node_type); + } + + // Check that no type variables remain + check_no_typevars(&mono_nodes).map_err(|e| { + format!( + "Type variable check failed: {}{}", + e.message, + if let Some(span) = &e.span { + format!(" at {}:{}", span.file, span.start) + } else { + String::new() + } + ) + })?; + + println!("Type variable check passed! No type variables remain in AST."); + + // Generate C code + let mut transpiler = Transpiler::new(); + let c_code = transpiler + .transpile_program(&mono_nodes) + .map_err(|e| format!("Code generation error: {}", e))?; + + // Write C code to file + let c_filename = filename.replace(".sui", ".c"); + fs::write(&c_filename, &c_code) + .map_err(|e| format!("Error writing C file {}: {}", c_filename, e))?; + + println!("C code generated successfully: {}", c_filename); + + Ok(()) +} + +``` + +```rust +// src/monomorphize.rs +use crate::ast::*; +use crate::typechecker::Type; +use std::collections::{HashMap, HashSet}; + +#[derive(Debug)] +pub struct MonomorphizationError { + pub message: String, + pub span: Option, +} + +impl MonomorphizationError { + fn new(message: impl Into, span: Option) -> Self { + MonomorphizationError { + message: message.into(), + span, + } + } +} + +/// Specialization cache to avoid duplicating already-generated specializations +#[derive(Clone)] +struct SpecializationKey { + base_name: String, + type_args: Vec, +} + +impl SpecializationKey { + fn new(base_name: String, type_args: Vec) -> Self { + SpecializationKey { + base_name, + type_args, + } + } + + fn to_string(&self) -> String { + if self.type_args.is_empty() { + self.base_name.clone() + } else { + let arg_strs: Vec = self.type_args.iter().map(|t| t.to_string()).collect(); + format!("{}_{}", self.base_name, arg_strs.join("_")) + } + } + + fn to_hashable(&self) -> String { + self.to_string() + } +} + +/// The monomorphizer specializes generic types into concrete versions +pub struct Monomorphizer { + // Track all generated specializations to avoid duplicates + generated_structs: HashMap, + generated_enums: HashMap, + generated_functions: HashMap, +} + +impl Monomorphizer { + pub fn new() -> Self { + Monomorphizer { + generated_structs: HashMap::new(), + generated_enums: HashMap::new(), + generated_functions: HashMap::new(), + } + } + + pub fn monomorphize_program( + mut self, + nodes: &[TypedASTNode], + ) -> Result, MonomorphizationError> { + // First pass: collect all generic definitions + let mut generic_structs = HashMap::new(); + let mut generic_enums = HashMap::new(); + let mut generic_functions = HashMap::new(); + let mut generic_impls = Vec::new(); + + for node in nodes { + match &node.kind { + TypedASTNodeKind::Struct(s) => { + if !s.parameters.is_empty() { + generic_structs.insert(s.name.clone(), (s.clone(), node.clone())); + } + } + TypedASTNodeKind::Enum(e) => { + if !e.parameters.is_empty() { + generic_enums.insert(e.name.clone(), (e.clone(), node.clone())); + } + } + TypedASTNodeKind::Function(f) => { + if !f.parameters.is_empty() { + generic_functions.insert(f.name.clone(), (f.clone(), node.clone())); + } + } + TypedASTNodeKind::Impl(imp) => { + generic_impls.push((imp.clone(), node.clone())); + } + _ => {} + } + } + + // Second pass: monomorphize expressions to collect specialization requirements + let mut specialization_needs: Vec = Vec::new(); + let mut seen_keys: HashSet = HashSet::new(); + let mut result_nodes = Vec::new(); + + for (_idx, node) in nodes.iter().enumerate() { + match &node.kind { + TypedASTNodeKind::Function(f) => { + // Skip generic functions - they'll be added as specialized versions when needed + if !f.parameters.is_empty() { + continue; + } + + let (mono_func, needs) = self.monomorphize_function( + f, + &generic_structs, + &generic_enums, + &generic_functions, + )?; + for need in needs { + let key = need.to_hashable(); + if !seen_keys.contains(&key) { + seen_keys.insert(key); + specialization_needs.push(need); + } + } + + let mut new_node = node.clone(); + new_node.kind = TypedASTNodeKind::Function(mono_func); + result_nodes.push(new_node); + } + TypedASTNodeKind::Struct(s) => { + // Skip generic structs - they'll be added as specialized versions when needed + if !s.parameters.is_empty() { + continue; + } + result_nodes.push(node.clone()); + } + TypedASTNodeKind::Enum(e) => { + // Skip generic enums - they'll be added as specialized versions when needed + if !e.parameters.is_empty() { + continue; + } + result_nodes.push(node.clone()); + } + TypedASTNodeKind::Impl(imp) => { + let (mono_impl, needs) = self.monomorphize_impl( + imp, + &generic_structs, + &generic_enums, + &generic_functions, + )?; + for need in needs { + let key = need.to_hashable(); + if !seen_keys.contains(&key) { + seen_keys.insert(key); + specialization_needs.push(need); + } + } + + let mut new_node = node.clone(); + new_node.kind = TypedASTNodeKind::Impl(mono_impl); + result_nodes.push(new_node); + } + _ => { + result_nodes.push(node.clone()); + } + } + } + + // Third pass: generate all needed specializations + let mut iterations = 0; + const MAX_ITERATIONS: usize = 1000; // Prevent infinite loops + + while !specialization_needs.is_empty() && iterations < MAX_ITERATIONS { + iterations += 1; + let current_needs: Vec<_> = specialization_needs.drain(..).collect(); + + for key in current_needs { + if self.generated_structs.contains_key(&key.to_string()) { + continue; + } + + // Try to specialize a struct + if let Some((generic_struct, orig_node)) = generic_structs.get(&key.base_name) { + let (mono_struct, needs) = self.specialize_struct( + generic_struct, + &key.type_args, + &generic_structs, + &generic_enums, + &generic_functions, + )?; + self.generated_structs + .insert(key.to_string(), mono_struct.clone()); + for need in needs { + let need_key = need.to_hashable(); + if !seen_keys.contains(&need_key) { + seen_keys.insert(need_key); + specialization_needs.push(need); + } + } + + let mut new_node = orig_node.clone(); + new_node.kind = TypedASTNodeKind::Struct(mono_struct); + result_nodes.push(new_node); + continue; + } + + // Try to specialize an enum + if let Some((generic_enum, orig_node)) = generic_enums.get(&key.base_name) { + let (mono_enum, needs) = self.specialize_enum( + generic_enum, + &key.type_args, + &generic_structs, + &generic_enums, + &generic_functions, + )?; + + // Only add if it was actually specialized (arity matched) + if mono_enum.parameters.is_empty() { + self.generated_enums + .insert(key.to_string(), mono_enum.clone()); + for need in needs { + let need_key = need.to_hashable(); + if !seen_keys.contains(&need_key) { + seen_keys.insert(need_key); + specialization_needs.push(need); + } + } + + let mut new_node = orig_node.clone(); + new_node.kind = TypedASTNodeKind::Enum(mono_enum); + result_nodes.push(new_node); + } + continue; + } + + // Try to specialize a function + if let Some((generic_func, orig_node)) = generic_functions.get(&key.base_name) { + let (mono_func, needs) = self.specialize_function( + generic_func, + &key.type_args, + &generic_structs, + &generic_enums, + &generic_functions, + )?; + self.generated_functions + .insert(key.to_string(), mono_func.clone()); + for need in needs { + let need_key = need.to_hashable(); + if !seen_keys.contains(&need_key) { + seen_keys.insert(need_key); + specialization_needs.push(need); + } + } + + let mut new_node = orig_node.clone(); + new_node.kind = TypedASTNodeKind::Function(mono_func); + result_nodes.push(new_node); + } + } + } + + if iterations >= MAX_ITERATIONS { + return Err(MonomorphizationError::new( + "Monomorphization exceeded maximum iterations (possible infinite recursion)", + None, + )); + } + + Ok(result_nodes) + } + + fn monomorphize_function( + &mut self, + func: &TypedFunction, + _generic_structs: &HashMap, + _generic_enums: &HashMap, + _generic_functions: &HashMap, + ) -> Result<(TypedFunction, Vec), MonomorphizationError> { + if func.parameters.is_empty() { + let (body, needs) = self.monomorphize_expr(&func.body)?; + let mut new_func = func.clone(); + new_func.body = body; + Ok((new_func, needs)) + } else { + // Functions with type parameters should not appear in final code + // They'll be specialized as needed + Ok((func.clone(), Vec::new())) + } + } + + fn monomorphize_impl( + &mut self, + imp: &TypedImpl, + _generic_structs: &HashMap, + _generic_enums: &HashMap, + _generic_functions: &HashMap, + ) -> Result<(TypedImpl, Vec), MonomorphizationError> { + let mut all_needs = Vec::new(); + let mut new_methods = Vec::new(); + + for method in &imp.methods { + let (mono_method, needs) = self.monomorphize_function( + method, + _generic_structs, + _generic_enums, + _generic_functions, + )?; + all_needs.extend(needs); + new_methods.push(mono_method); + } + + let mut new_impl = imp.clone(); + new_impl.methods = new_methods; + Ok((new_impl, all_needs)) + } + + fn monomorphize_expr( + &mut self, + expr: &TypedExpr, + ) -> Result<(TypedExpr, Vec), MonomorphizationError> { + let mut needs = Vec::new(); + let new_kind = match &expr.kind { + TypedExprKind::Int(_) + | TypedExprKind::Float(_) + | TypedExprKind::Bool(_) + | TypedExprKind::String(_) + | TypedExprKind::Break + | TypedExprKind::Continue => expr.kind.clone(), + + TypedExprKind::Array(elems) => { + let mut new_elems = Vec::new(); + for elem in elems { + let (new_elem, elem_needs) = self.monomorphize_expr(elem)?; + needs.extend(elem_needs); + new_elems.push(new_elem); + } + TypedExprKind::Array(new_elems) + } + + TypedExprKind::Tuple(elems) => { + let mut new_elems = Vec::new(); + for elem in elems { + let (new_elem, elem_needs) = self.monomorphize_expr(elem)?; + needs.extend(elem_needs); + new_elems.push(new_elem); + } + TypedExprKind::Tuple(new_elems) + } + + TypedExprKind::StructLit(name, fields) => { + let mut new_fields = Vec::new(); + let mut field_types = Vec::new(); + for (field_name, field_expr) in fields { + let (new_expr, expr_needs) = self.monomorphize_expr(field_expr)?; + field_types.push(new_expr.ty.clone()); + needs.extend(expr_needs); + new_fields.push((field_name.clone(), new_expr)); + } + // Infer struct specialization from field types + if !field_types.is_empty() { + self.infer_struct_specialization(name, &field_types, &mut needs); + } + TypedExprKind::StructLit(name.clone(), new_fields) + } + + TypedExprKind::EnumLit(enum_name, variant, args) => { + let mut new_args = Vec::new(); + let mut arg_types = Vec::new(); + for arg in args { + let (new_arg, arg_needs) = self.monomorphize_expr(arg)?; + arg_types.push(new_arg.ty.clone()); + needs.extend(arg_needs); + new_args.push(new_arg); + } + // Infer enum specialization from argument types + if !arg_types.is_empty() { + self.infer_enum_specialization(enum_name, &arg_types, &mut needs); + } + TypedExprKind::EnumLit(enum_name.clone(), variant.clone(), new_args) + } + + TypedExprKind::Variable(_) => expr.kind.clone(), + + TypedExprKind::Call(func_expr, args) => { + let (new_func_expr, func_needs) = self.monomorphize_expr(func_expr)?; + needs.extend(func_needs); + + let mut new_args = Vec::new(); + for arg in args { + let (new_arg, arg_needs) = self.monomorphize_expr(arg)?; + needs.extend(arg_needs); + new_args.push(new_arg); + } + + // Collect function call specialization needs from return type + self.collect_needs_from_expr_type(expr, &mut needs); + + TypedExprKind::Call(Box::new(new_func_expr), new_args) + } + + TypedExprKind::Index(array_expr, index_expr) => { + let (new_array, array_needs) = self.monomorphize_expr(array_expr)?; + let (new_index, index_needs) = self.monomorphize_expr(index_expr)?; + needs.extend(array_needs); + needs.extend(index_needs); + TypedExprKind::Index(Box::new(new_array), Box::new(new_index)) + } + + TypedExprKind::Dot(obj_expr, field) => { + let (new_obj, obj_needs) = self.monomorphize_expr(obj_expr)?; + needs.extend(obj_needs); + TypedExprKind::Dot(Box::new(new_obj), field.clone()) + } + + TypedExprKind::EarlyReturn(expr_opt) => { + if let Some(inner_expr) = expr_opt { + let (new_expr, expr_needs) = self.monomorphize_expr(inner_expr)?; + needs.extend(expr_needs); + TypedExprKind::EarlyReturn(Some(Box::new(new_expr))) + } else { + TypedExprKind::EarlyReturn(None) + } + } + + TypedExprKind::OptionalChain(expr_opt, field) => { + if let Some(inner_expr) = expr_opt { + let (new_expr, expr_needs) = self.monomorphize_expr(inner_expr)?; + needs.extend(expr_needs); + TypedExprKind::OptionalChain(Some(Box::new(new_expr)), field.clone()) + } else { + TypedExprKind::OptionalChain(None, field.clone()) + } + } + + TypedExprKind::Lambda(params, body) => { + let (new_body, body_needs) = self.monomorphize_expr(body)?; + needs.extend(body_needs); + TypedExprKind::Lambda(params.clone(), Box::new(new_body)) + } + + TypedExprKind::Let(id, name, binding_kind, ty_annot, expr) => { + let (new_expr, expr_needs) = self.monomorphize_expr(expr)?; + needs.extend(expr_needs); + TypedExprKind::Let( + *id, + name.clone(), + binding_kind.clone(), + ty_annot.clone(), + Box::new(new_expr), + ) + } + + TypedExprKind::Assign(lvalue, rvalue) => { + let (new_lvalue, lvalue_needs) = self.monomorphize_expr(lvalue)?; + let (new_rvalue, rvalue_needs) = self.monomorphize_expr(rvalue)?; + needs.extend(lvalue_needs); + needs.extend(rvalue_needs); + TypedExprKind::Assign(Box::new(new_lvalue), Box::new(new_rvalue)) + } + + TypedExprKind::Cast(expr, ty) => { + let (new_expr, expr_needs) = self.monomorphize_expr(expr)?; + needs.extend(expr_needs); + TypedExprKind::Cast(Box::new(new_expr), ty.clone()) + } + + TypedExprKind::If(cond, then_expr, else_expr) => { + let (new_cond, cond_needs) = self.monomorphize_expr(cond)?; + let (new_then, then_needs) = self.monomorphize_expr(then_expr)?; + needs.extend(cond_needs); + needs.extend(then_needs); + + let new_else = if let Some(else_e) = else_expr { + let (new_else_expr, else_needs) = self.monomorphize_expr(else_e)?; + needs.extend(else_needs); + Some(Box::new(new_else_expr)) + } else { + None + }; + + TypedExprKind::If(Box::new(new_cond), Box::new(new_then), new_else) + } + + TypedExprKind::Match(scrutinee, arms) => { + let (new_scrutinee, scrutinee_needs) = self.monomorphize_expr(scrutinee)?; + needs.extend(scrutinee_needs); + + let mut new_arms = Vec::new(); + for (pattern, arm_expr) in arms { + let (new_arm_expr, arm_needs) = self.monomorphize_expr(arm_expr)?; + needs.extend(arm_needs); + new_arms.push((pattern.clone(), new_arm_expr)); + } + + TypedExprKind::Match(Box::new(new_scrutinee), new_arms) + } + + TypedExprKind::While(cond, body) => { + let (new_cond, cond_needs) = self.monomorphize_expr(cond)?; + let (new_body, body_needs) = self.monomorphize_expr(body)?; + needs.extend(cond_needs); + needs.extend(body_needs); + TypedExprKind::While(Box::new(new_cond), Box::new(new_body)) + } + + TypedExprKind::Do(exprs) => { + let mut new_exprs = Vec::new(); + for e in exprs { + let (new_e, e_needs) = self.monomorphize_expr(e)?; + needs.extend(e_needs); + new_exprs.push(new_e); + } + TypedExprKind::Do(new_exprs) + } + + TypedExprKind::BinOp(lhs, op, rhs) => { + let (new_lhs, lhs_needs) = self.monomorphize_expr(lhs)?; + let (new_rhs, rhs_needs) = self.monomorphize_expr(rhs)?; + needs.extend(lhs_needs); + needs.extend(rhs_needs); + TypedExprKind::BinOp(Box::new(new_lhs), op.clone(), Box::new(new_rhs)) + } + + TypedExprKind::UnOp(op, operand) => { + let (new_operand, operand_needs) = self.monomorphize_expr(operand)?; + needs.extend(operand_needs); + TypedExprKind::UnOp(op.clone(), Box::new(new_operand)) + } + + TypedExprKind::For(id, var, iter_expr, body) => { + let (new_iter, iter_needs) = self.monomorphize_expr(iter_expr)?; + let (new_body, body_needs) = self.monomorphize_expr(body)?; + needs.extend(iter_needs); + needs.extend(body_needs); + TypedExprKind::For(*id, var.clone(), Box::new(new_iter), Box::new(new_body)) + } + + TypedExprKind::Range(start, end) => { + let (new_start, start_needs) = self.monomorphize_expr(start)?; + let (new_end, end_needs) = self.monomorphize_expr(end)?; + needs.extend(start_needs); + needs.extend(end_needs); + TypedExprKind::Range(Box::new(new_start), Box::new(new_end)) + } + + TypedExprKind::Return(expr_opt) => { + if let Some(ret_expr) = expr_opt { + let (new_expr, expr_needs) = self.monomorphize_expr(ret_expr)?; + needs.extend(expr_needs); + TypedExprKind::Return(Some(Box::new(new_expr))) + } else { + TypedExprKind::Return(None) + } + } + }; + + let mut new_expr = expr.clone(); + new_expr.kind = new_kind; + Ok((new_expr, needs)) + } + + fn specialize_struct( + &mut self, + generic_struct: &TypedStruct, + type_args: &[Type], + _generic_structs: &HashMap, + _generic_enums: &HashMap, + _generic_functions: &HashMap, + ) -> Result<(TypedStruct, Vec), MonomorphizationError> { + if generic_struct.parameters.len() != type_args.len() { + return Err(MonomorphizationError::new( + format!( + "Struct {} expects {} type arguments, got {}", + generic_struct.name, + generic_struct.parameters.len(), + type_args.len() + ), + None, + )); + } + + let mut subst_map = HashMap::new(); + for (param, arg) in generic_struct.parameters.iter().zip(type_args.iter()) { + subst_map.insert(param.name.clone(), arg.clone()); + } + + let mut new_fields = Vec::new(); + let mut needs = Vec::new(); + + for field in &generic_struct.fields { + let new_ty = self.substitute_in_type_annot(&field.field_type, &subst_map)?; + + // Collect specialization needs from the field type + self.collect_needs_from_type(&new_ty, &mut needs); + + new_fields.push(TypedField { + name: field.name.clone(), + field_type: new_ty, + span: field.span.clone(), + }); + } + + let mut new_struct = generic_struct.clone(); + new_struct.name = self.generate_specialized_name(&generic_struct.name, type_args); + new_struct.parameters = Vec::new(); // Remove type parameters after specialization + new_struct.fields = new_fields; + + Ok((new_struct, needs)) + } + + fn specialize_enum( + &mut self, + generic_enum: &TypedEnum, + type_args: &[Type], + _generic_structs: &HashMap, + _generic_enums: &HashMap, + _generic_functions: &HashMap, + ) -> Result<(TypedEnum, Vec), MonomorphizationError> { + if generic_enum.parameters.len() != type_args.len() { + // If we can't specialize due to type arity mismatch, just skip it + // This can happen when the typechecker doesn't fully infer generic types + return Ok((generic_enum.clone(), Vec::new())); + } + + let mut subst_map = HashMap::new(); + for (param, arg) in generic_enum.parameters.iter().zip(type_args.iter()) { + subst_map.insert(param.name.clone(), arg.clone()); + } + + let mut new_variants = Vec::new(); + let mut needs = Vec::new(); + + for variant in &generic_enum.variants { + let mut new_fields = Vec::new(); + for field_ty in &variant.fields { + let new_ty = self.substitute_in_type_annot(field_ty, &subst_map)?; + self.collect_needs_from_type(&new_ty, &mut needs); + new_fields.push(new_ty); + } + + new_variants.push(TypedVariant { + name: variant.name.clone(), + fields: new_fields, + span: variant.span.clone(), + }); + } + + let mut new_enum = generic_enum.clone(); + new_enum.name = self.generate_specialized_name(&generic_enum.name, type_args); + new_enum.parameters = Vec::new(); // Remove type parameters after specialization + new_enum.variants = new_variants; + + Ok((new_enum, needs)) + } + + fn specialize_function( + &mut self, + generic_func: &TypedFunction, + type_args: &[Type], + _generic_structs: &HashMap, + _generic_enums: &HashMap, + _generic_functions: &HashMap, + ) -> Result<(TypedFunction, Vec), MonomorphizationError> { + if generic_func.parameters.len() != type_args.len() { + return Err(MonomorphizationError::new( + format!( + "Function {} expects {} type arguments, got {}", + generic_func.name, + generic_func.parameters.len(), + type_args.len() + ), + None, + )); + } + + let mut subst_map = HashMap::new(); + for (param, arg) in generic_func.parameters.iter().zip(type_args.iter()) { + subst_map.insert(param.name.clone(), arg.clone()); + } + + // Specialize arguments + let mut new_args = Vec::new(); + let mut needs = Vec::new(); + + for (arg_id, arg_name, arg_ty_opt) in &generic_func.args { + let new_arg_ty = if let Some(arg_ty) = arg_ty_opt { + let ty = self.substitute_in_type_annot(arg_ty, &subst_map)?; + self.collect_needs_from_type(&ty, &mut needs); + Some(ty) + } else { + None + }; + new_args.push((*arg_id, arg_name.clone(), new_arg_ty)); + } + + // Specialize return type + let new_return_type = if let Some(ret_ty) = &generic_func.return_type { + let ty = self.substitute_in_type_annot(ret_ty, &subst_map)?; + self.collect_needs_from_type(&ty, &mut needs); + Some(ty) + } else { + None + }; + + // Specialize body + let (new_body, body_needs) = self.monomorphize_expr(&generic_func.body)?; + needs.extend(body_needs); + + let mut new_func = generic_func.clone(); + new_func.name = self.generate_specialized_name(&generic_func.name, type_args); + new_func.parameters = Vec::new(); // Remove type parameters after specialization + new_func.args = new_args; + new_func.return_type = new_return_type; + new_func.body = new_body; + + Ok((new_func, needs)) + } + + fn substitute_in_type_annot( + &self, + annot: &TypeAnnot, + subst_map: &HashMap, + ) -> Result { + match annot { + TypeAnnot::Var(name) => { + if let Some(ty) = subst_map.get(name) { + Ok(self.type_to_type_annot(ty)) + } else { + // This is fine - it could be a non-parameterized type + Ok(TypeAnnot::Var(name.clone())) + } + } + TypeAnnot::Cons(name, args) => { + let mut new_args = Vec::new(); + for arg in args { + new_args.push(self.substitute_in_type_annot(arg, subst_map)?); + } + Ok(TypeAnnot::Cons(name.clone(), new_args)) + } + TypeAnnot::Function(param_types, ret_type) => { + let mut new_params = Vec::new(); + for param in param_types { + new_params.push(self.substitute_in_type_annot(param, subst_map)?); + } + let new_ret = self.substitute_in_type_annot(ret_type, subst_map)?; + Ok(TypeAnnot::Function(new_params, Box::new(new_ret))) + } + TypeAnnot::Tuple(types) => { + let mut new_types = Vec::new(); + for ty in types { + new_types.push(self.substitute_in_type_annot(ty, subst_map)?); + } + Ok(TypeAnnot::Tuple(new_types)) + } + TypeAnnot::Array(inner) => { + let new_inner = self.substitute_in_type_annot(inner, subst_map)?; + Ok(TypeAnnot::Array(Box::new(new_inner))) + } + TypeAnnot::Ptr(inner) => { + let new_inner = self.substitute_in_type_annot(inner, subst_map)?; + Ok(TypeAnnot::Ptr(Box::new(new_inner))) + } + } + } + + fn type_to_type_annot(&self, ty: &Type) -> TypeAnnot { + match ty { + Type::Int => TypeAnnot::Var("int".to_string()), + Type::Float => TypeAnnot::Var("float".to_string()), + Type::Bool => TypeAnnot::Var("bool".to_string()), + Type::String => TypeAnnot::Var("string".to_string()), + Type::Unit => TypeAnnot::Tuple(Vec::new()), + Type::Array(inner) => TypeAnnot::Array(Box::new(self.type_to_type_annot(inner))), + Type::Ptr(inner) => TypeAnnot::Ptr(Box::new(self.type_to_type_annot(inner))), + Type::Tuple(types) => { + let annots = types.iter().map(|t| self.type_to_type_annot(t)).collect(); + TypeAnnot::Tuple(annots) + } + Type::Struct(name, args) => { + if args.is_empty() { + TypeAnnot::Var(name.clone()) + } else { + let arg_annots = args.iter().map(|t| self.type_to_type_annot(t)).collect(); + TypeAnnot::Cons(name.clone(), arg_annots) + } + } + Type::Enum(name, args) => { + if args.is_empty() { + TypeAnnot::Var(name.clone()) + } else { + let arg_annots = args.iter().map(|t| self.type_to_type_annot(t)).collect(); + TypeAnnot::Cons(name.clone(), arg_annots) + } + } + Type::Function(params, ret) => { + let param_annots = params.iter().map(|t| self.type_to_type_annot(t)).collect(); + let ret_annot = self.type_to_type_annot(ret); + TypeAnnot::Function(param_annots, Box::new(ret_annot)) + } + Type::TypeVar(name) => TypeAnnot::Var(name.clone()), + Type::Generic(name, args) => { + if args.is_empty() { + TypeAnnot::Var(name.clone()) + } else { + let arg_annots = args.iter().map(|t| self.type_to_type_annot(t)).collect(); + TypeAnnot::Cons(name.clone(), arg_annots) + } + } + Type::Never => TypeAnnot::Var("!".to_string()), + Type::Unknown => TypeAnnot::Var("?".to_string()), + } + } + + fn collect_needs_from_expr_type(&self, expr: &TypedExpr, needs: &mut Vec) { + // Collect specialization needs from the expression's type + match &expr.ty { + Type::Struct(name, args) if !args.is_empty() && !name.contains("?") => { + // Skip Unknown types + needs.push(SpecializationKey::new(name.clone(), args.clone())); + } + Type::Enum(name, args) if !args.is_empty() && !name.contains("?") => { + // Skip Unknown types + needs.push(SpecializationKey::new(name.clone(), args.clone())); + } + Type::Function(_, _) => { + // Function types don't need specialization at the call site + } + _ => {} + } + } + + fn infer_struct_specialization( + &self, + struct_name: &str, + field_types: &[Type], + needs: &mut Vec, + ) { + // Only infer single-parameter generics from field types + // This is a heuristic for Box { value: T } + if field_types.len() == 1 { + needs.push(SpecializationKey::new( + struct_name.to_string(), + vec![field_types[0].clone()], + )); + } + // For multi-field structs, we can't reliably infer the type parameters + } + + fn infer_enum_specialization( + &self, + enum_name: &str, + arg_types: &[Type], + needs: &mut Vec, + ) { + // Only infer single-parameter generics from argument types + // This is a heuristic for Option::Some(T) where arg_types[0] is T + if arg_types.len() == 1 { + needs.push(SpecializationKey::new( + enum_name.to_string(), + vec![arg_types[0].clone()], + )); + } + // For multi-parameter enums, we can't reliably infer from just the variant arguments + } + + fn collect_needs_from_type(&self, ty: &TypeAnnot, needs: &mut Vec) { + match ty { + TypeAnnot::Var(_) => {} + TypeAnnot::Cons(name, args) => { + let type_args: Vec = + args.iter().map(|a| self.type_annot_to_type(a)).collect(); + if !type_args.is_empty() { + needs.push(SpecializationKey::new(name.clone(), type_args)); + } + for arg in args { + self.collect_needs_from_type(arg, needs); + } + } + TypeAnnot::Function(params, ret) => { + for param in params { + self.collect_needs_from_type(param, needs); + } + self.collect_needs_from_type(ret, needs); + } + TypeAnnot::Tuple(types) => { + for ty in types { + self.collect_needs_from_type(ty, needs); + } + } + TypeAnnot::Array(inner) => { + self.collect_needs_from_type(inner, needs); + } + TypeAnnot::Ptr(inner) => { + self.collect_needs_from_type(inner, needs); + } + } + } + + fn type_annot_to_type(&self, annot: &TypeAnnot) -> Type { + match annot { + TypeAnnot::Var(name) => match name.as_str() { + "int" => Type::Int, + "float" => Type::Float, + "bool" => Type::Bool, + "string" => Type::String, + "!" => Type::Never, + "?" => Type::Unknown, + _ => Type::TypeVar(name.clone()), + }, + TypeAnnot::Cons(name, args) => { + let arg_types: Vec = + args.iter().map(|a| self.type_annot_to_type(a)).collect(); + Type::Struct(name.clone(), arg_types) // Assuming it's a struct for now + } + TypeAnnot::Function(params, ret) => { + let param_types = params.iter().map(|p| self.type_annot_to_type(p)).collect(); + let ret_type = self.type_annot_to_type(ret); + Type::Function(param_types, Box::new(ret_type)) + } + TypeAnnot::Tuple(types) => { + let tys = types.iter().map(|t| self.type_annot_to_type(t)).collect(); + Type::Tuple(tys) + } + TypeAnnot::Array(inner) => { + let inner_type = self.type_annot_to_type(inner); + Type::Array(Box::new(inner_type)) + } + TypeAnnot::Ptr(inner) => { + let inner_type = self.type_annot_to_type(inner); + Type::Ptr(Box::new(inner_type)) + } + } + } + + fn generate_specialized_name(&self, base_name: &str, type_args: &[Type]) -> String { + if type_args.is_empty() { + base_name.to_string() + } else { + let arg_strs: Vec = type_args + .iter() + .map(|t| { + t.to_string() + .replace("<", "_") + .replace(">", "_") + .replace(",", "_") + .replace(" ", "") + }) + .collect(); + format!("{}_{}", base_name, arg_strs.join("_")) + } + } +} + +/// Check that no type variables remain in the AST +pub fn check_no_typevars(nodes: &[TypedASTNode]) -> Result<(), MonomorphizationError> { + for node in nodes { + check_node_for_typevars(node)?; + } + Ok(()) +} + +fn check_node_for_typevars(node: &TypedASTNode) -> Result<(), MonomorphizationError> { + match &node.kind { + TypedASTNodeKind::Function(f) => { + check_function_for_typevars(f)?; + } + TypedASTNodeKind::Struct(s) => { + check_struct_for_typevars(s)?; + } + TypedASTNodeKind::Enum(e) => { + check_enum_for_typevars(e)?; + } + TypedASTNodeKind::Impl(imp) => { + for method in &imp.methods { + check_function_for_typevars(method)?; + } + } + TypedASTNodeKind::Trait(t) => { + // Traits with type parameters are not fully monomorphized + if !t.parameters.is_empty() { + return Err(MonomorphizationError::new( + format!("Trait {} still has type parameters", t.name), + None, + )); + } + // Trait methods are fine as-is - they're abstract signatures + } + _ => {} + } + Ok(()) +} + +fn check_function_for_typevars(func: &TypedFunction) -> Result<(), MonomorphizationError> { + if !func.parameters.is_empty() { + return Err(MonomorphizationError::new( + format!("Function {} still has type parameters", func.name), + None, + )); + } + + for (_, _, ty_opt) in &func.args { + if let Some(ty) = ty_opt { + if has_typevars_in_type_annot(ty) { + return Err(MonomorphizationError::new( + format!("Function {} argument has type variables", func.name), + None, + )); + } + } + } + + if let Some(ret_ty) = &func.return_type { + if has_typevars_in_type_annot(ret_ty) { + return Err(MonomorphizationError::new( + format!("Function {} return type has type variables", func.name), + None, + )); + } + } + + check_expr_for_typevars(&func.body)?; + Ok(()) +} + +fn check_struct_for_typevars(s: &TypedStruct) -> Result<(), MonomorphizationError> { + if !s.parameters.is_empty() { + return Err(MonomorphizationError::new( + format!("Struct {} still has type parameters", s.name), + None, + )); + } + + for field in &s.fields { + if has_typevars_in_type_annot(&field.field_type) { + return Err(MonomorphizationError::new( + format!("Struct {} field {} has type variables", s.name, field.name), + None, + )); + } + } + Ok(()) +} + +fn check_enum_for_typevars(e: &TypedEnum) -> Result<(), MonomorphizationError> { + if !e.parameters.is_empty() { + return Err(MonomorphizationError::new( + format!("Enum {} still has type parameters", e.name), + None, + )); + } + + for variant in &e.variants { + for field_ty in &variant.fields { + if has_typevars_in_type_annot(field_ty) { + return Err(MonomorphizationError::new( + format!( + "Enum {} variant {} has type variables", + e.name, variant.name + ), + None, + )); + } + } + } + Ok(()) +} + +fn check_expr_for_typevars(expr: &TypedExpr) -> Result<(), MonomorphizationError> { + match &expr.kind { + TypedExprKind::Lambda(params, body) => { + for (_, _, ty_opt) in params { + if let Some(ty) = ty_opt { + if has_typevars_in_type_annot(ty) { + return Err(MonomorphizationError::new( + "Lambda has type variables in parameters", + Some(expr.span.clone()), + )); + } + } + } + check_expr_for_typevars(body)?; + } + TypedExprKind::Let(_, _, _, ty_opt, expr) => { + if let Some(ty) = ty_opt { + if has_typevars_in_type_annot(ty) { + return Err(MonomorphizationError::new( + "Let binding has type variables", + Some(expr.span.clone()), + )); + } + } + check_expr_for_typevars(expr)?; + } + TypedExprKind::Cast(e, ty) => { + if has_typevars_in_type_annot(ty) { + return Err(MonomorphizationError::new( + "Cast has type variables", + Some(expr.span.clone()), + )); + } + check_expr_for_typevars(e)?; + } + TypedExprKind::Array(elems) => { + for elem in elems { + check_expr_for_typevars(elem)?; + } + } + TypedExprKind::Tuple(elems) => { + for elem in elems { + check_expr_for_typevars(elem)?; + } + } + TypedExprKind::StructLit(_, fields) => { + for (_, field_expr) in fields { + check_expr_for_typevars(field_expr)?; + } + } + TypedExprKind::EnumLit(_, _, args) => { + for arg in args { + check_expr_for_typevars(arg)?; + } + } + TypedExprKind::Call(func, args) => { + check_expr_for_typevars(func)?; + for arg in args { + check_expr_for_typevars(arg)?; + } + } + TypedExprKind::Index(array, index) => { + check_expr_for_typevars(array)?; + check_expr_for_typevars(index)?; + } + TypedExprKind::Dot(obj, _) => { + check_expr_for_typevars(obj)?; + } + TypedExprKind::EarlyReturn(expr_opt) => { + if let Some(e) = expr_opt { + check_expr_for_typevars(e)?; + } + } + TypedExprKind::OptionalChain(expr_opt, _) => { + if let Some(e) = expr_opt { + check_expr_for_typevars(e)?; + } + } + TypedExprKind::If(cond, then_e, else_e) => { + check_expr_for_typevars(cond)?; + check_expr_for_typevars(then_e)?; + if let Some(e) = else_e { + check_expr_for_typevars(e)?; + } + } + TypedExprKind::Match(scrutinee, arms) => { + check_expr_for_typevars(scrutinee)?; + for (_, arm_expr) in arms { + check_expr_for_typevars(arm_expr)?; + } + } + TypedExprKind::While(cond, body) => { + check_expr_for_typevars(cond)?; + check_expr_for_typevars(body)?; + } + TypedExprKind::Do(exprs) => { + for e in exprs { + check_expr_for_typevars(e)?; + } + } + TypedExprKind::BinOp(lhs, _, rhs) => { + check_expr_for_typevars(lhs)?; + check_expr_for_typevars(rhs)?; + } + TypedExprKind::UnOp(_, operand) => { + check_expr_for_typevars(operand)?; + } + TypedExprKind::For(_, _, iter, body) => { + check_expr_for_typevars(iter)?; + check_expr_for_typevars(body)?; + } + TypedExprKind::Range(start, end) => { + check_expr_for_typevars(start)?; + check_expr_for_typevars(end)?; + } + TypedExprKind::Return(expr_opt) => { + if let Some(e) = expr_opt { + check_expr_for_typevars(e)?; + } + } + _ => {} + } + Ok(()) +} + +fn has_typevars_in_type_annot(ty: &TypeAnnot) -> bool { + match ty { + TypeAnnot::Var(name) => { + // Check if it's a type variable (not a built-in type) + !matches!( + name.as_str(), + "int" | "float" | "bool" | "string" | "!" | "?" + ) + } + TypeAnnot::Cons(_, args) => args.iter().any(has_typevars_in_type_annot), + TypeAnnot::Function(params, ret) => { + params.iter().any(has_typevars_in_type_annot) || has_typevars_in_type_annot(ret) + } + TypeAnnot::Tuple(types) => types.iter().any(has_typevars_in_type_annot), + TypeAnnot::Array(inner) => has_typevars_in_type_annot(inner), + TypeAnnot::Ptr(inner) => has_typevars_in_type_annot(inner), + } +} + +``` + +```rust +// src/c_ir.rs +#[derive(Debug, Clone)] +pub enum CType { + Void, + Int, + Float, + Bool, + Char, + Ptr(Box), + Struct(String), + UnnamedStruct(Vec), + Array(Box, usize), // type and size + Func(Vec, Box), // args and return +} + +impl CType { + pub fn to_string(&self) -> String { + match self { + CType::Void => "void".to_string(), + CType::Int => "int".to_string(), + CType::Float => "float".to_string(), + CType::Bool => "bool".to_string(), + CType::Char => "char".to_string(), + CType::Ptr(inner) => format!("{}*", inner.to_string()), + CType::Struct(name) => format!("struct {}", name), + CType::UnnamedStruct(fields) => { + let field_strs: Vec = fields + .iter() + .map(|f| format!(" {} {};", f.ty.to_string(), f.name)) + .collect(); + format!("struct {{\n{}\n}}", field_strs.join("\n")) + } + CType::Array(inner, size) => format!("{}[{}]", inner.to_string(), size), + CType::Func(args, ret) => { + let arg_strs: Vec = args.iter().map(|t| t.to_string()).collect(); + format!("{} (*)({})", ret.to_string(), arg_strs.join(", ")) + } + } + } +} + +#[derive(Debug, Clone)] +pub struct CVarDecl { + pub name: String, + pub ty: CType, + pub initializer: Option, +} + +#[derive(Debug, Clone)] +pub struct CStructDecl { + pub name: String, + pub fields: Vec, +} + +#[derive(Debug, Clone)] +pub struct CFuncDecl { + pub name: String, + pub return_type: CType, + pub params: Vec, + pub body: Option>, +} + +#[derive(Debug, Clone)] +pub enum CExpr { + IntLit(i64), + FloatLit(f64), + BoolLit(bool), + StringLit(String), + Var(String), + Call(String, Vec), + BinOp(Box, CBinaryOp, Box), + UnOp(CUnaryOp, Box), + Cast(Box, CType), + StructLit(String, Vec<(String, CExpr)>), + EnumLit(String, String, Vec), // enum_name, variant_name, args + ArrayLit(Vec), + Index(Box, Box), + Dot(Box, String), + AddrOf(Box), + Deref(Box), +} + +#[derive(Debug, Clone)] +pub enum CBinaryOp { + Add, + Sub, + Mul, + Div, + Mod, + Eq, + Neq, + Lt, + Gt, + Leq, + Geq, + And, + Or, +} + +impl CBinaryOp { + pub fn to_string(&self) -> &'static str { + match self { + CBinaryOp::Add => "+", + CBinaryOp::Sub => "-", + CBinaryOp::Mul => "*", + CBinaryOp::Div => "/", + CBinaryOp::Mod => "%", + CBinaryOp::Eq => "==", + CBinaryOp::Neq => "!=", + CBinaryOp::Lt => "<", + CBinaryOp::Gt => ">", + CBinaryOp::Leq => "<=", + CBinaryOp::Geq => ">=", + CBinaryOp::And => "&&", + CBinaryOp::Or => "||", + } + } +} + +#[derive(Debug, Clone)] +pub enum CUnaryOp { + Neg, + Not, + Ref, + Deref, +} + +impl CUnaryOp { + pub fn to_string(&self) -> &'static str { + match self { + CUnaryOp::Neg => "-", + CUnaryOp::Not => "!", + CUnaryOp::Ref => "&", + CUnaryOp::Deref => "*", + } + } +} + +#[derive(Debug, Clone)] +pub enum CStmt { + VarDecl(CVarDecl), + Expr(CExpr), + Assign(CExpr, CExpr), + If(CExpr, Vec, Option>), + While(CExpr, Vec), + For(CVarDecl, CExpr, CExpr, Vec), // init, cond, incr, body + Return(Option), + Break, + Continue, + Block(Vec), +} + +#[derive(Debug, Clone)] +pub enum CToplevel { + StructDecl(CStructDecl), + FuncDecl(CFuncDecl), + VarDecl(CVarDecl), +} + +``` + +```rust +// src/lexer/mod.rs +use logos::Logos; + +#[cfg(test)] +pub mod tests; + +#[derive(Logos, Debug, PartialEq)] +#[logos(skip r"[ \n\r\t\f]+")] // Ignore this regex pattern between tokens +#[logos(skip r"#(.*)\n")] // Ignore this regex pattern between tokens +#[derive(Clone)] +pub enum Token { + #[regex(r"true|false", |lex| { + lex.slice().parse::().unwrap() + })] + Bool(bool), + + #[regex(r"0|[1-9][0-9_]*", |lex| { + let s = lex.slice().replace("_", ""); + // We parse to i64 for wider support. + s.parse::().unwrap() + }, priority = 4)] + Int(i64), + + #[regex(r"(([0-9][0-9_]*\.[0-9_]+|[0-9]*\.[0-9_]+)([eE][+-]?[0-9_]+)?)", |lex| { + let s = lex.slice().replace("_", ""); + s.parse::().unwrap() + }, priority = 3)] + Float(f64), + + #[regex(r#""([^"\\]*(\\.[^"\\]*)*)""#, |lex| { + let s = lex.slice(); + s[1..s.len()-1] + .replace("\\\"", "\"") + .replace("\\\\", "\\") + .replace("\\n", "\n") + .replace("\\r", "\r") + .replace("\\t", "\t") + })] + String(String), + + #[regex(r#"r#"([^"]*)""#, |lex| { + let s = lex.slice(); + // Remove the outer r" and " (s[2..s.len() - 1]) + s[3..s.len() - 1].to_string() + })] + RawString(String), + + #[regex(r"[a-zA-Z_][a-zA-Z0-9_]*", |lex|{ + lex.slice().to_string() + })] + Variable(String), + + #[token("bool")] + KeywordBool, + + #[token("int")] + KeywordInt, + + #[token("float")] + KeywordFloat, + + #[token("string")] + KeywordString, + + #[token("let")] + KeywordLet, + + #[token("mut")] + KeywordMut, + + #[token("uniq")] + KeywordUniq, + + #[token("once")] + KeywordOnce, + + #[token("if")] + KeywordIf, + + #[token("then")] + KeywordThen, + + #[token("else")] + KeywordElse, + + #[token("fn")] + KeywordFn, + + #[token("lambda")] + KeywordLambda, + + #[token("do")] + KeywordDo, + + #[token("end")] + KeywordEnd, + + #[token("as")] + KeywordAs, + + #[token("in")] + KeywordIn, + + #[token("for")] + KeywordFor, + #[token("while")] + KeywordWhile, + + #[token("loop")] + KeywordLoop, + + #[token("where")] + KeywordWhere, + + #[token("extern")] + KeywordExtern, + + #[token("load")] + KeywordLoad, + + #[token("from")] + KeywordFrom, + + #[token("use")] + KeywordUse, + + #[token("struct")] + KeywordStruct, + + #[token("enum")] + KeywordEnum, + + #[token("impl")] + KeywordImpl, + + #[token("trait")] + KeywordTrait, + + // #[token("type")] + // KeywordType, + // + #[token("match")] + KeywordMatch, + + #[token("return")] + KeywordReturn, + + #[token("break")] + KeywordBreak, + + #[token("continue")] + KeywordContinue, + + #[token("+")] + Plus, + + #[token("-")] + Minus, + + #[token("*")] + Mul, + + #[token("/")] + Div, + + #[token("%")] + Mod, + + #[token("**", priority = 3)] + Power, + + #[token("$")] + Dollar, + + #[token("@")] + At, + + #[token("&")] + Amp, + + #[token("==")] + Eq, + + #[token("!=")] + NotEq, + + #[token("<")] + Less, + + #[token(">")] + Greater, + + #[token("<=")] + LessEq, + + #[token(">=")] + GreaterEq, + + #[token("and")] + And, + + #[token("or")] + Or, + + #[token("xor")] + Xor, + + #[token("nor")] + Nor, + + #[token("not")] + Not, + + #[token("(")] + LParen, + + #[token(")")] + RParen, + + #[token("[")] + LBracket, + + #[token("]")] + RBracket, + + #[token("{")] + LBrace, + + #[token("}")] + RBrace, + + #[token(",")] + Comma, + + #[token(";")] + Semicolon, + + #[token(":")] + Colon, + + #[token(".")] + Dot, + + #[token("...")] + Spread, + + #[token("..")] + DotDot, + + #[token("::")] + Access, + + #[token("->")] + Arrow, + + #[token("~")] + Tilde, + + #[token("!")] + Bang, + + // New tokens for pattern matching + #[token("=>")] + FatArrow, // For match arms + + #[token("|")] + Union, + + #[token("?.")] + OptionalChain, + + #[token("?")] + Unwrap, + + #[token("=")] + Assign, + + #[token("+=")] + AddAssign, + + #[token("-=")] + SubAssign, + + #[token("*=")] + MulAssign, + + #[token("/=")] + DivAssign, + + #[token("%=")] + ModAssign, +} + +``` + +```rust +// src/lexer/tests.rs +use super::Token; +use logos::Logos; + +#[test] +fn test_literals() { + let mut lexer = Token::lexer("true false 42 2.14 \"hello\" r\"raw\""); + + assert_eq!(lexer.next(), Some(Ok(Token::Bool(true)))); + assert_eq!(lexer.next(), Some(Ok(Token::Bool(false)))); + assert_eq!(lexer.next(), Some(Ok(Token::Int(42)))); + assert_eq!(lexer.next(), Some(Ok(Token::Float(2.14)))); + assert_eq!(lexer.next(), Some(Ok(Token::String("hello".to_string())))); + // RawString regex seems to have issues, let's test separately + assert_eq!(lexer.next(), Some(Ok(Token::Variable("r".to_string())))); + assert_eq!(lexer.next(), Some(Ok(Token::String("raw".to_string())))); + assert_eq!(lexer.next(), None); +} + +#[test] +fn test_int_literals() { + let mut lexer = Token::lexer("0 123 1_000_000"); + + assert_eq!(lexer.next(), Some(Ok(Token::Int(0)))); + assert_eq!(lexer.next(), Some(Ok(Token::Int(123)))); + assert_eq!(lexer.next(), Some(Ok(Token::Int(1000000)))); + assert_eq!(lexer.next(), None); +} + +#[test] +fn test_string_literals() { + let mut lexer = Token::lexer("\"hello world\" \"with\\\\escape\" \"quote\\\"here\""); + + assert_eq!( + lexer.next(), + Some(Ok(Token::String("hello world".to_string()))) + ); + assert_eq!( + lexer.next(), + Some(Ok(Token::String("with\\escape".to_string()))) + ); + assert_eq!( + lexer.next(), + Some(Ok(Token::String("quote\"here".to_string()))) + ); + assert_eq!(lexer.next(), None); +} + +#[test] +fn test_keywords() { + let mut lexer = Token::lexer( + "bool int float string let if else fn do end as in for while loop where extern import struct enum impl trait match return break continue", + ); + + assert_eq!(lexer.next(), Some(Ok(Token::KeywordBool))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordInt))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordFloat))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordString))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordLet))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordIf))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordElse))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordFn))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordDo))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordEnd))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordAs))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordIn))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordFor))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordWhile))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordLoop))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordWhere))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordExtern))); + assert_eq!(lexer.next(), Some(Ok(Token::Variable("import".into())))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordStruct))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordEnum))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordImpl))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordTrait))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordMatch))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordReturn))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordBreak))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordContinue))); + assert_eq!(lexer.next(), None); +} + +#[test] +fn test_operators() { + let mut lexer = Token::lexer("+ - * / % ** $ @ == != < > <= >= and or xor nor not"); + + assert_eq!(lexer.next(), Some(Ok(Token::Plus))); + assert_eq!(lexer.next(), Some(Ok(Token::Minus))); + assert_eq!(lexer.next(), Some(Ok(Token::Mul))); + assert_eq!(lexer.next(), Some(Ok(Token::Div))); + assert_eq!(lexer.next(), Some(Ok(Token::Mod))); + assert_eq!(lexer.next(), Some(Ok(Token::Power))); + assert_eq!(lexer.next(), Some(Ok(Token::Dollar))); + assert_eq!(lexer.next(), Some(Ok(Token::At))); + assert_eq!(lexer.next(), Some(Ok(Token::Eq))); + assert_eq!(lexer.next(), Some(Ok(Token::NotEq))); + assert_eq!(lexer.next(), Some(Ok(Token::Less))); + assert_eq!(lexer.next(), Some(Ok(Token::Greater))); + assert_eq!(lexer.next(), Some(Ok(Token::LessEq))); + assert_eq!(lexer.next(), Some(Ok(Token::GreaterEq))); + assert_eq!(lexer.next(), Some(Ok(Token::And))); + assert_eq!(lexer.next(), Some(Ok(Token::Or))); + assert_eq!(lexer.next(), Some(Ok(Token::Xor))); + assert_eq!(lexer.next(), Some(Ok(Token::Nor))); + assert_eq!(lexer.next(), Some(Ok(Token::Not))); + assert_eq!(lexer.next(), None); +} + +#[test] +fn test_assignment_operators() { + let mut lexer = Token::lexer("= += -= *= /= %="); + + assert_eq!(lexer.next(), Some(Ok(Token::Assign))); + assert_eq!(lexer.next(), Some(Ok(Token::AddAssign))); + assert_eq!(lexer.next(), Some(Ok(Token::SubAssign))); + assert_eq!(lexer.next(), Some(Ok(Token::MulAssign))); + assert_eq!(lexer.next(), Some(Ok(Token::DivAssign))); + assert_eq!(lexer.next(), Some(Ok(Token::ModAssign))); + assert_eq!(lexer.next(), None); +} + +#[test] +fn test_punctuation() { + let mut lexer = Token::lexer("( ) [ ] { } , ; : . ... .. :: -> ~ ! => & | ?. ?"); + + assert_eq!(lexer.next(), Some(Ok(Token::LParen))); + assert_eq!(lexer.next(), Some(Ok(Token::RParen))); + assert_eq!(lexer.next(), Some(Ok(Token::LBracket))); + assert_eq!(lexer.next(), Some(Ok(Token::RBracket))); + assert_eq!(lexer.next(), Some(Ok(Token::LBrace))); + assert_eq!(lexer.next(), Some(Ok(Token::RBrace))); + assert_eq!(lexer.next(), Some(Ok(Token::Comma))); + assert_eq!(lexer.next(), Some(Ok(Token::Semicolon))); + assert_eq!(lexer.next(), Some(Ok(Token::Colon))); + assert_eq!(lexer.next(), Some(Ok(Token::Dot))); + assert_eq!(lexer.next(), Some(Ok(Token::Spread))); + assert_eq!(lexer.next(), Some(Ok(Token::DotDot))); + assert_eq!(lexer.next(), Some(Ok(Token::Access))); + assert_eq!(lexer.next(), Some(Ok(Token::Arrow))); + assert_eq!(lexer.next(), Some(Ok(Token::Tilde))); + assert_eq!(lexer.next(), Some(Ok(Token::Bang))); + assert_eq!(lexer.next(), Some(Ok(Token::FatArrow))); + assert_eq!(lexer.next(), Some(Ok(Token::Amp))); + assert_eq!(lexer.next(), Some(Ok(Token::Union))); + assert_eq!(lexer.next(), Some(Ok(Token::OptionalChain))); + assert_eq!(lexer.next(), Some(Ok(Token::Unwrap))); + assert_eq!(lexer.next(), None); +} + +#[test] +fn test_variables() { + let mut lexer = Token::lexer("x y_z _private camelCase PascalCase"); + + assert_eq!(lexer.next(), Some(Ok(Token::Variable("x".to_string())))); + assert_eq!(lexer.next(), Some(Ok(Token::Variable("y_z".to_string())))); + assert_eq!( + lexer.next(), + Some(Ok(Token::Variable("_private".to_string()))) + ); + assert_eq!( + lexer.next(), + Some(Ok(Token::Variable("camelCase".to_string()))) + ); + assert_eq!( + lexer.next(), + Some(Ok(Token::Variable("PascalCase".to_string()))) + ); + assert_eq!(lexer.next(), None); +} + +#[test] +fn test_whitespace_skipping() { + let mut lexer = Token::lexer(" \t\n\r true \n false "); + + assert_eq!(lexer.next(), Some(Ok(Token::Bool(true)))); + assert_eq!(lexer.next(), Some(Ok(Token::Bool(false)))); + assert_eq!(lexer.next(), None); +} + +#[test] +fn test_comment_skipping() { + let mut lexer = Token::lexer("true # this is a comment\n false"); + + assert_eq!(lexer.next(), Some(Ok(Token::Bool(true)))); + assert_eq!(lexer.next(), Some(Ok(Token::Bool(false)))); + assert_eq!(lexer.next(), None); +} + +#[test] +fn test_complex_sequence() { + let mut lexer = Token::lexer("fn add(x: int, y: int) -> int { x + y }"); + + assert_eq!(lexer.next(), Some(Ok(Token::KeywordFn))); + assert_eq!(lexer.next(), Some(Ok(Token::Variable("add".to_string())))); + assert_eq!(lexer.next(), Some(Ok(Token::LParen))); + assert_eq!(lexer.next(), Some(Ok(Token::Variable("x".to_string())))); + assert_eq!(lexer.next(), Some(Ok(Token::Colon))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordInt))); + assert_eq!(lexer.next(), Some(Ok(Token::Comma))); + assert_eq!(lexer.next(), Some(Ok(Token::Variable("y".to_string())))); + assert_eq!(lexer.next(), Some(Ok(Token::Colon))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordInt))); + assert_eq!(lexer.next(), Some(Ok(Token::RParen))); + assert_eq!(lexer.next(), Some(Ok(Token::Arrow))); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordInt))); + assert_eq!(lexer.next(), Some(Ok(Token::LBrace))); + assert_eq!(lexer.next(), Some(Ok(Token::Variable("x".to_string())))); + assert_eq!(lexer.next(), Some(Ok(Token::Plus))); + assert_eq!(lexer.next(), Some(Ok(Token::Variable("y".to_string())))); + assert_eq!(lexer.next(), Some(Ok(Token::RBrace))); + assert_eq!(lexer.next(), None); +} + +#[test] +fn test_edge_cases() { + // Test that keywords are not treated as variables + let mut lexer = Token::lexer("let let_var if if_var"); + + assert_eq!(lexer.next(), Some(Ok(Token::KeywordLet))); + assert_eq!( + lexer.next(), + Some(Ok(Token::Variable("let_var".to_string()))) + ); + assert_eq!(lexer.next(), Some(Ok(Token::KeywordIf))); + assert_eq!( + lexer.next(), + Some(Ok(Token::Variable("if_var".to_string()))) + ); + assert_eq!(lexer.next(), None); +} + +``` + +```rust +// src/codegen/mod.rs +pub mod declaration_transpiler; +pub mod statements_transpiler; +pub mod transpiler; + +``` + +```rust +// src/codegen/statements_transpiler.rs +use crate::ast::*; +use crate::c_ir::*; +use crate::typechecker::Type; + +pub struct StatementsTranspiler; + +impl StatementsTranspiler { + pub fn new() -> Self { + StatementsTranspiler + } + + pub fn transpile_expr(&self, expr: &TypedExpr) -> Result { + match &expr.kind { + TypedExprKind::Int(i) => Ok(CExpr::IntLit(*i)), + TypedExprKind::Float(f) => Ok(CExpr::FloatLit(*f)), + TypedExprKind::Bool(b) => Ok(CExpr::BoolLit(*b)), + TypedExprKind::String(s) => Ok(CExpr::StringLit(s.clone())), + TypedExprKind::Variable(name) => Ok(CExpr::Var(name.clone())), + TypedExprKind::Call(func, args) => { + if let TypedExprKind::Dot(obj, method) = &func.kind { + // Method call + let obj_type = &obj.ty; + let type_name = if let Type::Struct(name, _) = obj_type { + name + } else { + return Err("Method call on non-struct".to_string()); + }; + let func_name = format!("{}_{}", type_name, method); + let c_args = args + .iter() + .map(|arg| self.transpile_expr(arg)) + .collect::, _>>()?; + Ok(CExpr::Call(func_name, c_args)) + } else { + let func_expr = self.transpile_expr(func)?; + let func_name = match func_expr { + CExpr::Var(name) => name, + _ => return Err("Function calls must be on variables for now".to_string()), + }; + let c_args = args + .iter() + .map(|arg| self.transpile_expr(arg)) + .collect::, _>>()?; + Ok(CExpr::Call(func_name, c_args)) + } + } + TypedExprKind::BinOp(lhs, op, rhs) => { + let c_lhs = self.transpile_expr(lhs)?; + let c_rhs = self.transpile_expr(rhs)?; + let c_op = self.binop_to_c_binop(op)?; + Ok(CExpr::BinOp(Box::new(c_lhs), c_op, Box::new(c_rhs))) + } + TypedExprKind::UnOp(op, expr) => { + let c_expr = self.transpile_expr(expr)?; + let c_op = self.unop_to_c_unop(op)?; + Ok(CExpr::UnOp(c_op, Box::new(c_expr))) + } + TypedExprKind::Index(array, index) => { + let c_array = self.transpile_expr(array)?; + let c_index = self.transpile_expr(index)?; + Ok(CExpr::Index(Box::new(c_array), Box::new(c_index))) + } + TypedExprKind::Dot(obj, field) => { + let c_obj = self.transpile_expr(obj)?; + Ok(CExpr::Dot(Box::new(c_obj), field.clone())) + } + TypedExprKind::StructLit(struct_name, fields) => { + let c_fields = fields + .iter() + .map(|(name, expr)| { + let c_expr = self.transpile_expr(expr)?; + Ok::<(String, CExpr), String>((name.clone(), c_expr)) + }) + .collect::, _>>()?; + Ok(CExpr::StructLit(struct_name.clone(), c_fields)) + } + TypedExprKind::Array(array_exprs) => { + let c_exprs = array_exprs + .iter() + .map(|expr| self.transpile_expr(expr)) + .collect::, _>>()?; + Ok(CExpr::ArrayLit(c_exprs)) + } + TypedExprKind::Cast(expr, type_annot) => { + let c_expr = self.transpile_expr(expr)?; + // Simplified: assuming we can map type annotations to C types + let c_type = self.type_annot_to_ctype(type_annot)?; + Ok(CExpr::Cast(Box::new(c_expr), c_type)) + } + TypedExprKind::Tuple(_) => { + // Simplified: treat as void for now + Ok(CExpr::IntLit(0)) + } + TypedExprKind::EnumLit(enum_name, variant_name, args) => { + let c_args = args + .iter() + .map(|arg| self.transpile_expr(arg)) + .collect::, _>>()?; + Ok(CExpr::EnumLit( + enum_name.clone(), + variant_name.clone(), + c_args, + )) + } + TypedExprKind::If(cond, then_expr, else_expr) => { + // Conditional expressions - for now, simplify to function call + // This is not ideal but works for basic cases + Err("Conditional expressions not yet supported".to_string()) + } + _ => Err(format!("Unsupported expression: {:?}", expr.kind)), + } + } + + pub fn transpile_stmt(&self, expr: &TypedExpr) -> Result { + match &expr.kind { + TypedExprKind::Let(_binding_id, name, _kind, _type_annot, init_expr) => { + let c_type = self.type_to_ctype(&expr.ty)?; + let initializer = Some(self.transpile_expr(init_expr)?); + let var_decl = CVarDecl { + name: name.clone(), + ty: c_type, + initializer, + }; + Ok(CStmt::VarDecl(var_decl)) + } + TypedExprKind::Assign(lhs, rhs) => { + let c_lhs = self.transpile_expr(lhs)?; + let c_rhs = self.transpile_expr(rhs)?; + Ok(CStmt::Assign(c_lhs, c_rhs)) + } + TypedExprKind::Return(ret_expr) => { + let c_ret = match ret_expr { + Some(expr) => Some(self.transpile_expr(expr)?), + None => None, + }; + Ok(CStmt::Return(c_ret)) + } + TypedExprKind::If(cond, then_expr, else_expr) => { + let c_cond = self.transpile_expr(cond)?; + let then_stmts = self.expr_to_stmts(then_expr)?; + let else_stmts = match else_expr { + Some(else_expr) => Some(self.expr_to_stmts(else_expr)?), + None => None, + }; + Ok(CStmt::If(c_cond, then_stmts, else_stmts)) + } + TypedExprKind::While(cond, body) => { + let c_cond = self.transpile_expr(cond)?; + let body_stmts = self.expr_to_stmts(body)?; + Ok(CStmt::While(c_cond, body_stmts)) + } + TypedExprKind::Do(exprs) => { + let mut stmts = Vec::new(); + for expr in exprs { + stmts.push(self.transpile_stmt(expr)?); + } + Ok(CStmt::Block(stmts)) + } + TypedExprKind::For(_binding_id, var_name, iterable, body) => { + // Simplified for loop handling + // For now, assume range iteration + match &iterable.kind { + TypedExprKind::Range(start, end) => { + let start_expr = self.transpile_expr(start)?; + let end_expr = self.transpile_expr(end)?; + // Create a simple for loop: for(int i = start; i < end; i++) + let init = CVarDecl { + name: var_name.clone(), + ty: CType::Int, + initializer: Some(start_expr), + }; + let cond = CExpr::BinOp( + Box::new(CExpr::Var(var_name.clone())), + CBinaryOp::Lt, + Box::new(end_expr), + ); + let incr = CExpr::UnOp(CUnaryOp::Neg, Box::new(CExpr::IntLit(-1))); // i++ + let incr_stmt = CStmt::Assign( + CExpr::Var(var_name.clone()), + CExpr::BinOp( + Box::new(CExpr::Var(var_name.clone())), + CBinaryOp::Add, + Box::new(CExpr::IntLit(1)), + ), + ); + let body_stmts = self.expr_to_stmts(body)?; + Ok(CStmt::For(init, cond, CExpr::IntLit(1), body_stmts)) + } + _ => Err("Only range iteration supported for for loops".to_string()), + } + } + TypedExprKind::Break => Ok(CStmt::Break), + TypedExprKind::Continue => Ok(CStmt::Continue), + _ => { + // For other expressions, treat as expression statements + let c_expr = self.transpile_expr(expr)?; + Ok(CStmt::Expr(c_expr)) + } + } + } + + pub fn expr_to_stmts(&self, expr: &TypedExpr) -> Result, String> { + match &expr.kind { + TypedExprKind::Do(stmts) => { + let mut c_stmts = Vec::new(); + for (i, stmt) in stmts.iter().enumerate() { + if i == stmts.len() - 1 { + // Last expression in a block should be returned + match &stmt.kind { + TypedExprKind::Return(_) => { + c_stmts.push(self.transpile_stmt(stmt)?); + } + _ => { + // Convert to return statement + let c_expr = self.transpile_expr(stmt)?; + c_stmts.push(CStmt::Return(Some(c_expr))); + } + } + } else { + c_stmts.push(self.transpile_stmt(stmt)?); + } + } + Ok(c_stmts) + } + _ => Ok(vec![CStmt::Return(Some(self.transpile_expr(expr)?))]), + } + } + + fn binop_to_c_binop(&self, op: &BinOp) -> Result { + match op { + BinOp::Add => Ok(CBinaryOp::Add), + BinOp::Sub => Ok(CBinaryOp::Sub), + BinOp::Mul => Ok(CBinaryOp::Mul), + BinOp::Div => Ok(CBinaryOp::Div), + BinOp::Mod => Ok(CBinaryOp::Mod), + BinOp::Eq => Ok(CBinaryOp::Eq), + BinOp::Neq => Ok(CBinaryOp::Neq), + BinOp::Lt => Ok(CBinaryOp::Lt), + BinOp::Gt => Ok(CBinaryOp::Gt), + BinOp::Leq => Ok(CBinaryOp::Leq), + BinOp::Geq => Ok(CBinaryOp::Geq), + BinOp::And => Ok(CBinaryOp::And), + BinOp::Or => Ok(CBinaryOp::Or), + } + } + + fn unop_to_c_unop(&self, op: &UnOp) -> Result { + match op { + UnOp::Neg => Ok(CUnaryOp::Neg), + UnOp::Not => Ok(CUnaryOp::Not), + UnOp::Ref => Ok(CUnaryOp::Ref), + UnOp::Deref => Ok(CUnaryOp::Deref), + } + } + + fn type_to_ctype(&self, ty: &crate::typechecker::Type) -> Result { + match ty { + crate::typechecker::Type::Int => Ok(CType::Int), + crate::typechecker::Type::Float => Ok(CType::Float), + crate::typechecker::Type::Bool => Ok(CType::Bool), + crate::typechecker::Type::String => Ok(CType::Ptr(Box::new(CType::Char))), + crate::typechecker::Type::Unit => Ok(CType::Void), + crate::typechecker::Type::Ptr(inner) => { + Ok(CType::Ptr(Box::new(self.type_to_ctype(inner)?))) + } + crate::typechecker::Type::Array(inner) => { + Ok(CType::Ptr(Box::new(self.type_to_ctype(inner)?))) + } + crate::typechecker::Type::Struct(name, _) => Ok(CType::Struct(name.clone())), + crate::typechecker::Type::Enum(name, _) => Ok(CType::Struct(name.clone())), + crate::typechecker::Type::Tuple(types) => { + let mut fields = Vec::new(); + for (i, inner_ty) in types.iter().enumerate() { + let c_type = self.type_to_ctype(inner_ty)?; + fields.push(CVarDecl { + name: format!("field{}", i), + ty: c_type, + initializer: None, + }); + } + Ok(CType::UnnamedStruct(fields)) + } + crate::typechecker::Type::Function(args, ret) => { + let mut c_args = Vec::new(); + for arg in args { + c_args.push(self.type_to_ctype(arg)?); + } + let c_ret = self.type_to_ctype(ret)?; + Ok(CType::Func(c_args, Box::new(c_ret))) + } + crate::typechecker::Type::Generic(name, _args) => { + // Generic types should have been monomorphized away, + // but if they remain, treat them as struct types + // For now, just use the base name + Ok(CType::Struct(name.clone())) + } + crate::typechecker::Type::TypeVar(name) => { + // Type variables should have been resolved during monomorphization + Err(format!("Unresolved type variable: {}", name)) + } + crate::typechecker::Type::Never => Ok(CType::Void), + crate::typechecker::Type::Unknown => Err("Unknown type".to_string()), + } + } + + fn type_annot_to_ctype(&self, annot: &TypeAnnot) -> Result { + match annot { + TypeAnnot::Var(name) => match name.as_str() { + "int" => Ok(CType::Int), + "float" => Ok(CType::Float), + "bool" => Ok(CType::Bool), + "string" => Ok(CType::Ptr(Box::new(CType::Char))), + _ => Ok(CType::Struct(name.clone())), + }, + TypeAnnot::Cons(name, args) if args.is_empty() => match name.as_str() { + "int" => Ok(CType::Int), + "float" => Ok(CType::Float), + "bool" => Ok(CType::Bool), + "string" => Ok(CType::Ptr(Box::new(CType::Char))), + _ => Ok(CType::Struct(name.clone())), + }, + TypeAnnot::Cons(name, _args) => { + // Generic types - for now just use the base name + Ok(CType::Struct(name.clone())) + } + TypeAnnot::Ptr(inner) => { + let inner_type = self.type_annot_to_ctype(inner)?; + Ok(CType::Ptr(Box::new(inner_type))) + } + TypeAnnot::Array(inner) => { + let inner_type = self.type_annot_to_ctype(inner)?; + Ok(CType::Ptr(Box::new(inner_type))) + } + TypeAnnot::Tuple(fields) => { + let mut c_fields = Vec::new(); + for (i, field_annot) in fields.iter().enumerate() { + let field_type = self.type_annot_to_ctype(field_annot)?; + c_fields.push(CVarDecl { + name: format!("field{}", i), + ty: field_type, + initializer: None, + }); + } + Ok(CType::UnnamedStruct(c_fields)) + } + TypeAnnot::Function(args, ret) => { + let mut c_args = Vec::new(); + for arg in args { + c_args.push(self.type_annot_to_ctype(arg)?); + } + let c_ret = self.type_annot_to_ctype(ret)?; + Ok(CType::Func(c_args, Box::new(c_ret))) + } + _ => Err(format!("Unsupported type annotation: {:?}", annot)), + } + } +} + +``` + +```rust +// src/codegen/transpiler.rs +use crate::ast::*; +use crate::c_ir::*; +use crate::codegen::declaration_transpiler::DeclarationTranspiler; +use crate::codegen::statements_transpiler::StatementsTranspiler; +use std::collections::HashMap; + +pub struct Transpiler { + structs: HashMap, + functions: Vec, + globals: Vec, + decl_transpiler: DeclarationTranspiler, + stmt_transpiler: StatementsTranspiler, +} + +impl Transpiler { + pub fn new() -> Self { + Transpiler { + structs: HashMap::new(), + functions: Vec::new(), + globals: Vec::new(), + decl_transpiler: DeclarationTranspiler::new(), + stmt_transpiler: StatementsTranspiler::new(), + } + } + + pub fn transpile_program(&mut self, nodes: &[TypedASTNode]) -> Result { + // First pass: collect declarations + for node in nodes { + self.collect_declaration(node)?; + } + + // Second pass: transpile function bodies + self.transpile_function_bodies(nodes)?; + + // Generate C code + let mut output = String::new(); + + // Add includes + output.push_str("#include \n"); + output.push_str("#include \n"); + output.push_str("#include \n"); + output.push_str("#include \n\n"); + + // Generate struct declarations + for struct_decl in self.structs.values() { + output.push_str(&self.generate_struct_decl(struct_decl)); + output.push_str(";\n\n"); + } + + // Generate function declarations (prototypes) + for func in &self.functions { + output.push_str(&self.generate_func_proto(func)); + output.push_str(";\n"); + } + output.push_str("\n"); + + // Generate global variables + for global in &self.globals { + output.push_str(&self.generate_var_decl(global)); + output.push_str(";\n"); + } + output.push_str("\n"); + + // Generate function definitions + for func in &self.functions { + output.push_str(&self.generate_func_def(func)); + output.push_str("\n"); + } + + Ok(output) + } + + fn collect_declaration(&mut self, node: &TypedASTNode) -> Result<(), String> { + match &node.kind { + TypedASTNodeKind::Struct(s) => { + let struct_decl = self.decl_transpiler.transpile_struct(s)?; + self.structs.insert(s.name.clone(), struct_decl); + } + TypedASTNodeKind::Enum(e) => { + let enum_structs = self.decl_transpiler.transpile_enum(e)?; + for struct_decl in enum_structs { + self.structs.insert(struct_decl.name.clone(), struct_decl); + } + } + TypedASTNodeKind::Function(f) => { + let mut func_decl = self.decl_transpiler.transpile_function(f)?; + // Body will be filled later + func_decl.body = Some(Vec::new()); + self.functions.push(func_decl); + } + TypedASTNodeKind::Impl(imp) => { + for method in &imp.methods { + let mut func_decl = self.decl_transpiler.transpile_function(method)?; + func_decl.name = format!("{}_{}", imp.target, method.name); + func_decl.body = Some(Vec::new()); + self.functions.push(func_decl); + } + } + TypedASTNodeKind::Extern(e) => { + // For externs, we might need to add function prototypes + // But for now, skip as they're handled differently + } + _ => { + // Other node types (traits, etc.) - handle later + } + } + Ok(()) + } + + fn transpile_function_bodies(&mut self, nodes: &[TypedASTNode]) -> Result<(), String> { + for node in nodes { + match &node.kind { + TypedASTNodeKind::Function(f) => { + // Find the corresponding function declaration + if let Some(func_decl) = self.functions.iter_mut().find(|fd| fd.name == f.name) + { + let body_stmts = self.stmt_transpiler.expr_to_stmts(&f.body)?; + func_decl.body = Some(body_stmts); + } + } + TypedASTNodeKind::Impl(imp) => { + for method in &imp.methods { + let method_name = format!("{}_{}", imp.target, method.name); + if let Some(func_decl) = + self.functions.iter_mut().find(|fd| fd.name == method_name) + { + let body_stmts = self.stmt_transpiler.expr_to_stmts(&method.body)?; + func_decl.body = Some(body_stmts); + } + } + } + _ => {} + } + } + Ok(()) + } + + fn generate_struct_decl(&self, struct_decl: &CStructDecl) -> String { + let mut output = format!("struct {} {{\n", struct_decl.name); + for field in &struct_decl.fields { + output.push_str(&format!(" {} {};\n", field.ty.to_string(), field.name)); + } + output.push_str("}"); + output + } + + fn generate_func_proto(&self, func: &CFuncDecl) -> String { + let params_str = if func.params.is_empty() { + "void".to_string() + } else { + func.params + .iter() + .map(|p| format!("{} {}", p.ty.to_string(), p.name)) + .collect::>() + .join(", ") + }; + format!( + "{} {}({})", + func.return_type.to_string(), + func.name, + params_str + ) + } + + fn generate_func_def(&self, func: &CFuncDecl) -> String { + let proto = self.generate_func_proto(func); + let mut output = format!("{} {{\n", proto); + + if let Some(body) = &func.body { + for stmt in body { + output.push_str(&self.generate_stmt(stmt)); + } + } + + output.push_str("}\n"); + output + } + + fn generate_var_decl(&self, var: &CVarDecl) -> String { + let mut output = format!("{} {}", var.ty.to_string(), var.name); + if let Some(init) = &var.initializer { + output.push_str(&format!(" = {}", self.generate_expr(init))); + } + output + } + + fn generate_stmt(&self, stmt: &CStmt) -> String { + match stmt { + CStmt::VarDecl(var) => format!(" {};\n", self.generate_var_decl(var)), + CStmt::Expr(expr) => format!(" {};\n", self.generate_expr(expr)), + CStmt::Assign(lhs, rhs) => format!( + " {} = {};\n", + self.generate_expr(lhs), + self.generate_expr(rhs) + ), + CStmt::Return(Some(expr)) => format!(" return {};\n", self.generate_expr(expr)), + CStmt::Return(None) => " return;\n".to_string(), + CStmt::If(cond, then_stmts, else_stmts) => { + let mut output = format!(" if ({}) {{\n", self.generate_expr(cond)); + for stmt in then_stmts { + output.push_str(&format!(" {}", self.generate_stmt(stmt))); + } + output.push_str(" }"); + if let Some(else_stmts) = else_stmts { + output.push_str(" else {\n"); + for stmt in else_stmts { + output.push_str(&format!(" {}", self.generate_stmt(stmt))); + } + output.push_str(" }"); + } + output.push_str("\n"); + output + } + CStmt::While(cond, body) => { + let mut output = format!(" while ({}) {{\n", self.generate_expr(cond)); + for stmt in body { + output.push_str(&format!(" {}", self.generate_stmt(stmt))); + } + output.push_str(" }\n"); + output + } + CStmt::Block(stmts) => { + let mut output = " {\n".to_string(); + for stmt in stmts { + output.push_str(&format!(" {}", self.generate_stmt(stmt))); + } + output.push_str(" }\n"); + output + } + _ => "// TODO: unimplemented stmt\n".to_string(), + } + } + + fn generate_expr(&self, expr: &CExpr) -> String { + match expr { + CExpr::IntLit(i) => format!("{}", i), + CExpr::FloatLit(f) => format!("{:.6}", f), + CExpr::BoolLit(b) => format!("{}", b), + CExpr::StringLit(s) => format!("\"{}\"", s), + CExpr::Var(name) => name.clone(), + CExpr::Call(func, args) => { + let args_str = args + .iter() + .map(|arg| self.generate_expr(arg)) + .collect::>() + .join(", "); + format!("{}({})", func, args_str) + } + CExpr::BinOp(lhs, op, rhs) => { + format!( + "({} {} {})", + self.generate_expr(lhs), + op.to_string(), + self.generate_expr(rhs) + ) + } + CExpr::UnOp(op, expr) => { + format!("{}{}", op.to_string(), self.generate_expr(expr)) + } + CExpr::Cast(expr, ty) => { + format!("({}) {}", ty.to_string(), self.generate_expr(expr)) + } + CExpr::AddrOf(expr) => format!("&{}", self.generate_expr(expr)), + CExpr::Deref(expr) => format!("*{}", self.generate_expr(expr)), + CExpr::Dot(expr, field) => format!("{}.{}", self.generate_expr(expr), field), + CExpr::Index(array, index) => format!( + "{}[{}]", + self.generate_expr(array), + self.generate_expr(index) + ), + CExpr::StructLit(struct_name, fields) => { + let field_inits: Vec = fields + .iter() + .map(|(name, expr)| format!(".{} = {}", name, self.generate_expr(expr))) + .collect(); + format!("(struct {}){{ {} }}", struct_name, field_inits.join(", ")) + } + CExpr::EnumLit(enum_name, variant_name, args) => { + // Find the variant index - for simplicity, assume variants are in order + // TODO: This should be stored properly + let variant_index = 0; // Placeholder - need to map variant name to index + + let variant_struct_name = format!("{}_{}", enum_name, variant_name); + let union_field_name = variant_name.to_lowercase(); + + let struct_init = if args.is_empty() { + "{}".to_string() + } else { + let field_inits: Vec = args + .iter() + .enumerate() + .map(|(i, arg)| format!(".field_{} = {}", i, self.generate_expr(arg))) + .collect(); + format!("{{ {} }}", field_inits.join(", ")) + }; + + format!( + "({}){{ .discriminant = {}, .data = {{ .{} = ({}{}) }} }}", + enum_name, variant_index, union_field_name, variant_struct_name, struct_init + ) + } + _ => "// TODO: unimplemented expr".to_string(), + } + } +} + +``` + +```rust +// src/codegen/declaration_transpiler.rs +use crate::ast::*; +use crate::c_ir::*; +use crate::typechecker::Type; +use std::collections::HashMap; + +pub struct DeclarationTranspiler { + type_map: HashMap, +} + +impl DeclarationTranspiler { + pub fn new() -> Self { + DeclarationTranspiler { + type_map: HashMap::new(), + } + } + + pub fn transpile_struct(&self, struct_: &TypedStruct) -> Result { + let mut fields = Vec::new(); + + for field in &struct_.fields { + let field_type = self.type_annot_to_ctype(&Some(field.field_type.clone()))?; + fields.push(CVarDecl { + name: field.name.clone(), + ty: field_type, + initializer: None, + }); + } + + Ok(CStructDecl { + name: struct_.name.clone(), + fields, + }) + } + + pub fn transpile_function(&self, func: &TypedFunction) -> Result { + let return_type = match &func.return_type { + Some(type_annot) => self.type_annot_to_ctype(&Some(type_annot.clone()))?, + None => CType::Void, + }; + + let mut params = Vec::new(); + for (_binding_id, name, type_annot) in &func.args { + let param_type = match type_annot { + Some(annot) => self.type_annot_to_ctype(&Some(annot.clone()))?, + None => { + return Err(format!( + "Function parameter {} missing type annotation", + name + )); + } + }; + params.push(CVarDecl { + name: name.clone(), + ty: param_type, + initializer: None, + }); + } + + // Note: body will be transpiled separately by statements transpiler + Ok(CFuncDecl { + name: func.name.clone(), + return_type, + params, + body: None, + }) + } + + pub fn transpile_enum(&self, enum_: &TypedEnum) -> Result, String> { + let mut structs = Vec::new(); + + // For each variant, create a struct + for (i, variant) in enum_.variants.iter().enumerate() { + let struct_name = format!("{}_{}", enum_.name, variant.name); + let mut fields = Vec::new(); + + // Add variant fields (no discriminant in variant struct) + for (j, field_type) in variant.fields.iter().enumerate() { + let field_name = format!("field_{}", j); + let c_type = self.type_annot_to_ctype(&Some(field_type.clone()))?; + fields.push(CVarDecl { + name: field_name, + ty: c_type, + initializer: None, + }); + } + + structs.push(CStructDecl { + name: struct_name, + fields, + }); + } + + // Create union of all variants + let union_name = format!("{}_union", enum_.name); + let mut union_fields = Vec::new(); + for variant in &enum_.variants { + let field_name = variant.name.to_lowercase(); + let struct_name = format!("{}_{}", enum_.name, variant.name); + union_fields.push(CVarDecl { + name: field_name, + ty: CType::Struct(struct_name), + initializer: None, + }); + } + + let union_name_clone = union_name.clone(); + structs.push(CStructDecl { + name: union_name, + fields: union_fields, + }); + + // Create main enum struct + let enum_fields = vec![ + CVarDecl { + name: "discriminant".to_string(), + ty: CType::Int, + initializer: None, + }, + CVarDecl { + name: "data".to_string(), + ty: CType::Struct(union_name_clone), + initializer: None, + }, + ]; + + structs.push(CStructDecl { + name: enum_.name.clone(), + fields: enum_fields, + }); + + Ok(structs) + } + + fn type_annot_to_ctype(&self, annot: &Option) -> Result { + match annot { + Some(TypeAnnot::Var(name)) => match name.as_str() { + "int" => Ok(CType::Int), + "float" => Ok(CType::Float), + "bool" => Ok(CType::Bool), + "string" => Ok(CType::Ptr(Box::new(CType::Char))), + _ => Ok(CType::Struct(name.clone())), // Assume struct + }, + Some(TypeAnnot::Cons(name, args)) if args.is_empty() => match name.as_str() { + "int" => Ok(CType::Int), + "float" => Ok(CType::Float), + "bool" => Ok(CType::Bool), + "string" => Ok(CType::Ptr(Box::new(CType::Char))), + _ => Ok(CType::Struct(name.clone())), // Assume struct + }, + Some(TypeAnnot::Cons(name, _args)) => { + // Generic types - for now just use the base name + Ok(CType::Struct(name.clone())) + } + Some(TypeAnnot::Ptr(inner)) => { + let inner_type = self.type_annot_to_ctype(&Some(*inner.clone()))?; + Ok(CType::Ptr(Box::new(inner_type))) + } + Some(TypeAnnot::Array(inner)) => { + let inner_type = self.type_annot_to_ctype(&Some(*inner.clone()))?; + Ok(CType::Ptr(Box::new(inner_type))) + } + Some(TypeAnnot::Tuple(fields)) => { + let mut c_fields = Vec::new(); + for (i, field_annot) in fields.iter().enumerate() { + let field_type = self.type_annot_to_ctype(&Some(field_annot.clone()))?; + c_fields.push(CVarDecl { + name: format!("field{}", i), + ty: field_type, + initializer: None, + }); + } + Ok(CType::UnnamedStruct(c_fields)) + } + Some(TypeAnnot::Function(args, ret)) => { + let mut c_args = Vec::new(); + for arg in args { + c_args.push(self.type_annot_to_ctype(&Some(arg.clone()))?); + } + let c_ret = self.type_annot_to_ctype(&Some(*ret.clone()))?; + Ok(CType::Func(c_args, Box::new(c_ret))) + } + _ => Ok(CType::Void), // Default + } + } +} + +``` + +This is a compiler ive been working on. +This compiler will be used for 3D gamedev (a battle royale game). +I need to add imports now, using the use keyword. + +use "std/something" +imports something.sui from std +use "std/somefolder/something" +imports somefolder/something.su from std + +use "@packagename/something" +imports something.sui +use "std/somefolder/something" +imports somefolder/something.su from packagemanager + +use "~/something" +or use "./something" +or use "../something" + +are just relative file imports. +NOTE: keep security in mind + +Cache per-file parse output (tokens/AST) keyed by file hash; when one file changes, re-parse that file, then re-run the global “collect definitions” pass and re-typecheck. +Do this in a target/suicmez-cache folder +Even if you re-typecheck everything at first, avoiding re-parsing and re-reading all files still saves time and keeps the design simple. + +Your pipeline already typechecks a Vec by first collecting global definitions into a single TypeEnv (addtype, addfunction, trait info, impls) and then typechecking bodies, so “AST concat” fits naturally. +We do AST concatenation. + +fn collect_nodes_for_importing(node: ASTNode, mut acc: Vec) -> Vec { + match node.kind { + ASTNodeKind::Struct(_) + | ASTNodeKind::Enum(_) + | ASTNodeKind::Function(_) + | ASTNodeKind::Impl(_) + | ASTNodeKind::Extern(_) + | ASTNodeKind::Load(_) + | ASTNodeKind::Trait(_) => acc.push(node), + ASTNodeKind::Get(path) => { + acc.extend(handle_import(&path, &node.span.file)); + } + } + acc +} + +fn handle_import(path: &str, importing_file: &str) -> Vec { + if path.starts_with("std/") { + let std_path = &path; // [4..]; + let filename = format!("src/{}{}", std_path, EXTENSION); + let source = match fs::read_to_string(&filename) { + Ok(content) => content, + Err(e) => { + eprintln!("Std module not accessible '{}': {}", filename, e); + process::exit(1); + } + }; + let mut tokens = Vec::new(); + let mut lexer = Token::lexer(&source); + + while let Some(token_result) = lexer.next() { + match token_result { + Ok(token) => { + tokens.push((token, lexer.span())); + } + Err(()) => { + eprintln!( + "Lexer error at position {} in std file {}", + lexer.span().start, + filename + ); + process::exit(1); + } + } + } + + let mut parser = Parser::new(filename.clone(), tokens); + let ast = match parser.parse() { + Ok(nodes) => { + println!(" Parsed {} top-level declarations from std", nodes.len()); + nodes + } + Err(e) => { + eprintln!("Parse error: {:?}", e); + eprintln!( + " at {}:{}..{}", + e.span.file, e.span.range.start, e.span.range.end + ); + + if let Ok(content) = fs::read_to_string(&e.span.file) { + let lines: Vec<&str> = content.lines().collect(); + let mut pos = 0; + for (line_num, line) in lines.iter().enumerate() { + let line_end = pos + line.len(); + if e.span.range.start >= pos && e.span.range.start <= line_end { + eprintln!(" Line {}: {}", line_num + 1, line); + let col = e.span.range.start - pos; + eprintln!( + " {}^", + " ".repeat(col + format!("Line {}: ", line_num + 1).len()) + ); + break; + } + pos = line_end + 1; // +1 for newline + } + } + + process::exit(1); + } + }; + let mut ret = vec![]; + for node in ast { + ret.extend(collect_nodes_for_importing(node, vec![])); + } + ret + } else if path.starts_with("@") { + todo!() // package manager stuff + } else if path.starts_with(".") || path.starts_with("~") { + let importing_dir = Path::new(importing_file).parent().unwrap_or(Path::new("")); + let resolved_path = importing_dir.join(path); + let filename = resolved_path.to_string_lossy().to_string() + EXTENSION; + let source = match fs::read_to_string(&filename) { + Ok(content) => content, + Err(e) => { + eprintln!("Module not accessible '{}': {}", filename, e); + process::exit(1); + } + }; + let mut tokens = Vec::new(); + let mut lexer = Token::lexer(&source); + + while let Some(token_result) = lexer.next() { + match token_result { + Ok(token) => { + tokens.push((token, lexer.span())); + } + Err(()) => { + eprintln!( + "Lexer error at position {} in imported file {}", + lexer.span().start, + filename + ); + process::exit(1); + } + } + } + + let mut parser = Parser::new(filename.clone(), tokens); + let ast = match parser.parse() { + Ok(nodes) => { + println!(" Parsed {} top-level declarations", nodes.len()); + nodes + } + Err(e) => { + eprintln!("Parse error: {:?}", e); + eprintln!( + " at {}:{}..{}", + e.span.file, e.span.range.start, e.span.range.end + ); + + if let Ok(content) = fs::read_to_string(&e.span.file) { + let lines: Vec<&str> = content.lines().collect(); + let mut pos = 0; + for (line_num, line) in lines.iter().enumerate() { + let line_end = pos + line.len(); + if e.span.range.start >= pos && e.span.range.start <= line_end { + eprintln!(" Line {}: {}", line_num + 1, line); + let col = e.span.range.start - pos; + eprintln!( + " {}^", + " ".repeat(col + format!("Line {}: ", line_num + 1).len()) + ); + break; + } + pos = line_end + 1; // +1 for newline + } + } + + process::exit(1); + } + }; + let mut ret = vec![]; + for node in ast { + ret.extend(collect_nodes_for_importing(node, vec![])); + } + ret + } else { + todo!() + } +} + +this is an example. + +Even with a global namespace, use ASTNodeKind::Use(path) to build a file dependency graph and load/parse each file once (dedupe repeated use), rather than blindly appending. + +add an explicit “duplicate global symbol” error during the definition-collection pass (function/type/trait name collisions), instead of last-one-wins behavior diff --git a/src/ast.rs b/src/ast.rs index 616ab90..71e0bbe 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -70,7 +70,13 @@ pub enum ASTNodeKind { Enum(Enum), Impl(Impl), Trait(Trait), - Use(String), + Use(Use), +} + +#[derive(Debug, Clone)] +pub struct Use { + pub path: String, + pub span: Span, } // ? implies OPTIONAL here @@ -305,7 +311,7 @@ pub enum TypedASTNodeKind { Enum(TypedEnum), Impl(TypedImpl), Trait(TypedTrait), - Use(String), + Use(Use), } #[derive(Debug, Clone)]