From 0dd716182975d2fdd6e47f72c540107f4512d445 Mon Sep 17 00:00:00 2001 From: Masashi Date: Tue, 16 Dec 2025 14:37:51 +0530 Subject: [PATCH 1/2] use --- output.md | 8036 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ast.rs | 10 +- 2 files changed, 8044 insertions(+), 2 deletions(-) create mode 100644 output.md 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)] From 376152f4659399d3ff4c805654b0578b81e0d364 Mon Sep 17 00:00:00 2001 From: Masashi Date: Tue, 16 Dec 2025 14:38:03 +0530 Subject: [PATCH 2/2] use --- output.md | 8036 ----------------------------------------------------- 1 file changed, 8036 deletions(-) delete mode 100644 output.md diff --git a/output.md b/output.md deleted file mode 100644 index 338d02d..0000000 --- a/output.md +++ /dev/null @@ -1,8036 +0,0 @@ -```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