//! Parser for the Lux language #![allow(dead_code)] use crate::ast::*; use crate::diagnostics::{Diagnostic, ErrorCode, Severity}; use crate::lexer::{LexError, Lexer, StringPart, Token, TokenKind}; use std::fmt; /// Parser error #[derive(Debug, Clone)] pub struct ParseError { pub message: String, pub span: Span, } impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Parse error at {}-{}: {}", self.span.start, self.span.end, self.message ) } } impl ParseError { /// Convert to a rich diagnostic for Elm-style error display pub fn to_diagnostic(&self) -> Diagnostic { let (code, title, hints) = categorize_parse_error(&self.message); Diagnostic { severity: Severity::Error, code, title, message: self.message.clone(), span: self.span, hints, expected_type: None, actual_type: None, secondary_spans: Vec::new(), } } } /// Categorize parse errors to provide better titles, hints, and error codes fn categorize_parse_error(message: &str) -> (Option, String, Vec) { let message_lower = message.to_lowercase(); if message_lower.contains("unexpected") && message_lower.contains("expected") { ( Some(ErrorCode::E0101), "Unexpected Token".to_string(), vec!["Check for missing or misplaced punctuation.".to_string()], ) } else if message_lower.contains("expected") && message_lower.contains("expression") { ( Some(ErrorCode::E0101), "Missing Expression".to_string(), vec!["An expression was expected here.".to_string()], ) } else if message_lower.contains("expected") && message_lower.contains(":") { ( Some(ErrorCode::E0104), "Missing Type Annotation".to_string(), vec!["A type annotation is required here.".to_string()], ) } else if message_lower.contains("unclosed") || message_lower.contains("unterminated") { ( Some(ErrorCode::E0102), "Unclosed Delimiter".to_string(), vec![ "Check for matching opening and closing brackets.".to_string(), "Make sure all strings are properly closed with quotes.".to_string(), ], ) } else if message_lower.contains("invalid") && message_lower.contains("literal") { ( Some(ErrorCode::E0103), "Invalid Literal".to_string(), vec!["Check the format of the literal value.".to_string()], ) } else if message_lower.contains("invalid") && message_lower.contains("operator") { ( Some(ErrorCode::E0105), "Invalid Operator".to_string(), vec!["Check the operator syntax.".to_string()], ) } else if message_lower.contains("invalid") { ( Some(ErrorCode::E0100), "Invalid Syntax".to_string(), vec!["Check the syntax of this construct.".to_string()], ) } else if message_lower.contains("identifier") { ( Some(ErrorCode::E0100), "Invalid Identifier".to_string(), vec!["Identifiers must start with a letter and contain only letters, numbers, and underscores.".to_string()], ) } else { (Some(ErrorCode::E0100), "Parse Error".to_string(), vec![]) } } impl From for ParseError { fn from(err: LexError) -> Self { ParseError { message: err.message, span: err.span, } } } /// The parser pub struct Parser { tokens: Vec, pos: usize, eof_token: Token, } impl Parser { pub fn new(tokens: Vec) -> Self { Self { tokens, pos: 0, eof_token: Token::new(TokenKind::Eof, Span::default()), } } pub fn parse_source(source: &str) -> Result { let tokens = Lexer::new(source).tokenize()?; let mut parser = Parser::new(tokens); parser.parse_program() } /// Parse a complete program pub fn parse_program(&mut self) -> Result { let mut imports = Vec::new(); let mut declarations = Vec::new(); self.skip_newlines(); // Parse imports first (they must come before declarations) while self.check(TokenKind::Import) { imports.push(self.parse_import()?); self.skip_newlines(); } while !self.is_at_end() { declarations.push(self.parse_declaration()?); self.skip_newlines(); } Ok(Program { imports, declarations, }) } /// Parse an import declaration fn parse_import(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::Import)?; // Parse module path: foo/bar/baz let mut segments = vec![self.parse_ident()?]; while self.check(TokenKind::Slash) { self.advance(); segments.push(self.parse_ident()?); } let path_span = start.merge(self.previous_span()); let path = ModulePath { segments, span: path_span, }; // Check for wildcard import: import foo.* let wildcard = if self.check(TokenKind::Dot) && self.peek_next_kind() == TokenKind::Star { self.advance(); // . self.advance(); // * true } else { false }; // Check for selective import: import foo.{a, b, c} let items = if !wildcard && self.check(TokenKind::Dot) && self.peek_next_kind() == TokenKind::LBrace { self.advance(); // . self.advance(); // { let mut items = Vec::new(); while !self.check(TokenKind::RBrace) { items.push(self.parse_ident()?); if !self.check(TokenKind::RBrace) { self.expect(TokenKind::Comma)?; } } self.expect(TokenKind::RBrace)?; Some(items) } else { None }; // Check for alias: import foo as bar let alias = if self.check(TokenKind::As) { self.advance(); Some(self.parse_ident()?) } else { None }; let span = start.merge(self.previous_span()); Ok(ImportDecl { path, alias, items, wildcard, span, }) } /// Parse a top-level declaration fn parse_declaration(&mut self) -> Result { self.skip_newlines(); // Collect any doc comments before the declaration let doc = self.collect_doc_comments(); // Check for visibility modifier let visibility = if self.check(TokenKind::Pub) { self.advance(); Visibility::Public } else { Visibility::Private }; match self.peek_kind() { TokenKind::Fn => Ok(Declaration::Function(self.parse_function_decl(visibility, doc)?)), TokenKind::Effect => Ok(Declaration::Effect(self.parse_effect_decl(doc)?)), TokenKind::Handler => Ok(Declaration::Handler(self.parse_handler_decl()?)), TokenKind::Type => Ok(Declaration::Type(self.parse_type_decl(visibility, doc)?)), TokenKind::Let => Ok(Declaration::Let(self.parse_let_decl(visibility, doc)?)), TokenKind::Trait => Ok(Declaration::Trait(self.parse_trait_decl(visibility, doc)?)), TokenKind::Impl => Ok(Declaration::Impl(self.parse_impl_decl()?)), TokenKind::Run => Err(self.error("Bare 'run' expressions are not allowed at top level. Use 'let _ = run ...' or 'let result = run ...'")), _ => Err(self.error("Expected declaration (fn, effect, handler, type, trait, impl, or let)")), } } /// Collect consecutive doc comments into a single string fn collect_doc_comments(&mut self) -> Option { let mut docs = Vec::new(); while let TokenKind::DocComment(content) = self.peek_kind() { docs.push(content.clone()); self.advance(); self.skip_newlines(); } if docs.is_empty() { None } else { Some(docs.join("\n")) } } /// Parse a function declaration fn parse_function_decl(&mut self, visibility: Visibility, doc: Option) -> Result { let start = self.current_span(); self.expect(TokenKind::Fn)?; let name = self.parse_ident()?; // Optional type parameters let type_params = if self.check(TokenKind::Lt) { self.parse_type_params()? } else { Vec::new() }; self.expect(TokenKind::LParen)?; let params = self.parse_params()?; self.expect(TokenKind::RParen)?; // Return type self.expect(TokenKind::Colon)?; let return_type = self.parse_type()?; // Optional effects let effects = if self.check(TokenKind::With) { self.advance(); self.parse_effect_list()? } else { Vec::new() }; // Optional behavioral properties: is pure, is total, etc. let properties = self.parse_behavioral_properties()?; // Optional where clauses let where_clauses = self.parse_where_clauses()?; self.expect(TokenKind::Eq)?; self.skip_newlines(); let body = self.parse_expr()?; let span = start.merge(body.span()); Ok(FunctionDecl { visibility, doc, name, type_params, params, return_type, effects, properties, where_clauses, body, span, }) } /// Parse effect declaration fn parse_effect_decl(&mut self, doc: Option) -> Result { let start = self.current_span(); self.expect(TokenKind::Effect)?; let name = self.parse_ident()?; let type_params = if self.check(TokenKind::Lt) { self.parse_type_params()? } else { Vec::new() }; self.expect(TokenKind::LBrace)?; self.skip_newlines(); let mut operations = Vec::new(); while !self.check(TokenKind::RBrace) { operations.push(self.parse_effect_op()?); self.skip_newlines(); // Optional comma or newline separator if self.check(TokenKind::Comma) { self.advance(); } self.skip_newlines(); } let end = self.current_span(); self.expect(TokenKind::RBrace)?; Ok(EffectDecl { doc, name, type_params, operations, span: start.merge(end), }) } /// Parse an effect operation fn parse_effect_op(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::Fn)?; let name = self.parse_ident()?; self.expect(TokenKind::LParen)?; let params = self.parse_params()?; self.expect(TokenKind::RParen)?; self.expect(TokenKind::Colon)?; let return_type = self.parse_type()?; let span = start.merge(self.previous_span()); Ok(EffectOp { name, params, return_type, span, }) } /// Parse handler declaration fn parse_handler_decl(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::Handler)?; let name = self.parse_ident()?; // Optional parameters let params = if self.check(TokenKind::LParen) { self.advance(); let p = self.parse_params()?; self.expect(TokenKind::RParen)?; p } else { Vec::new() }; self.expect(TokenKind::Colon)?; let effect = self.parse_ident()?; self.expect(TokenKind::LBrace)?; self.skip_newlines(); let mut implementations = Vec::new(); while !self.check(TokenKind::RBrace) { implementations.push(self.parse_handler_impl()?); self.skip_newlines(); } let end = self.current_span(); self.expect(TokenKind::RBrace)?; Ok(HandlerDecl { name, params, effect, implementations, span: start.merge(end), }) } /// Parse handler implementation fn parse_handler_impl(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::Fn)?; let op_name = self.parse_ident()?; self.expect(TokenKind::LParen)?; let mut params = Vec::new(); while !self.check(TokenKind::RParen) { params.push(self.parse_ident()?); if !self.check(TokenKind::RParen) { self.expect(TokenKind::Comma)?; } } self.expect(TokenKind::RParen)?; // Optional resume parameter let resume = if self.check(TokenKind::With) { self.advance(); Some(self.parse_ident()?) } else { None }; self.expect(TokenKind::Eq)?; self.skip_newlines(); let body = self.parse_expr()?; let span = start.merge(body.span()); Ok(HandlerImpl { op_name, params, resume, body, span, }) } /// Parse type declaration fn parse_type_decl(&mut self, visibility: Visibility, doc: Option) -> Result { let start = self.current_span(); self.expect(TokenKind::Type)?; let name = self.parse_ident()?; let type_params = if self.check(TokenKind::Lt) { self.parse_type_params()? } else { Vec::new() }; // Check for version annotation: type User @v2 { ... } let version = if self.check(TokenKind::At) { Some(self.parse_version()?) } else { None }; // Check what kind of type definition let definition = if self.check(TokenKind::LBrace) { // Record type self.advance(); self.skip_newlines(); let fields = self.parse_record_fields()?; self.skip_newlines(); // Check for migrations inside the record: from @v1 = { ... } let migrations = self.parse_migrations()?; self.expect(TokenKind::RBrace)?; (TypeDef::Record(fields), migrations) } else if self.check(TokenKind::Eq) { self.advance(); self.skip_newlines(); if self.check(TokenKind::Pipe) { // Enum type - with leading | for variants (TypeDef::Enum(self.parse_variants()?), Vec::new()) } else if self.is_single_line_enum() { // Single-line enum without leading pipe: type Status = Ok | Error (TypeDef::Enum(self.parse_single_line_variants()?), Vec::new()) } else { // Type alias - any type expression (TypeDef::Alias(self.parse_type()?), Vec::new()) } } else { return Err(self.error("Expected '=' or '{' in type declaration")); }; let span = start.merge(self.previous_span()); Ok(TypeDecl { visibility, doc, name, type_params, version, definition: definition.0, migrations: definition.1, span, }) } /// Parse let declaration fn parse_let_decl(&mut self, visibility: Visibility, doc: Option) -> Result { let start = self.current_span(); self.expect(TokenKind::Let)?; // Allow underscore as wildcard pattern (discards the value) let name = if self.check(TokenKind::Underscore) { let span = self.current_span(); self.advance(); Ident::new("_".to_string(), span) } else { self.parse_ident()? }; let typ = if self.check(TokenKind::Colon) { self.advance(); Some(self.parse_type()?) } else { None }; self.expect(TokenKind::Eq)?; self.skip_newlines(); let value = self.parse_expr()?; let span = start.merge(value.span()); Ok(LetDecl { visibility, doc, name, typ, value, span, }) } /// Parse trait declaration: trait Show { fn show(self): String } fn parse_trait_decl(&mut self, visibility: Visibility, doc: Option) -> Result { let start = self.current_span(); self.expect(TokenKind::Trait)?; let name = self.parse_ident()?; // Optional type parameters: trait Functor { ... } let type_params = if self.check(TokenKind::Lt) { self.parse_type_params()? } else { Vec::new() }; // Optional super traits: trait Ord: Eq { ... } let super_traits = if self.check(TokenKind::Colon) { self.advance(); self.parse_trait_bounds()? } else { Vec::new() }; self.expect(TokenKind::LBrace)?; self.skip_newlines(); let mut methods = Vec::new(); while !self.check(TokenKind::RBrace) { methods.push(self.parse_trait_method()?); self.skip_newlines(); if self.check(TokenKind::Comma) { self.advance(); } self.skip_newlines(); } let end = self.current_span(); self.expect(TokenKind::RBrace)?; Ok(TraitDecl { visibility, doc, name, type_params, super_traits, methods, span: start.merge(end), }) } /// Parse a trait method signature fn parse_trait_method(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::Fn)?; let name = self.parse_ident()?; // Optional type parameters let type_params = if self.check(TokenKind::Lt) { self.parse_type_params()? } else { Vec::new() }; self.expect(TokenKind::LParen)?; let params = self.parse_params()?; self.expect(TokenKind::RParen)?; self.expect(TokenKind::Colon)?; let return_type = self.parse_type()?; // Optional default implementation let default_impl = if self.check(TokenKind::Eq) { self.advance(); self.skip_newlines(); Some(self.parse_expr()?) } else { None }; let span = start.merge(self.previous_span()); Ok(TraitMethod { name, type_params, params, return_type, default_impl, span, }) } /// Parse trait bounds: Eq + Ord + Show fn parse_trait_bounds(&mut self) -> Result, ParseError> { let mut bounds = Vec::new(); loop { bounds.push(self.parse_trait_bound()?); if self.check(TokenKind::Plus) { self.advance(); } else { break; } } Ok(bounds) } /// Parse a single trait bound: Show, Functor fn parse_trait_bound(&mut self) -> Result { let start = self.current_span(); let trait_name = self.parse_ident()?; let type_args = if self.check(TokenKind::Lt) { self.advance(); let mut args = Vec::new(); while !self.check(TokenKind::Gt) { args.push(self.parse_type()?); if !self.check(TokenKind::Gt) { self.expect(TokenKind::Comma)?; } } self.expect(TokenKind::Gt)?; args } else { Vec::new() }; let span = start.merge(self.previous_span()); Ok(TraitBound { trait_name, type_args, span, }) } /// Parse impl declaration: impl Show for Int { ... } fn parse_impl_decl(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::Impl)?; // Optional type parameters: impl Show for List { ... } let type_params = if self.check(TokenKind::Lt) { self.parse_type_params()? } else { Vec::new() }; // Parse the trait name let trait_name = self.parse_ident()?; // Optional type arguments for the trait: impl Functor for ... let trait_args = if self.check(TokenKind::Lt) { self.advance(); let mut args = Vec::new(); while !self.check(TokenKind::Gt) { args.push(self.parse_type()?); if !self.check(TokenKind::Gt) { self.expect(TokenKind::Comma)?; } } self.expect(TokenKind::Gt)?; args } else { Vec::new() }; self.expect(TokenKind::For)?; let target_type = self.parse_type()?; // Optional where clause with trait constraints let constraints = if self.check(TokenKind::Where) { self.parse_trait_constraints()? } else { Vec::new() }; self.expect(TokenKind::LBrace)?; self.skip_newlines(); let mut methods = Vec::new(); while !self.check(TokenKind::RBrace) { methods.push(self.parse_impl_method()?); self.skip_newlines(); if self.check(TokenKind::Comma) { self.advance(); } self.skip_newlines(); } let end = self.current_span(); self.expect(TokenKind::RBrace)?; Ok(ImplDecl { type_params, constraints, trait_name, trait_args, target_type, methods, span: start.merge(end), }) } /// Parse trait constraints in a where clause: where T: Show, U: Eq + Ord fn parse_trait_constraints(&mut self) -> Result, ParseError> { let mut constraints = Vec::new(); while self.check(TokenKind::Where) { self.advance(); let start = self.current_span(); let type_param = self.parse_ident()?; self.expect(TokenKind::Colon)?; let bounds = self.parse_trait_bounds()?; let span = start.merge(self.previous_span()); constraints.push(TraitConstraint { type_param, bounds, span, }); if self.check(TokenKind::Comma) { self.advance(); } } Ok(constraints) } /// Parse an impl method fn parse_impl_method(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::Fn)?; let name = self.parse_ident()?; self.expect(TokenKind::LParen)?; let params = self.parse_params()?; self.expect(TokenKind::RParen)?; // Optional return type (infer if not provided) let return_type = if self.check(TokenKind::Colon) { self.advance(); Some(self.parse_type()?) } else { None }; self.expect(TokenKind::Eq)?; self.skip_newlines(); let body = self.parse_expr()?; let span = start.merge(body.span()); Ok(ImplMethod { name, params, return_type, body, span, }) } /// Parse type parameters fn parse_type_params(&mut self) -> Result, ParseError> { self.expect(TokenKind::Lt)?; let mut params = Vec::new(); while !self.check(TokenKind::Gt) { params.push(self.parse_ident()?); if !self.check(TokenKind::Gt) { self.expect(TokenKind::Comma)?; } } self.expect(TokenKind::Gt)?; Ok(params) } /// Parse function parameters fn parse_params(&mut self) -> Result, ParseError> { let mut params = Vec::new(); while !self.check(TokenKind::RParen) { let start = self.current_span(); let name = self.parse_ident()?; self.expect(TokenKind::Colon)?; let typ = self.parse_type()?; let span = start.merge(self.previous_span()); params.push(Parameter { name, typ, span }); if !self.check(TokenKind::RParen) { self.expect(TokenKind::Comma)?; } } Ok(params) } /// Parse effect list { Effect1, Effect2 } fn parse_effect_list(&mut self) -> Result, ParseError> { self.expect(TokenKind::LBrace)?; let mut effects = Vec::new(); while !self.check(TokenKind::RBrace) { effects.push(self.parse_ident()?); if !self.check(TokenKind::RBrace) { self.expect(TokenKind::Comma)?; } } self.expect(TokenKind::RBrace)?; Ok(effects) } /// Parse behavioral properties: is pure, is total, is idempotent, etc. fn parse_behavioral_properties(&mut self) -> Result, ParseError> { let mut properties = Vec::new(); while self.check(TokenKind::Is) || self.check(TokenKind::Assume) { let is_assumed = self.check(TokenKind::Assume); self.advance(); // consume 'is' or 'assume' if is_assumed { // 'assume' must be followed by 'is' if !self.check(TokenKind::Is) { return Err(ParseError { message: "Expected 'is' after 'assume'".to_string(), span: self.current_span(), }); } self.advance(); // consume 'is' } let property = self.parse_single_property()?; properties.push(property); // Optional comma for multiple properties: is pure, is total if self.check(TokenKind::Comma) { self.advance(); } } Ok(properties) } /// Parse a single behavioral property keyword fn parse_single_property(&mut self) -> Result { let span = self.current_span(); match self.peek_kind() { TokenKind::Pure => { self.advance(); Ok(BehavioralProperty::Pure) } TokenKind::Total => { self.advance(); Ok(BehavioralProperty::Total) } TokenKind::Idempotent => { self.advance(); Ok(BehavioralProperty::Idempotent) } TokenKind::Deterministic => { self.advance(); Ok(BehavioralProperty::Deterministic) } TokenKind::Commutative => { self.advance(); Ok(BehavioralProperty::Commutative) } _ => Err(ParseError { message: "Expected behavioral property: pure, total, idempotent, deterministic, or commutative".to_string(), span, }), } } /// Parse where clauses: where F is pure, where result > 0 fn parse_where_clauses(&mut self) -> Result, ParseError> { let mut clauses = Vec::new(); while self.check(TokenKind::Where) { self.advance(); // consume 'where' let span = self.current_span(); // Check if it's a property constraint: where F is pure // or a result refinement: where result > 0 if self.check_ident() { let ident = self.parse_ident()?; if self.check(TokenKind::Is) { self.advance(); // consume 'is' let property = self.parse_single_property()?; clauses.push(WhereClause::PropertyConstraint { type_param: ident, property, span, }); } else { // This is a result refinement starting with an identifier // For now, we'll parse it as a simple expression // Put the identifier back by creating an expression let predicate = self.parse_refinement_with_ident(ident)?; clauses.push(WhereClause::ResultRefinement { predicate: Box::new(predicate), span, }); } } else { return Err(ParseError { message: "Expected identifier after 'where'".to_string(), span, }); } // Optional comma for multiple where clauses if self.check(TokenKind::Comma) { self.advance(); } } Ok(clauses) } /// Parse a refinement expression that starts with an already-parsed identifier fn parse_refinement_with_ident(&mut self, ident: Ident) -> Result { // Start with the identifier as a variable let mut left = Expr::Var(ident); // Parse the rest as a comparison expression if let Some(op) = self.try_parse_comparison_op() { let right = self.parse_primary_expr()?; let span = left.span().merge(right.span()); left = Expr::BinaryOp { op, left: Box::new(left), right: Box::new(right), span, }; } Ok(left) } /// Try to parse a comparison operator fn try_parse_comparison_op(&mut self) -> Option { match self.peek_kind() { TokenKind::Lt => { self.advance(); Some(BinaryOp::Lt) } TokenKind::Le => { self.advance(); Some(BinaryOp::Le) } TokenKind::Gt => { self.advance(); Some(BinaryOp::Gt) } TokenKind::Ge => { self.advance(); Some(BinaryOp::Ge) } TokenKind::EqEq => { self.advance(); Some(BinaryOp::Eq) } TokenKind::Ne => { self.advance(); Some(BinaryOp::Ne) } _ => None, } } /// Check if the current token is an identifier fn check_ident(&self) -> bool { matches!(self.peek_kind(), TokenKind::Ident(_)) } /// Parse a type expression fn parse_type(&mut self) -> Result { // Function type: fn(A, B): C with {E} if self.check(TokenKind::Fn) { return self.parse_function_type(); } // Tuple or parenthesized type if self.check(TokenKind::LParen) { return self.parse_tuple_or_paren_type(); } // Record type if self.check(TokenKind::LBrace) { return self.parse_record_type(); } // Named type (possibly with type arguments) let name = self.parse_ident()?; // Check for type arguments let base_type = if self.check(TokenKind::Lt) { self.advance(); let mut args = Vec::new(); while !self.check(TokenKind::Gt) { args.push(self.parse_type()?); if !self.check(TokenKind::Gt) { self.expect(TokenKind::Comma)?; } } self.expect(TokenKind::Gt)?; TypeExpr::App(Box::new(TypeExpr::Named(name)), args) } else { TypeExpr::Named(name) }; // Check for version constraint: Type @v1, Type @v2+, Type @latest if self.check(TokenKind::At) { let constraint = self.parse_version_constraint()?; Ok(TypeExpr::Versioned { base: Box::new(base_type), constraint, }) } else { Ok(base_type) } } fn parse_function_type(&mut self) -> Result { self.expect(TokenKind::Fn)?; self.expect(TokenKind::LParen)?; let mut params = Vec::new(); while !self.check(TokenKind::RParen) { params.push(self.parse_type()?); if !self.check(TokenKind::RParen) { self.expect(TokenKind::Comma)?; } } self.expect(TokenKind::RParen)?; self.expect(TokenKind::Colon)?; let return_type = Box::new(self.parse_type()?); let effects = if self.check(TokenKind::With) { self.advance(); self.parse_effect_list()? } else { Vec::new() }; Ok(TypeExpr::Function { params, return_type, effects, }) } fn parse_tuple_or_paren_type(&mut self) -> Result { self.expect(TokenKind::LParen)?; if self.check(TokenKind::RParen) { self.advance(); return Ok(TypeExpr::Unit); } let first = self.parse_type()?; if self.check(TokenKind::Comma) { // Tuple type let mut elements = vec![first]; while self.check(TokenKind::Comma) { self.advance(); if self.check(TokenKind::RParen) { break; } elements.push(self.parse_type()?); } self.expect(TokenKind::RParen)?; Ok(TypeExpr::Tuple(elements)) } else { // Parenthesized type self.expect(TokenKind::RParen)?; Ok(first) } } fn parse_record_type(&mut self) -> Result { self.expect(TokenKind::LBrace)?; self.skip_newlines(); let fields = self.parse_record_fields()?; self.expect(TokenKind::RBrace)?; Ok(TypeExpr::Record(fields)) } fn parse_record_fields(&mut self) -> Result, ParseError> { let mut fields = Vec::new(); while !self.check(TokenKind::RBrace) && !self.check(TokenKind::From) { let start = self.current_span(); let name = self.parse_ident()?; self.expect(TokenKind::Colon)?; let typ = self.parse_type()?; let span = start.merge(self.previous_span()); fields.push(RecordField { name, typ, span }); self.skip_newlines(); if self.check(TokenKind::Comma) { self.advance(); } self.skip_newlines(); } Ok(fields) } /// Parse a version annotation: @v1, @v2, etc. fn parse_version(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::At)?; // Expect an identifier like "v1", "v2" let ident = self.parse_ident()?; // Parse the version number from the identifier (e.g., "v1" -> 1) if !ident.name.starts_with('v') { return Err(ParseError { message: format!("Expected version like @v1, @v2, got @{}", ident.name), span: ident.span, }); } let version_str = &ident.name[1..]; let number = version_str.parse::().map_err(|_| ParseError { message: format!("Invalid version number: {}", version_str), span: ident.span, })?; let span = start.merge(ident.span); Ok(Version::new(number, span)) } /// Parse a version constraint: @v1, @v1+, @latest fn parse_version_constraint(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::At)?; // Check for @latest if self.check(TokenKind::Latest) { self.advance(); let span = start.merge(self.previous_span()); return Ok(VersionConstraint::Latest(span)); } // Parse version identifier (v1, v2, etc.) let ident = self.parse_ident()?; if !ident.name.starts_with('v') { return Err(ParseError { message: format!( "Expected version like @v1, @v2, or @latest, got @{}", ident.name ), span: ident.span, }); } let version_str = &ident.name[1..]; let number = version_str.parse::().map_err(|_| ParseError { message: format!("Invalid version number: {}", version_str), span: ident.span, })?; let span = start.merge(ident.span); let version = Version::new(number, span); // Check for + (at least this version) if self.check(TokenKind::Plus) { self.advance(); Ok(VersionConstraint::AtLeast(version)) } else { Ok(VersionConstraint::Exact(version)) } } /// Parse migrations: from @v1 = { ... }, from @v2 = { ... } fn parse_migrations(&mut self) -> Result, ParseError> { let mut migrations = Vec::new(); while self.check(TokenKind::From) { let start = self.current_span(); self.advance(); // consume 'from' let from_version = self.parse_version()?; self.expect(TokenKind::Eq)?; self.skip_newlines(); // Parse the migration body (an expression, typically a record literal) let body = self.parse_expr()?; let span = start.merge(body.span()); migrations.push(Migration { from_version, body, span, }); self.skip_newlines(); // Optional comma between migrations if self.check(TokenKind::Comma) { self.advance(); } self.skip_newlines(); } Ok(migrations) } /// Check if we're looking at a single-line enum (no leading pipe) /// e.g., type Status = Ok | Error fn is_single_line_enum(&self) -> bool { // Look for pattern: Ident (LParen|LBrace)? Pipe // We need to peek ahead without consuming tokens if !matches!(&self.peek().kind, TokenKind::Ident(_)) { return false; } // Check if there's a | somewhere on this logical line // This is a simple heuristic - look at the next few tokens let mut pos = self.pos; let mut found_ident = false; let mut depth = 0; while pos < self.tokens.len() { match &self.tokens[pos].kind { TokenKind::Ident(_) if !found_ident => found_ident = true, TokenKind::LParen | TokenKind::LBrace => depth += 1, TokenKind::RParen | TokenKind::RBrace => { if depth > 0 { depth -= 1; } } TokenKind::Pipe if depth == 0 => return true, TokenKind::Newline | TokenKind::Eof => return false, _ => {} } pos += 1; } false } /// Parse single-line variants without leading pipe fn parse_single_line_variants(&mut self) -> Result, ParseError> { let mut variants = Vec::new(); loop { let start = self.current_span(); let name = self.parse_ident()?; let fields = if self.check(TokenKind::LParen) { // Tuple variant self.advance(); let mut types = Vec::new(); while !self.check(TokenKind::RParen) { types.push(self.parse_type()?); if !self.check(TokenKind::RParen) { self.expect(TokenKind::Comma)?; } } self.expect(TokenKind::RParen)?; VariantFields::Tuple(types) } else if self.check(TokenKind::LBrace) { // Record variant self.advance(); self.skip_newlines(); let fields = self.parse_record_fields()?; self.expect(TokenKind::RBrace)?; VariantFields::Record(fields) } else { VariantFields::Unit }; let span = start.merge(self.previous_span()); variants.push(Variant { name, fields, span }); // Check for more variants if self.check(TokenKind::Pipe) { self.advance(); self.skip_newlines(); } else { break; } } Ok(variants) } fn parse_variants(&mut self) -> Result, ParseError> { let mut variants = Vec::new(); // Skip leading pipe if self.check(TokenKind::Pipe) { self.advance(); } loop { let start = self.current_span(); let name = self.parse_ident()?; let fields = if self.check(TokenKind::LParen) { // Tuple variant self.advance(); let mut types = Vec::new(); while !self.check(TokenKind::RParen) { types.push(self.parse_type()?); if !self.check(TokenKind::RParen) { self.expect(TokenKind::Comma)?; } } self.expect(TokenKind::RParen)?; VariantFields::Tuple(types) } else if self.check(TokenKind::LBrace) { // Record variant self.advance(); self.skip_newlines(); let fields = self.parse_record_fields()?; self.expect(TokenKind::RBrace)?; VariantFields::Record(fields) } else { VariantFields::Unit }; let span = start.merge(self.previous_span()); variants.push(Variant { name, fields, span }); self.skip_newlines(); if self.check(TokenKind::Pipe) { self.advance(); self.skip_newlines(); } else { break; } } Ok(variants) } fn peek_is_variant(&self) -> bool { matches!(self.peek_kind(), TokenKind::Ident(_)) } /// Parse an expression fn parse_expr(&mut self) -> Result { self.parse_pipe_expr() } /// Parse pipe expressions: a |> b |> c fn parse_pipe_expr(&mut self) -> Result { let mut expr = self.parse_or_expr()?; while self.check(TokenKind::PipeGt) { let start = expr.span(); self.advance(); self.skip_newlines(); let right = self.parse_or_expr()?; let span = start.merge(right.span()); // Transform a |> f into f(a) expr = Expr::Call { func: Box::new(right), args: vec![expr], span, }; } Ok(expr) } /// Parse or expressions: a || b fn parse_or_expr(&mut self) -> Result { let mut expr = self.parse_and_expr()?; while self.check(TokenKind::Or) { let start = expr.span(); self.advance(); self.skip_newlines(); let right = self.parse_and_expr()?; let span = start.merge(right.span()); expr = Expr::BinaryOp { op: BinaryOp::Or, left: Box::new(expr), right: Box::new(right), span, }; } Ok(expr) } /// Parse and expressions: a && b fn parse_and_expr(&mut self) -> Result { let mut expr = self.parse_equality_expr()?; while self.check(TokenKind::And) { let start = expr.span(); self.advance(); self.skip_newlines(); let right = self.parse_equality_expr()?; let span = start.merge(right.span()); expr = Expr::BinaryOp { op: BinaryOp::And, left: Box::new(expr), right: Box::new(right), span, }; } Ok(expr) } /// Parse equality expressions: a == b, a != b fn parse_equality_expr(&mut self) -> Result { let mut expr = self.parse_comparison_expr()?; loop { let op = match self.peek_kind() { TokenKind::EqEq => BinaryOp::Eq, TokenKind::Ne => BinaryOp::Ne, _ => break, }; let start = expr.span(); self.advance(); self.skip_newlines(); let right = self.parse_comparison_expr()?; let span = start.merge(right.span()); expr = Expr::BinaryOp { op, left: Box::new(expr), right: Box::new(right), span, }; } Ok(expr) } /// Parse comparison expressions: a < b, a <= b, etc. fn parse_comparison_expr(&mut self) -> Result { let mut expr = self.parse_additive_expr()?; loop { let op = match self.peek_kind() { TokenKind::Lt => BinaryOp::Lt, TokenKind::Le => BinaryOp::Le, TokenKind::Gt => BinaryOp::Gt, TokenKind::Ge => BinaryOp::Ge, _ => break, }; let start = expr.span(); self.advance(); self.skip_newlines(); let right = self.parse_additive_expr()?; let span = start.merge(right.span()); expr = Expr::BinaryOp { op, left: Box::new(expr), right: Box::new(right), span, }; } Ok(expr) } /// Parse additive expressions: a + b, a - b fn parse_additive_expr(&mut self) -> Result { let mut expr = self.parse_multiplicative_expr()?; loop { let op = match self.peek_kind() { TokenKind::Plus => BinaryOp::Add, TokenKind::Minus => BinaryOp::Sub, _ => break, }; let start = expr.span(); self.advance(); self.skip_newlines(); let right = self.parse_multiplicative_expr()?; let span = start.merge(right.span()); expr = Expr::BinaryOp { op, left: Box::new(expr), right: Box::new(right), span, }; } Ok(expr) } /// Parse multiplicative expressions: a * b, a / b, a % b fn parse_multiplicative_expr(&mut self) -> Result { let mut expr = self.parse_unary_expr()?; loop { let op = match self.peek_kind() { TokenKind::Star => BinaryOp::Mul, TokenKind::Slash => BinaryOp::Div, TokenKind::Percent => BinaryOp::Mod, _ => break, }; let start = expr.span(); self.advance(); self.skip_newlines(); let right = self.parse_unary_expr()?; let span = start.merge(right.span()); expr = Expr::BinaryOp { op, left: Box::new(expr), right: Box::new(right), span, }; } Ok(expr) } /// Parse unary expressions: -a, !a fn parse_unary_expr(&mut self) -> Result { let op = match self.peek_kind() { TokenKind::Minus => UnaryOp::Neg, TokenKind::Not => UnaryOp::Not, _ => return self.parse_call_expr(), }; let start = self.current_span(); self.advance(); let operand = self.parse_unary_expr()?; let span = start.merge(operand.span()); Ok(Expr::UnaryOp { op, operand: Box::new(operand), span, }) } /// Parse call and field access expressions fn parse_call_expr(&mut self) -> Result { let mut expr = self.parse_primary_expr()?; loop { if self.check(TokenKind::LParen) { // Function call let start = expr.span(); self.advance(); let args = self.parse_args()?; self.expect(TokenKind::RParen)?; let span = start.merge(self.previous_span()); expr = Expr::Call { func: Box::new(expr), args, span, }; } else if self.check(TokenKind::Dot) { let start = expr.span(); self.advance(); let field = self.parse_ident()?; // Check if this is an effect operation: Effect.operation(args) if self.check(TokenKind::LParen) { if let Expr::Var(effect) = expr { self.advance(); let args = self.parse_args()?; self.expect(TokenKind::RParen)?; let span = start.merge(self.previous_span()); expr = Expr::EffectOp { effect, operation: field, args, span, }; continue; } } let span = start.merge(field.span); expr = Expr::Field { object: Box::new(expr), field, span, }; } else { break; } } Ok(expr) } fn parse_args(&mut self) -> Result, ParseError> { let mut args = Vec::new(); while !self.check(TokenKind::RParen) { args.push(self.parse_expr()?); if !self.check(TokenKind::RParen) { self.expect(TokenKind::Comma)?; } } Ok(args) } /// Parse primary expressions fn parse_primary_expr(&mut self) -> Result { let token = self.peek().clone(); match &token.kind { // Literals TokenKind::Int(n) => { let n = *n; self.advance(); Ok(Expr::Literal(Literal { kind: LiteralKind::Int(n), span: token.span, })) } TokenKind::Float(f) => { let f = *f; self.advance(); Ok(Expr::Literal(Literal { kind: LiteralKind::Float(f), span: token.span, })) } TokenKind::String(s) => { let s = s.clone(); self.advance(); Ok(Expr::Literal(Literal { kind: LiteralKind::String(s), span: token.span, })) } TokenKind::InterpolatedString(parts) => { let parts = parts.clone(); let span = token.span; self.advance(); self.desugar_interpolated_string(&parts, span) } TokenKind::Char(c) => { let c = *c; self.advance(); Ok(Expr::Literal(Literal { kind: LiteralKind::Char(c), span: token.span, })) } TokenKind::Bool(b) => { let b = *b; self.advance(); Ok(Expr::Literal(Literal { kind: LiteralKind::Bool(b), span: token.span, })) } // Identifiers TokenKind::Ident(_) => { let ident = self.parse_ident()?; Ok(Expr::Var(ident)) } // Keywords that start expressions TokenKind::If => self.parse_if_expr(), TokenKind::Match => self.parse_match_expr(), TokenKind::Let => self.parse_let_expr(), TokenKind::Fn => self.parse_lambda_expr(), TokenKind::Run => self.parse_run_expr(), TokenKind::Resume => self.parse_resume_expr(), // Delimiters TokenKind::LParen => self.parse_tuple_or_paren_expr(), TokenKind::LBrace => self.parse_block_or_record_expr(), TokenKind::LBracket => self.parse_list_expr(), _ => Err(self.error(&format!("Unexpected token: {}", token.kind))), } } fn parse_if_expr(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::If)?; let condition = Box::new(self.parse_expr()?); self.expect(TokenKind::Then)?; self.skip_newlines(); let then_branch = Box::new(self.parse_expr()?); self.skip_newlines(); // Else is optional - if missing, synthesize a Unit value let else_branch = if self.check(TokenKind::Else) { self.expect(TokenKind::Else)?; self.skip_newlines(); Box::new(self.parse_expr()?) } else { // No else clause - use Unit as the else branch Box::new(Expr::Literal(Literal { kind: LiteralKind::Unit, span: then_branch.span(), })) }; let span = start.merge(else_branch.span()); Ok(Expr::If { condition, then_branch, else_branch, span, }) } fn parse_match_expr(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::Match)?; let scrutinee = Box::new(self.parse_expr()?); self.expect(TokenKind::LBrace)?; self.skip_newlines(); let mut arms = Vec::new(); while !self.check(TokenKind::RBrace) { arms.push(self.parse_match_arm()?); self.skip_newlines(); if self.check(TokenKind::Comma) { self.advance(); } self.skip_newlines(); } let end = self.current_span(); self.expect(TokenKind::RBrace)?; Ok(Expr::Match { scrutinee, arms, span: start.merge(end), }) } fn parse_match_arm(&mut self) -> Result { let start = self.current_span(); let pattern = self.parse_pattern()?; let guard = if self.check(TokenKind::If) { self.advance(); Some(self.parse_expr()?) } else { None }; self.expect(TokenKind::Arrow)?; self.skip_newlines(); let body = self.parse_expr()?; let span = start.merge(body.span()); Ok(MatchArm { pattern, guard, body, span, }) } fn parse_pattern(&mut self) -> Result { let token = self.peek().clone(); match &token.kind { TokenKind::Underscore => { self.advance(); Ok(Pattern::Wildcard(token.span)) } TokenKind::Int(n) => { let n = *n; self.advance(); Ok(Pattern::Literal(Literal { kind: LiteralKind::Int(n), span: token.span, })) } TokenKind::String(s) => { let s = s.clone(); self.advance(); Ok(Pattern::Literal(Literal { kind: LiteralKind::String(s), span: token.span, })) } TokenKind::Bool(b) => { let b = *b; self.advance(); Ok(Pattern::Literal(Literal { kind: LiteralKind::Bool(b), span: token.span, })) } TokenKind::Ident(name) => { // Check if it starts with uppercase (constructor) or lowercase (variable) if name.chars().next().map_or(false, |c| c.is_uppercase()) { self.parse_constructor_pattern() } else { let ident = self.parse_ident()?; Ok(Pattern::Var(ident)) } } TokenKind::LParen => self.parse_tuple_pattern(), TokenKind::LBrace => self.parse_record_pattern(), _ => Err(self.error("Expected pattern")), } } fn parse_constructor_pattern(&mut self) -> Result { let start = self.current_span(); let name = self.parse_ident()?; if self.check(TokenKind::LParen) { self.advance(); let mut fields = Vec::new(); while !self.check(TokenKind::RParen) { fields.push(self.parse_pattern()?); if !self.check(TokenKind::RParen) { self.expect(TokenKind::Comma)?; } } self.expect(TokenKind::RParen)?; let span = start.merge(self.previous_span()); Ok(Pattern::Constructor { name, fields, span }) } else { let span = name.span; Ok(Pattern::Constructor { name, fields: Vec::new(), span, }) } } fn parse_tuple_pattern(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::LParen)?; let mut elements = Vec::new(); while !self.check(TokenKind::RParen) { elements.push(self.parse_pattern()?); if !self.check(TokenKind::RParen) { self.expect(TokenKind::Comma)?; } } self.expect(TokenKind::RParen)?; let span = start.merge(self.previous_span()); Ok(Pattern::Tuple { elements, span }) } fn parse_record_pattern(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::LBrace)?; self.skip_newlines(); let mut fields = Vec::new(); while !self.check(TokenKind::RBrace) { let name = self.parse_ident()?; let pattern = if self.check(TokenKind::Colon) { self.advance(); self.parse_pattern()? } else { Pattern::Var(name.clone()) }; fields.push((name, pattern)); self.skip_newlines(); if self.check(TokenKind::Comma) { self.advance(); } self.skip_newlines(); } self.expect(TokenKind::RBrace)?; let span = start.merge(self.previous_span()); Ok(Pattern::Record { fields, span }) } fn parse_let_expr(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::Let)?; // Allow underscore as wildcard pattern (discards the value) let name = if self.check(TokenKind::Underscore) { let span = self.current_span(); self.advance(); Ident::new("_".to_string(), span) } else { self.parse_ident()? }; let typ = if self.check(TokenKind::Colon) { self.advance(); Some(self.parse_type()?) } else { None }; self.expect(TokenKind::Eq)?; self.skip_newlines(); let value = Box::new(self.parse_expr()?); // Check for semicolon (let-in style) self.skip_newlines(); if self.check(TokenKind::Semi) { self.advance(); self.skip_newlines(); let body = Box::new(self.parse_expr()?); let span = start.merge(body.span()); Ok(Expr::Let { name, typ, value, body, span, }) } else { // Let as expression (returns unit) let span = start.merge(value.span()); let body = Box::new(Expr::Literal(Literal { kind: LiteralKind::Unit, span: Span::default(), })); Ok(Expr::Let { name, typ, value, body, span, }) } } fn parse_lambda_expr(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::Fn)?; self.expect(TokenKind::LParen)?; let params = self.parse_lambda_params()?; self.expect(TokenKind::RParen)?; let return_type = if self.check(TokenKind::Colon) { self.advance(); Some(Box::new(self.parse_type()?)) } else { None }; let effects = if self.check(TokenKind::With) { self.advance(); self.parse_effect_list()? } else { Vec::new() }; self.expect(TokenKind::Arrow)?; self.skip_newlines(); let body = Box::new(self.parse_expr()?); let span = start.merge(body.span()); Ok(Expr::Lambda { params, return_type, effects, body, span, }) } fn parse_lambda_params(&mut self) -> Result, ParseError> { let mut params = Vec::new(); while !self.check(TokenKind::RParen) { let start = self.current_span(); let name = self.parse_ident()?; let typ = if self.check(TokenKind::Colon) { self.advance(); self.parse_type()? } else { // Infer type later TypeExpr::Named(Ident::new("_", Span::default())) }; let span = start.merge(self.previous_span()); params.push(Parameter { name, typ, span }); if !self.check(TokenKind::RParen) { self.expect(TokenKind::Comma)?; } } Ok(params) } fn parse_run_expr(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::Run)?; let expr = Box::new(self.parse_call_expr()?); self.expect(TokenKind::With)?; self.expect(TokenKind::LBrace)?; self.skip_newlines(); let mut handlers = Vec::new(); while !self.check(TokenKind::RBrace) { let effect = self.parse_ident()?; self.expect(TokenKind::Eq)?; let handler = self.parse_expr()?; handlers.push((effect, handler)); self.skip_newlines(); if self.check(TokenKind::Comma) { self.advance(); } self.skip_newlines(); } let end = self.current_span(); self.expect(TokenKind::RBrace)?; Ok(Expr::Run { expr, handlers, span: start.merge(end), }) } fn parse_resume_expr(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::Resume)?; self.expect(TokenKind::LParen)?; let value = Box::new(self.parse_expr()?); self.expect(TokenKind::RParen)?; let span = start.merge(self.previous_span()); Ok(Expr::Resume { value, span }) } fn parse_tuple_or_paren_expr(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::LParen)?; if self.check(TokenKind::RParen) { self.advance(); return Ok(Expr::Literal(Literal { kind: LiteralKind::Unit, span: start.merge(self.previous_span()), })); } let first = self.parse_expr()?; if self.check(TokenKind::Comma) { // Tuple let mut elements = vec![first]; while self.check(TokenKind::Comma) { self.advance(); if self.check(TokenKind::RParen) { break; } elements.push(self.parse_expr()?); } self.expect(TokenKind::RParen)?; let span = start.merge(self.previous_span()); Ok(Expr::Tuple { elements, span }) } else { // Parenthesized expression self.expect(TokenKind::RParen)?; Ok(first) } } fn parse_block_or_record_expr(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::LBrace)?; self.skip_newlines(); // Empty block if self.check(TokenKind::RBrace) { self.advance(); return Ok(Expr::Literal(Literal { kind: LiteralKind::Unit, span: start.merge(self.previous_span()), })); } // Check if it's a record (ident: expr) or block if matches!(self.peek_kind(), TokenKind::Ident(_)) { let lookahead = self.tokens.get(self.pos + 1).map(|t| &t.kind); if matches!(lookahead, Some(TokenKind::Colon)) { return self.parse_record_expr_rest(start); } } // It's a block self.parse_block_rest(start) } fn parse_record_expr_rest(&mut self, start: Span) -> Result { let mut fields = Vec::new(); while !self.check(TokenKind::RBrace) { let name = self.parse_ident()?; self.expect(TokenKind::Colon)?; let value = self.parse_expr()?; fields.push((name, value)); self.skip_newlines(); if self.check(TokenKind::Comma) { self.advance(); } self.skip_newlines(); } self.expect(TokenKind::RBrace)?; let span = start.merge(self.previous_span()); Ok(Expr::Record { fields, span }) } fn parse_block_rest(&mut self, start: Span) -> Result { let mut statements = Vec::new(); loop { self.skip_newlines(); if self.check(TokenKind::RBrace) { break; } if self.check(TokenKind::Let) { // Let statement let let_start = self.current_span(); self.advance(); // Allow underscore as wildcard pattern (discards the value) let name = if self.check(TokenKind::Underscore) { let span = self.current_span(); self.advance(); Ident::new("_".to_string(), span) } else { self.parse_ident()? }; let typ = if self.check(TokenKind::Colon) { self.advance(); Some(self.parse_type()?) } else { None }; self.expect(TokenKind::Eq)?; self.skip_newlines(); let value = self.parse_expr()?; let span = let_start.merge(value.span()); statements.push(Statement::Let { name, typ, value, span, }); } else { // Expression statement let expr = self.parse_expr()?; statements.push(Statement::Expr(expr)); } self.skip_newlines(); // Optional semicolon if self.check(TokenKind::Semi) { self.advance(); } self.skip_newlines(); } // The last statement is the result let result = if let Some(Statement::Expr(expr)) = statements.pop() { Box::new(expr) } else { Box::new(Expr::Literal(Literal { kind: LiteralKind::Unit, span: Span::default(), })) }; self.expect(TokenKind::RBrace)?; let span = start.merge(self.previous_span()); Ok(Expr::Block { statements, result, span, }) } fn parse_list_expr(&mut self) -> Result { let start = self.current_span(); self.expect(TokenKind::LBracket)?; self.skip_newlines(); let mut elements = Vec::new(); while !self.check(TokenKind::RBracket) { elements.push(self.parse_expr()?); self.skip_newlines(); if !self.check(TokenKind::RBracket) { self.expect(TokenKind::Comma)?; self.skip_newlines(); } } self.expect(TokenKind::RBracket)?; let span = start.merge(self.previous_span()); Ok(Expr::List { elements, span }) } /// Desugar an interpolated string into concatenation with toString calls /// "Hello, {name}!" becomes "Hello, " + toString(name) + "!" fn desugar_interpolated_string( &mut self, parts: &[StringPart], span: Span, ) -> Result { let mut exprs: Vec = Vec::new(); for part in parts { match part { StringPart::Literal(s) => { exprs.push(Expr::Literal(Literal { kind: LiteralKind::String(s.clone()), span, })); } StringPart::Expr(expr_text) => { // Parse the expression text let lexer = Lexer::new(expr_text); let tokens = lexer.tokenize().map_err(|e| ParseError { message: format!("Lexer error in interpolation: {}", e.message), span, })?; let mut parser = Parser::new(tokens); let inner_expr = parser.parse_expr().map_err(|e| ParseError { message: format!("Parse error in interpolation: {}", e.message), span, })?; // Wrap the expression in toString() call let to_string_call = Expr::Call { func: Box::new(Expr::Var(Ident::new("toString".to_string(), span))), args: vec![inner_expr], span, }; exprs.push(to_string_call); } } } // Chain all expressions with + operator if exprs.is_empty() { return Ok(Expr::Literal(Literal { kind: LiteralKind::String(String::new()), span, })); } let mut result = exprs.remove(0); for expr in exprs { result = Expr::BinaryOp { op: BinaryOp::Add, left: Box::new(result), right: Box::new(expr), span, }; } Ok(result) } // Helper methods fn parse_ident(&mut self) -> Result { let token = self.peek().clone(); match &token.kind { TokenKind::Ident(name) => { let name = name.clone(); self.advance(); Ok(Ident::new(name, token.span)) } _ => Err(self.error("Expected identifier")), } } fn peek(&self) -> &Token { self.tokens.get(self.pos).unwrap_or(&self.eof_token) } fn peek_kind(&self) -> TokenKind { self.peek().kind.clone() } fn peek_next(&self) -> &Token { self.tokens.get(self.pos + 1).unwrap_or(&self.eof_token) } fn peek_next_kind(&self) -> TokenKind { self.peek_next().kind.clone() } fn advance(&mut self) -> &Token { if !self.is_at_end() { self.pos += 1; } self.tokens.get(self.pos - 1).unwrap() } fn check(&self, kind: TokenKind) -> bool { std::mem::discriminant(&self.peek_kind()) == std::mem::discriminant(&kind) } fn expect(&mut self, kind: TokenKind) -> Result<&Token, ParseError> { if self.check(kind.clone()) { Ok(self.advance()) } else { Err(self.error(&format!("Expected {}, found {}", kind, self.peek_kind()))) } } fn is_at_end(&self) -> bool { matches!(self.peek_kind(), TokenKind::Eof) } fn skip_newlines(&mut self) { while self.check(TokenKind::Newline) { self.advance(); } } fn current_span(&self) -> Span { self.peek().span } fn previous_span(&self) -> Span { self.tokens .get(self.pos.saturating_sub(1)) .map(|t| t.span) .unwrap_or_default() } fn error(&self, message: &str) -> ParseError { ParseError { message: message.to_string(), span: self.current_span(), } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_parse_function() { let source = "fn add(a: Int, b: Int): Int = a + b"; let program = Parser::parse_source(source).unwrap(); assert_eq!(program.declarations.len(), 1); } #[test] fn test_parse_effect() { let source = r#" effect Console { fn print(msg: String): Unit fn read(): String } "#; let program = Parser::parse_source(source).unwrap(); assert_eq!(program.declarations.len(), 1); } #[test] fn test_parse_if_expr() { let source = "fn max(a: Int, b: Int): Int = if a > b then a else b"; let program = Parser::parse_source(source).unwrap(); assert_eq!(program.declarations.len(), 1); } #[test] fn test_parse_lambda() { let source = "let f = fn(x: Int): Int => x + 1"; let program = Parser::parse_source(source).unwrap(); assert_eq!(program.declarations.len(), 1); } #[test] fn test_parse_import() { let source = r#" import std/list fn foo(): Int = 42 "#; let program = Parser::parse_source(source).unwrap(); assert_eq!(program.imports.len(), 1); assert_eq!(program.imports[0].path.segments.len(), 2); assert_eq!(program.imports[0].path.segments[0].name, "std"); assert_eq!(program.imports[0].path.segments[1].name, "list"); assert_eq!(program.declarations.len(), 1); } #[test] fn test_parse_import_alias() { let source = "import std/list as L"; let program = Parser::parse_source(source).unwrap(); assert_eq!(program.imports.len(), 1); assert!(program.imports[0].alias.is_some()); assert_eq!(program.imports[0].alias.as_ref().unwrap().name, "L"); } #[test] fn test_parse_import_selective() { let source = "import std/list.{map, filter, fold}"; let program = Parser::parse_source(source).unwrap(); assert_eq!(program.imports.len(), 1); assert!(program.imports[0].items.is_some()); let items = program.imports[0].items.as_ref().unwrap(); assert_eq!(items.len(), 3); assert_eq!(items[0].name, "map"); assert_eq!(items[1].name, "filter"); assert_eq!(items[2].name, "fold"); } #[test] fn test_parse_pub_function() { let source = "pub fn add(a: Int, b: Int): Int = a + b"; let program = Parser::parse_source(source).unwrap(); assert_eq!(program.declarations.len(), 1); if let Declaration::Function(f) = &program.declarations[0] { assert_eq!(f.visibility, Visibility::Public); } else { panic!("Expected function declaration"); } } #[test] fn test_parse_pub_let() { let source = "pub let x = 42"; let program = Parser::parse_source(source).unwrap(); assert_eq!(program.declarations.len(), 1); if let Declaration::Let(l) = &program.declarations[0] { assert_eq!(l.visibility, Visibility::Public); } else { panic!("Expected let declaration"); } } #[test] fn test_parse_private_by_default() { let source = "fn foo(): Int = 42"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Function(f) = &program.declarations[0] { assert_eq!(f.visibility, Visibility::Private); } else { panic!("Expected function declaration"); } } // Schema Evolution tests #[test] fn test_parse_versioned_type() { let source = "type User @v1 { name: String, email: String }"; let program = Parser::parse_source(source).unwrap(); assert_eq!(program.declarations.len(), 1); if let Declaration::Type(t) = &program.declarations[0] { assert_eq!(t.name.name, "User"); assert!(t.version.is_some()); assert_eq!(t.version.unwrap().number, 1); } else { panic!("Expected type declaration"); } } #[test] fn test_parse_versioned_type_v2() { let source = "type User @v2 { name: String, email: String, age: Int }"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Type(t) = &program.declarations[0] { assert!(t.version.is_some()); assert_eq!(t.version.unwrap().number, 2); } else { panic!("Expected type declaration"); } } #[test] fn test_parse_versioned_type_expr() { let source = "let user: User @v2 = x"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Let(l) = &program.declarations[0] { if let Some(TypeExpr::Versioned { base, constraint }) = &l.typ { if let TypeExpr::Named(name) = base.as_ref() { assert_eq!(name.name, "User"); } else { panic!("Expected Named type"); } if let VersionConstraint::Exact(v) = constraint { assert_eq!(v.number, 2); } else { panic!("Expected Exact version constraint"); } } else { panic!("Expected Versioned type expression"); } } else { panic!("Expected let declaration"); } } #[test] fn test_parse_version_at_least() { let source = "let user: User @v2+ = x"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Let(l) = &program.declarations[0] { if let Some(TypeExpr::Versioned { constraint, .. }) = &l.typ { if let VersionConstraint::AtLeast(v) = constraint { assert_eq!(v.number, 2); } else { panic!("Expected AtLeast version constraint"); } } else { panic!("Expected Versioned type expression"); } } else { panic!("Expected let declaration"); } } #[test] fn test_parse_version_latest() { let source = "let user: User @latest = x"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Let(l) = &program.declarations[0] { if let Some(TypeExpr::Versioned { constraint, .. }) = &l.typ { assert!(matches!(constraint, VersionConstraint::Latest(_))); } else { panic!("Expected Versioned type expression"); } } else { panic!("Expected let declaration"); } } #[test] fn test_parse_type_with_migration() { let source = r#" type User @v2 { name: String, email: String, age: Int, from @v1 = { name: old.name, email: old.email, age: 0 } } "#; let program = Parser::parse_source(source).unwrap(); if let Declaration::Type(t) = &program.declarations[0] { assert_eq!(t.name.name, "User"); assert_eq!(t.version.unwrap().number, 2); assert_eq!(t.migrations.len(), 1); assert_eq!(t.migrations[0].from_version.number, 1); } else { panic!("Expected type declaration"); } } // ============ Behavioral Properties Tests ============ #[test] fn test_parse_function_is_pure() { let source = "fn add(a: Int, b: Int): Int is pure = a + b"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Function(f) = &program.declarations[0] { assert_eq!(f.name.name, "add"); assert_eq!(f.properties.len(), 1); assert_eq!(f.properties[0], BehavioralProperty::Pure); } else { panic!("Expected function declaration"); } } #[test] fn test_parse_function_multiple_properties() { let source = "fn double(x: Int): Int is pure, is total = x * 2"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Function(f) = &program.declarations[0] { assert_eq!(f.name.name, "double"); assert_eq!(f.properties.len(), 2); assert!(f.properties.contains(&BehavioralProperty::Pure)); assert!(f.properties.contains(&BehavioralProperty::Total)); } else { panic!("Expected function declaration"); } } #[test] fn test_parse_function_with_effects_and_properties() { let source = "fn log(msg: String): Unit with {Logger} is deterministic = Logger.log(msg)"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Function(f) = &program.declarations[0] { assert_eq!(f.name.name, "log"); assert_eq!(f.effects.len(), 1); assert_eq!(f.effects[0].name, "Logger"); assert_eq!(f.properties.len(), 1); assert_eq!(f.properties[0], BehavioralProperty::Deterministic); } else { panic!("Expected function declaration"); } } #[test] fn test_parse_function_idempotent() { let source = "fn normalize(s: String): String is idempotent = s"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Function(f) = &program.declarations[0] { assert_eq!(f.properties.len(), 1); assert_eq!(f.properties[0], BehavioralProperty::Idempotent); } else { panic!("Expected function declaration"); } } #[test] fn test_parse_function_commutative() { let source = "fn add(a: Int, b: Int): Int is commutative = a + b"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Function(f) = &program.declarations[0] { assert_eq!(f.properties.len(), 1); assert_eq!(f.properties[0], BehavioralProperty::Commutative); } else { panic!("Expected function declaration"); } } #[test] fn test_parse_where_property_constraint() { let source = "fn retry(action: F): Int where F is idempotent = 0"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Function(f) = &program.declarations[0] { assert_eq!(f.name.name, "retry"); assert_eq!(f.where_clauses.len(), 1); if let WhereClause::PropertyConstraint { type_param, property, .. } = &f.where_clauses[0] { assert_eq!(type_param.name, "F"); assert_eq!(*property, BehavioralProperty::Idempotent); } else { panic!("Expected PropertyConstraint"); } } else { panic!("Expected function declaration"); } } #[test] fn test_parse_where_result_refinement() { let source = "fn abs(x: Int): Int where result >= 0 = if x < 0 then 0 - x else x"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Function(f) = &program.declarations[0] { assert_eq!(f.name.name, "abs"); assert_eq!(f.where_clauses.len(), 1); if let WhereClause::ResultRefinement { predicate, .. } = &f.where_clauses[0] { // Check that the predicate is a binary comparison if let Expr::BinaryOp { op, .. } = predicate.as_ref() { assert_eq!(*op, BinaryOp::Ge); } else { panic!("Expected BinaryOp in refinement"); } } else { panic!("Expected ResultRefinement"); } } else { panic!("Expected function declaration"); } } #[test] fn test_parse_all_behavioral_features() { // Single-line version to avoid newline issues let source = "fn process(f: F, x: Int): Int with {Logger} is pure, is total where F is deterministic = f(x)"; let program = Parser::parse_source(source).unwrap(); if let Declaration::Function(func) = &program.declarations[0] { assert_eq!(func.name.name, "process"); assert_eq!(func.effects.len(), 1); assert_eq!(func.properties.len(), 2); assert!(func.properties.contains(&BehavioralProperty::Pure)); assert!(func.properties.contains(&BehavioralProperty::Total)); assert_eq!(func.where_clauses.len(), 1); } else { panic!("Expected function declaration"); } } }