From 39587e85d417233647f5a6135ad30dfbb0a33f3a Mon Sep 17 00:00:00 2001 From: ale Date: Fri, 22 Aug 2025 18:46:18 +0200 Subject: [PATCH] some implementations Signed-off-by: ale --- src/codegen.rs | 298 ++++++++++++++++++++++++++++++++++++++------ src/linker.rs | 32 +---- src/parser.rs | 326 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 585 insertions(+), 71 deletions(-) diff --git a/src/codegen.rs b/src/codegen.rs index c66f9b1..d1f046b 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,4 +1,4 @@ -use crate::parser::{Program, Function, Expression, Statement, Type}; +use crate::parser::{Program, Function, Expression, Statement, Type, BinaryOperator}; use crate::targets::Target; use crate::error::{AleccError, Result}; use std::collections::HashMap; @@ -8,6 +8,7 @@ pub struct CodeGenerator { output: String, label_counter: usize, string_literals: HashMap, + current_function_params: Vec<(String, i32)>, // (name, stack_offset) } impl CodeGenerator { @@ -17,6 +18,7 @@ impl CodeGenerator { output: String::new(), label_counter: 0, string_literals: HashMap::new(), + current_function_params: Vec::new(), } } @@ -49,9 +51,35 @@ impl CodeGenerator { self.generate_function(function)?; } + // Generate _start entry point + self.generate_start_function()?; + Ok(self.output.clone()) } + fn generate_start_function(&mut self) -> Result<()> { + self.emit_line(""); + self.emit_line(".globl _start"); + self.emit_line("_start:"); + + // Set up stack and call main + self.emit_line(" push rbp"); + self.emit_line(" mov rbp, rsp"); + + // Reserve space for temporary operations (prevents stack corruption) + self.emit_line(" sub rsp, 128"); + + // Call main function + self.emit_line(" call main"); + + // Exit syscall with main's return value + self.emit_line(" mov rdi, rax"); // exit status = main's return value + self.emit_line(" mov rax, 60"); // sys_exit syscall number + self.emit_line(" syscall"); // invoke syscall + + Ok(()) + } + fn emit_header(&mut self) { match self.target { Target::I386 => { @@ -59,7 +87,6 @@ impl CodeGenerator { self.emit_line(".intel_syntax noprefix"); } Target::Amd64 => { - self.emit_line(".arch x86_64"); self.emit_line(".intel_syntax noprefix"); } Target::Arm64 => { @@ -73,6 +100,9 @@ impl CodeGenerator { self.emit_line(&format!(".globl {}", function.name)); self.emit_line(&format!("{}:", function.name)); + // Set up parameter tracking + self.current_function_params.clear(); + // Function prologue self.emit_function_prologue(&function.parameters)?; @@ -92,28 +122,63 @@ impl CodeGenerator { self.emit_line(" push ebp"); self.emit_line(" mov ebp, esp"); - // Reserve space for local variables (simplified) - let stack_space = parameters.len() * 4; // Simplified calculation - if stack_space > 0 { - self.emit_line(&format!(" sub esp, {}", stack_space)); + // Reserve space for parameters + 128 bytes for temporaries + let stack_space = parameters.len() * 4 + 128; + self.emit_line(&format!(" sub esp, {}", stack_space)); + + // Store parameters from stack (i386 calling convention) + for (i, (name, _)) in parameters.iter().enumerate() { + let param_offset = -(i as i32 + 1) * 4; + let stack_offset = 8 + i as i32 * 4; // ebp + 8 + offset + self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", stack_offset)); + self.emit_line(&format!(" mov DWORD PTR [ebp + {}], eax", param_offset)); + self.current_function_params.push((name.clone(), param_offset)); } } Target::Amd64 => { self.emit_line(" push rbp"); self.emit_line(" mov rbp, rsp"); - let stack_space = parameters.len() * 8; - if stack_space > 0 { - self.emit_line(&format!(" sub rsp, {}", stack_space)); + // Reserve space for parameters + 128 bytes for temporaries + let stack_space = parameters.len() * 8 + 128; + self.emit_line(&format!(" sub rsp, {}", stack_space)); + + // Store parameters from registers (x86_64 calling convention) + let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; + for (i, (name, _)) in parameters.iter().enumerate() { + let param_offset = -(i as i32 + 1) * 8; + if i < param_registers.len() { + // Parameter passed in register + self.emit_line(&format!(" mov QWORD PTR [rbp + {}], {}", param_offset, param_registers[i])); + } else { + // Parameter passed on stack + let stack_offset = 16 + (i - param_registers.len()) as i32 * 8; + self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", stack_offset)); + self.emit_line(&format!(" mov QWORD PTR [rbp + {}], rax", param_offset)); + } + self.current_function_params.push((name.clone(), param_offset)); } } Target::Arm64 => { self.emit_line(" stp x29, x30, [sp, #-16]!"); self.emit_line(" mov x29, sp"); - let stack_space = (parameters.len() * 8 + 15) & !15; // 16-byte aligned - if stack_space > 0 { - self.emit_line(&format!(" sub sp, sp, #{}", stack_space)); + let stack_space = (parameters.len() * 8 + 128 + 15) & !15; // 16-byte aligned + self.emit_line(&format!(" sub sp, sp, #{}", stack_space)); + + // Store parameters from registers (ARM64 calling convention) + for (i, (name, _)) in parameters.iter().enumerate() { + let param_offset = -(i as i32 + 1) * 8; + if i < 8 { + // Parameter passed in register x0-x7 + self.emit_line(&format!(" str x{}, [x29, #{}]", i, param_offset)); + } else { + // Parameter passed on stack + let stack_offset = 16 + (i - 8) as i32 * 8; + self.emit_line(&format!(" ldr x9, [x29, #{}]", stack_offset)); + self.emit_line(&format!(" str x9, [x29, #{}]", param_offset)); + } + self.current_function_params.push((name.clone(), param_offset)); } } } @@ -240,26 +305,77 @@ impl CodeGenerator { } } Expression::Identifier(name) => { - // Load variable (simplified - assumes it's a parameter or global) - match self.target { - Target::I386 => { - self.emit_line(&format!(" mov eax, DWORD PTR [{}]", name)); + // Check if it's a function parameter first + if let Some((_, offset)) = self.current_function_params.iter().find(|(param_name, _)| param_name == name) { + // Load parameter from stack + match self.target { + Target::I386 => { + self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset)); + } + Target::Amd64 => { + self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset)); + } + Target::Arm64 => { + self.emit_line(&format!(" ldr x0, [x29, #{}]", offset)); + } } - Target::Amd64 => { - self.emit_line(&format!(" mov rax, QWORD PTR [{}]", name)); - } - Target::Arm64 => { - self.emit_line(&format!(" adrp x1, {}", name)); - self.emit_line(&format!(" add x1, x1, :lo12:{}", name)); - self.emit_line(" ldr x0, [x1]"); + } else { + // Load global variable + match self.target { + Target::I386 => { + self.emit_line(&format!(" mov eax, DWORD PTR [{}]", name)); + } + Target::Amd64 => { + self.emit_line(&format!(" mov rax, QWORD PTR [{}]", name)); + } + Target::Arm64 => { + self.emit_line(&format!(" adrp x1, {}", name)); + self.emit_line(&format!(" add x1, x1, :lo12:{}", name)); + self.emit_line(" ldr x0, [x1]"); + } } } } Expression::Call { function, arguments } => { - // Generate arguments in reverse order - for (i, arg) in arguments.iter().enumerate().rev() { - self.generate_expression(arg)?; - self.push_argument(i)?; + // Generate arguments and place in calling convention registers/stack + match self.target { + Target::I386 => { + // i386: push arguments in reverse order + for arg in arguments.iter().rev() { + self.generate_expression(arg)?; + self.emit_line(" push eax"); + } + } + Target::Amd64 => { + // x86_64: first 6 args in registers, rest on stack + let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; + + // Generate arguments and store in registers/stack + for (i, arg) in arguments.iter().enumerate() { + self.generate_expression(arg)?; + if i < param_registers.len() { + // Move to parameter register + self.emit_line(&format!(" mov {}, rax", param_registers[i])); + } else { + // Push to stack (reverse order for stack args) + self.emit_line(" push rax"); + } + } + } + Target::Arm64 => { + // ARM64: first 8 args in x0-x7, rest on stack + for (i, arg) in arguments.iter().enumerate() { + self.generate_expression(arg)?; + if i < 8 { + if i > 0 { + self.emit_line(&format!(" mov x{}, x0", i)); + } + // x0 already has the result for first argument + } else { + self.emit_line(" str x0, [sp, #-16]!"); + } + } + } } if let Expression::Identifier(func_name) = function.as_ref() { @@ -270,18 +386,128 @@ impl CodeGenerator { }); } - // Clean up stack - let stack_cleanup = arguments.len() * self.target.pointer_size(); - if stack_cleanup > 0 { - match self.target { - Target::I386 => { + // Clean up stack for arguments that were pushed + match self.target { + Target::I386 => { + let stack_cleanup = arguments.len() * 4; + if stack_cleanup > 0 { self.emit_line(&format!(" add esp, {}", stack_cleanup)); } - Target::Amd64 => { - // Arguments passed in registers, no cleanup needed + } + Target::Amd64 => { + // Clean up stack arguments (if any) + let stack_args = if arguments.len() > 6 { arguments.len() - 6 } else { 0 }; + if stack_args > 0 { + self.emit_line(&format!(" add rsp, {}", stack_args * 8)); } - Target::Arm64 => { - // Arguments passed in registers, no cleanup needed + } + Target::Arm64 => { + // Clean up stack arguments (if any) + let stack_args = if arguments.len() > 8 { arguments.len() - 8 } else { 0 }; + if stack_args > 0 { + self.emit_line(&format!(" add sp, sp, #{}", stack_args * 16)); + } + } + } + } + Expression::Binary { left, operator, right } => { + // Generate binary operations + // First generate right operand and save it + self.generate_expression(right)?; + match self.target { + Target::I386 => { + self.emit_line(" push eax"); // Save right operand + } + Target::Amd64 => { + self.emit_line(" push rax"); // Save right operand + } + Target::Arm64 => { + self.emit_line(" str x0, [sp, #-16]!"); // Save right operand + } + } + + // Generate left operand + self.generate_expression(left)?; + + // Pop right operand and perform operation + match self.target { + Target::I386 => { + self.emit_line(" pop ebx"); // Right operand in ebx + match operator { + BinaryOperator::Add => self.emit_line(" add eax, ebx"), + BinaryOperator::Subtract => self.emit_line(" sub eax, ebx"), + BinaryOperator::Multiply => self.emit_line(" imul eax, ebx"), + BinaryOperator::Divide => { + self.emit_line(" cdq"); // Sign extend eax to edx:eax + self.emit_line(" idiv ebx"); + } + _ => { + return Err(AleccError::CodegenError { + message: format!("Binary operator {:?} not implemented for i386", operator), + }); + } + } + } + Target::Amd64 => { + self.emit_line(" pop rbx"); // Right operand in rbx + match operator { + BinaryOperator::Add => self.emit_line(" add rax, rbx"), + BinaryOperator::Subtract => self.emit_line(" sub rax, rbx"), + BinaryOperator::Multiply => self.emit_line(" imul rax, rbx"), + BinaryOperator::Divide => { + self.emit_line(" cqo"); // Sign extend rax to rdx:rax + self.emit_line(" idiv rbx"); + } + // Comparison operators + BinaryOperator::Equal => { + self.emit_line(" cmp rax, rbx"); + self.emit_line(" sete al"); + self.emit_line(" movzx rax, al"); + } + BinaryOperator::NotEqual => { + self.emit_line(" cmp rax, rbx"); + self.emit_line(" setne al"); + self.emit_line(" movzx rax, al"); + } + BinaryOperator::Less => { + self.emit_line(" cmp rax, rbx"); + self.emit_line(" setl al"); + self.emit_line(" movzx rax, al"); + } + BinaryOperator::Greater => { + self.emit_line(" cmp rax, rbx"); + self.emit_line(" setg al"); + self.emit_line(" movzx rax, al"); + } + BinaryOperator::LessEqual => { + self.emit_line(" cmp rax, rbx"); + self.emit_line(" setle al"); + self.emit_line(" movzx rax, al"); + } + BinaryOperator::GreaterEqual => { + self.emit_line(" cmp rax, rbx"); + self.emit_line(" setge al"); + self.emit_line(" movzx rax, al"); + } + _ => { + return Err(AleccError::CodegenError { + message: format!("Binary operator {:?} not implemented for amd64", operator), + }); + } + } + } + Target::Arm64 => { + self.emit_line(" ldr x1, [sp], #16"); // Right operand in x1 + match operator { + BinaryOperator::Add => self.emit_line(" add x0, x0, x1"), + BinaryOperator::Subtract => self.emit_line(" sub x0, x0, x1"), + BinaryOperator::Multiply => self.emit_line(" mul x0, x0, x1"), + BinaryOperator::Divide => self.emit_line(" sdiv x0, x0, x1"), + _ => { + return Err(AleccError::CodegenError { + message: format!("Binary operator {:?} not implemented for arm64", operator), + }); + } } } } diff --git a/src/linker.rs b/src/linker.rs index 32b9b7e..00f594f 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -210,40 +210,20 @@ impl Linker { command.push(lib.clone()); } - // Standard libraries + // Standard libraries - skip for now to avoid conflicts + // Our programs use custom runtime with syscalls + /* if !self.static_link { command.push("-lc".to_string()); } + */ Ok(command) } fn add_standard_startup_files(&self, command: &mut Vec) -> Result<()> { - let lib_path = match self.target { - Target::I386 => "/usr/lib/i386-linux-gnu", - Target::Amd64 => "/usr/lib/x86_64-linux-gnu", - Target::Arm64 => "/usr/lib/aarch64-linux-gnu", - }; - - // Add crt1.o, crti.o, crtbegin.o - let startup_files = if self.pie { - vec!["Scrt1.o", "crti.o"] - } else { - vec!["crt1.o", "crti.o"] - }; - - for file in startup_files { - command.push(format!("{}/{}", lib_path, file)); - } - - // Add GCC's crtbegin.o - let gcc_lib = self.get_gcc_lib_path()?; - if self.shared { - command.push(format!("{}/crtbeginS.o", gcc_lib)); - } else { - command.push(format!("{}/crtbegin.o", gcc_lib)); - } - + // Skip startup files when we have our own _start + // This prevents conflicts with our custom _start implementation Ok(()) } diff --git a/src/parser.rs b/src/parser.rs index b10d847..516de90 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -169,7 +169,9 @@ pub struct Parser { impl Parser { pub fn new(tokens: Vec) -> Self { - Self { tokens, current: 0 } + let mut parser = Self { tokens, current: 0 }; + parser.skip_newlines(); // Skip initial newlines + parser } pub fn parse(&mut self) -> Result { @@ -384,9 +386,24 @@ impl Parser { if !self.is_at_end() { self.current += 1; } + self.skip_newlines(); self.previous() } + fn skip_newlines(&mut self) { + while !self.is_at_end() { + if let Ok(token) = self.current_token() { + if token.token_type == TokenType::Newline { + self.current += 1; + } else { + break; + } + } else { + break; + } + } + } + fn previous(&self) -> Result<&Token> { self.tokens.get(self.current - 1).ok_or_else(|| AleccError::ParseError { line: 0, @@ -426,6 +443,16 @@ impl Parser { } } + fn match_tokens(&mut self, token_types: &[TokenType]) -> bool { + for token_type in token_types { + if self.check(token_type) { + self.advance().unwrap(); + return true; + } + } + false + } + fn consume(&mut self, token_type: &TokenType, message: &str) -> Result<&Token> { if self.check(token_type) { self.advance() @@ -495,6 +522,7 @@ impl Parser { self.consume(&TokenType::RightParen, "Expected ')' after parameters")?; let body = if self.check(&TokenType::LeftBrace) { + self.advance()?; // Consume the LeftBrace self.parse_block_statement()? } else { self.consume(&TokenType::Semicolon, "Expected ';' after function declaration")?; @@ -535,8 +563,7 @@ impl Parser { } fn parse_block_statement(&mut self) -> Result { - self.consume(&TokenType::LeftBrace, "Expected '{'")?; - + // Note: LeftBrace was already consumed by match_token in parse_statement let mut statements = Vec::new(); while !self.check(&TokenType::RightBrace) && !self.is_at_end() { statements.push(self.parse_statement()?); @@ -547,7 +574,7 @@ impl Parser { } fn parse_statement(&mut self) -> Result { - // Simplified statement parsing + // Try to parse different types of statements if self.match_token(&TokenType::Return) { let expr = if !self.check(&TokenType::Semicolon) { Some(self.parse_expression()?) @@ -556,25 +583,306 @@ impl Parser { }; self.consume(&TokenType::Semicolon, "Expected ';' after return")?; Ok(Statement::Return(expr)) + } else if self.match_token(&TokenType::If) { + self.parse_if_statement() + } else if self.match_token(&TokenType::While) { + self.parse_while_statement() + } else if self.match_token(&TokenType::For) { + self.parse_for_statement() + } else if self.match_token(&TokenType::LeftBrace) { + self.parse_block_statement() + } else if self.is_type(&self.current_token()?.token_type) { + // Variable declaration - convert to Statement format + let var_type = self.parse_type()?; + let name = if let TokenType::Identifier(name) = &self.advance()?.token_type { + name.clone() + } else { + return Err(AleccError::ParseError { + line: self.current_token()?.line, + column: self.current_token()?.column, + message: "Expected variable name".to_string(), + }); + }; + + let initializer = if self.match_token(&TokenType::Assign) { + Some(self.parse_expression()?) + } else { + None + }; + + self.consume(&TokenType::Semicolon, "Expected ';' after variable declaration")?; + + Ok(Statement::Declaration { + name, + var_type, + initializer, + }) } else { + // Expression statement let expr = self.parse_expression()?; self.consume(&TokenType::Semicolon, "Expected ';' after expression")?; Ok(Statement::Expression(expr)) } } + fn parse_if_statement(&mut self) -> Result { + self.consume(&TokenType::LeftParen, "Expected '(' after 'if'")?; + let condition = self.parse_expression()?; + self.consume(&TokenType::RightParen, "Expected ')' after if condition")?; + + let then_stmt = Box::new(self.parse_statement()?); + let else_stmt = if self.match_token(&TokenType::Else) { + Some(Box::new(self.parse_statement()?)) + } else { + None + }; + + Ok(Statement::If { + condition, + then_stmt, + else_stmt, + }) + } + + fn parse_while_statement(&mut self) -> Result { + self.consume(&TokenType::LeftParen, "Expected '(' after 'while'")?; + let condition = self.parse_expression()?; + self.consume(&TokenType::RightParen, "Expected ')' after while condition")?; + let body = Box::new(self.parse_statement()?); + + Ok(Statement::While { condition, body }) + } + + fn parse_for_statement(&mut self) -> Result { + self.consume(&TokenType::LeftParen, "Expected '(' after 'for'")?; + + let init = if self.check(&TokenType::Semicolon) { + None + } else { + Some(Box::new(self.parse_statement()?)) + }; + + if init.is_none() { + self.advance()?; // consume semicolon + } + + let condition = if self.check(&TokenType::Semicolon) { + None + } else { + Some(self.parse_expression()?) + }; + self.consume(&TokenType::Semicolon, "Expected ';' after for condition")?; + + let increment = if self.check(&TokenType::RightParen) { + None + } else { + Some(self.parse_expression()?) + }; + self.consume(&TokenType::RightParen, "Expected ')' after for clauses")?; + + let body = Box::new(self.parse_statement()?); + + Ok(Statement::For { + init, + condition, + increment, + body, + }) + } + + fn is_type(&self, token_type: &TokenType) -> bool { + matches!(token_type, + TokenType::Int | TokenType::Float | TokenType::Double | + TokenType::Char | TokenType::Void | TokenType::Short | + TokenType::Long | TokenType::Signed | TokenType::Unsigned) + } + fn parse_expression(&mut self) -> Result { - // Simplified expression parsing - just literals and identifiers for now - match &self.advance()?.token_type { + self.parse_logical_or() + } + + fn parse_logical_or(&mut self) -> Result { + let mut expr = self.parse_logical_and()?; + + while self.match_token(&TokenType::LogicalOr) { + let operator = BinaryOperator::LogicalOr; + let right = self.parse_logical_and()?; + expr = Expression::Binary { + left: Box::new(expr), + operator, + right: Box::new(right), + }; + } + + Ok(expr) + } + + fn parse_logical_and(&mut self) -> Result { + let mut expr = self.parse_equality()?; + + while self.match_token(&TokenType::LogicalAnd) { + let operator = BinaryOperator::LogicalAnd; + let right = self.parse_equality()?; + expr = Expression::Binary { + left: Box::new(expr), + operator, + right: Box::new(right), + }; + } + + Ok(expr) + } + + fn parse_equality(&mut self) -> Result { + let mut expr = self.parse_comparison()?; + + while self.match_tokens(&[TokenType::Equal, TokenType::NotEqual]) { + let operator = match self.previous()?.token_type { + TokenType::Equal => BinaryOperator::Equal, + TokenType::NotEqual => BinaryOperator::NotEqual, + _ => unreachable!(), + }; + let right = self.parse_comparison()?; + expr = Expression::Binary { + left: Box::new(expr), + operator, + right: Box::new(right), + }; + } + + Ok(expr) + } + + fn parse_comparison(&mut self) -> Result { + let mut expr = self.parse_term()?; + + while self.match_tokens(&[TokenType::Greater, TokenType::GreaterEqual, + TokenType::Less, TokenType::LessEqual]) { + let operator = match self.previous()?.token_type { + TokenType::Greater => BinaryOperator::Greater, + TokenType::GreaterEqual => BinaryOperator::GreaterEqual, + TokenType::Less => BinaryOperator::Less, + TokenType::LessEqual => BinaryOperator::LessEqual, + _ => unreachable!(), + }; + let right = self.parse_term()?; + expr = Expression::Binary { + left: Box::new(expr), + operator, + right: Box::new(right), + }; + } + + Ok(expr) + } + + fn parse_term(&mut self) -> Result { + let mut expr = self.parse_factor()?; + + while self.match_tokens(&[TokenType::Minus, TokenType::Plus]) { + let operator = match self.previous()?.token_type { + TokenType::Minus => BinaryOperator::Subtract, + TokenType::Plus => BinaryOperator::Add, + _ => unreachable!(), + }; + let right = self.parse_factor()?; + expr = Expression::Binary { + left: Box::new(expr), + operator, + right: Box::new(right), + }; + } + + Ok(expr) + } + + fn parse_factor(&mut self) -> Result { + let mut expr = self.parse_unary()?; + + while self.match_tokens(&[TokenType::Divide, TokenType::Multiply, TokenType::Modulo]) { + let operator = match self.previous()?.token_type { + TokenType::Divide => BinaryOperator::Divide, + TokenType::Multiply => BinaryOperator::Multiply, + TokenType::Modulo => BinaryOperator::Modulo, + _ => unreachable!(), + }; + let right = self.parse_unary()?; + expr = Expression::Binary { + left: Box::new(expr), + operator, + right: Box::new(right), + }; + } + + Ok(expr) + } + + fn parse_unary(&mut self) -> Result { + if self.match_tokens(&[TokenType::LogicalNot, TokenType::Minus, TokenType::Plus]) { + let operator = match self.previous()?.token_type { + TokenType::LogicalNot => UnaryOperator::LogicalNot, + TokenType::Minus => UnaryOperator::Minus, + TokenType::Plus => UnaryOperator::Plus, + _ => unreachable!(), + }; + let right = self.parse_unary()?; + return Ok(Expression::Unary { + operator, + operand: Box::new(right), + }); + } + + self.parse_call() + } + + fn parse_call(&mut self) -> Result { + let mut expr = self.parse_primary()?; + + while self.match_token(&TokenType::LeftParen) { + expr = self.finish_call(expr)?; + } + + Ok(expr) + } + + fn finish_call(&mut self, callee: Expression) -> Result { + let mut arguments = Vec::new(); + + if !self.check(&TokenType::RightParen) { + loop { + arguments.push(self.parse_expression()?); + if !self.match_token(&TokenType::Comma) { + break; + } + } + } + + self.consume(&TokenType::RightParen, "Expected ')' after arguments")?; + + Ok(Expression::Call { + function: Box::new(callee), + arguments, + }) + } + + fn parse_primary(&mut self) -> Result { + if self.match_token(&TokenType::LeftParen) { + let expr = self.parse_expression()?; + self.consume(&TokenType::RightParen, "Expected ')' after expression")?; + return Ok(expr); + } + + let token = self.advance()?; + match &token.token_type { TokenType::IntegerLiteral(value) => Ok(Expression::IntegerLiteral(*value)), TokenType::FloatLiteral(value) => Ok(Expression::FloatLiteral(*value)), TokenType::StringLiteral(value) => Ok(Expression::StringLiteral(value.clone())), TokenType::CharLiteral(value) => Ok(Expression::CharLiteral(*value)), TokenType::Identifier(name) => Ok(Expression::Identifier(name.clone())), _ => Err(AleccError::ParseError { - line: self.current_token()?.line, - column: self.current_token()?.column, - message: "Expected expression".to_string(), + line: token.line, + column: token.column, + message: format!("Expected expression, found {:?}", token.token_type), }), } }