From 0e50042bb074af5ef75967901150a1f9a03b89a4 Mon Sep 17 00:00:00 2001 From: Shautvast Date: Tue, 25 Nov 2025 17:36:00 +0100 Subject: [PATCH] let -> expr --- src/compiler/assembly_pass.rs | 44 +++++++------- src/compiler/ast_pass.rs | 104 ++++++++++++++++----------------- src/compiler/compiler_tests.rs | 2 +- src/symbol_builder.rs | 23 +++++--- 4 files changed, 90 insertions(+), 83 deletions(-) diff --git a/src/compiler/assembly_pass.rs b/src/compiler/assembly_pass.rs index 4daf20d..82fdd55 100644 --- a/src/compiler/assembly_pass.rs +++ b/src/compiler/assembly_pass.rs @@ -169,28 +169,6 @@ impl AsmPass { ) -> Result<(), CompilerErrorAtLine> { self.current_line = statement.line(); match statement { - Statement::VarStmt { - name, initializer, .. - } => { - let name = name.lexeme.as_str(); - let var = symbols.get(name); - if let Some(Symbol::Variable { var_type, .. }) = var { - let inferred_type = infer_type(initializer, symbols); - let calculated_type = - calculate_type(var_type, &inferred_type).map_err(|e| self.raise(e))?; - if var_type != &Unknown && var_type != &calculated_type { - return Err( - self.raise(IncompatibleTypes(var_type.clone(), calculated_type)) - ); - } - let name_index = self.chunk.add_var(var_type, name); - self.vars.insert(name.to_string(), name_index); - self.compile_expression(namespace, initializer, symbols, registry)?; - self.emit(Assign(name_index)); - } else { - return Err(self.raise(UndeclaredVariable(name.to_string()))); - } - } Statement::ExpressionStmt { expression } => { self.compile_expression(namespace, expression, symbols, registry)?; } @@ -277,6 +255,28 @@ impl AsmPass { } self.chunk.code[goto_addr2] = Op::Goto(self.chunk.code.len()); } + Expression::LetExpression { + name, initializer, .. + } => { + let name = name.lexeme.as_str(); + let var = symbols.get(name); + if let Some(Symbol::Variable { var_type, .. }) = var { + let inferred_type = infer_type(initializer, symbols); + let calculated_type = + calculate_type(var_type, &inferred_type).map_err(|e| self.raise(e))?; + if var_type != &Unknown && var_type != &calculated_type { + return Err( + self.raise(IncompatibleTypes(var_type.clone(), calculated_type)) + ); + } + let name_index = self.chunk.add_var(var_type, name); + self.vars.insert(name.to_string(), name_index); + self.compile_expression(namespace, initializer, symbols, registry)?; + self.emit(Assign(name_index)); + } else { + return Err(self.raise(UndeclaredVariable(name.to_string()))); + } + } Expression::FunctionCall { name, arguments, .. } => { diff --git a/src/compiler/ast_pass.rs b/src/compiler/ast_pass.rs index 923879d..a649016 100644 --- a/src/compiler/ast_pass.rs +++ b/src/compiler/ast_pass.rs @@ -1,7 +1,7 @@ use crate::builtins::globals::GLOBAL_FUNCTIONS; use crate::compiler::ast_pass::Expression::{ - Assignment, FieldGet, FunctionCall, IfExpression, ListGet, MapGet, MethodCall, NamedParameter, - Stop, Variable, + Assignment, FieldGet, FunctionCall, IfExpression, LetExpression, ListGet, MapGet, MethodCall, + NamedParameter, Stop, Variable, }; use crate::compiler::tokens::TokenType::{ Bang, Bool, Char, Colon, DateTime, Dot, Else, Eof, Eol, Equal, False, FloatingPoint, Fn, For, @@ -123,8 +123,6 @@ impl AstCompiler { fn declaration(&mut self, symbol_table: &mut SymbolTable) -> Stmt { if self.match_token(&[Fn]) { self.function_declaration(symbol_table) - } else if self.match_token(&[Let]) { - self.let_declaration(symbol_table) } else if self.match_token(&[Object]) { self.object_declaration(symbol_table) } else if self.match_token(&[TokenType::Pipe]) { @@ -286,47 +284,6 @@ impl AstCompiler { Ok(Statement::FunctionStmt { function }) } - fn let_declaration(&mut self, symbol_table: &mut SymbolTable) -> Stmt { - if self.peek().token_type.is_type() { - return Err(self.raise(CompilerError::KeywordNotAllowedAsIdentifier( - self.peek().token_type.clone(), - ))); - } - let name_token = self.consume(&Identifier, Expected("variable name."))?; - - let declared_type = if self.check(&Colon) { - self.advance(); - Some(self.advance().token_type.clone()) - } else { - None - }; - - if self.match_token(&[Equal]) { - let initializer = self.expression(symbol_table)?; - let declared_type = declared_type.unwrap_or(Unknown); - let inferred_type = infer_type(&initializer, symbol_table); - let var_type = - calculate_type(&declared_type, &inferred_type).map_err(|e| self.raise(e))?; - symbol_table.insert( - name_token.lexeme.clone(), - Symbol::Variable { - name: name_token.lexeme.clone(), - var_type: var_type.clone(), - }, - ); - - self.consume(&Eol, Expected("end of line after initializer."))?; - - Ok(Statement::VarStmt { - name: name_token, - var_type, - initializer, - }) - } else { - Err(self.raise(UninitializedVariable))? - } - } - fn statement(&mut self, symbol_table: &mut SymbolTable) -> Stmt { if self.match_token(&[For]) { self.for_statement(symbol_table) @@ -356,13 +313,56 @@ impl AstCompiler { } fn expr_statement(&mut self, symbol_table: &mut SymbolTable) -> Stmt { - let expr = self.expression(symbol_table)?; + let expr = self.let_exp(symbol_table)?; if !self.is_at_end() { self.consume(&Eol, Expected("end of line after expression."))?; } Ok(Statement::ExpressionStmt { expression: expr }) } + fn let_exp(&mut self, symbol_table: &mut SymbolTable) -> Expr { + if self.match_token(&[Let]) { + if self.peek().token_type.is_type() { + return Err(self.raise(CompilerError::KeywordNotAllowedAsIdentifier( + self.peek().token_type.clone(), + ))); + } + let name_token = self.consume(&Identifier, Expected("variable name."))?; + + let declared_type = if self.check(&Colon) { + self.advance(); + Some(self.advance().token_type.clone()) + } else { + None + }; + + if self.match_token(&[Equal]) { + let initializer = self.expression(symbol_table)?; + let declared_type = declared_type.unwrap_or(Unknown); + let inferred_type = infer_type(&initializer, symbol_table); + let var_type = + calculate_type(&declared_type, &inferred_type).map_err(|e| self.raise(e))?; + symbol_table.insert( + name_token.lexeme.clone(), + Symbol::Variable { + name: name_token.lexeme.clone(), + var_type: var_type.clone(), + }, + ); + + Ok(LetExpression { + name: name_token, + var_type, + initializer: Box::new(initializer), + }) + } else { + Err(self.raise(UninitializedVariable))? + } + } else { + self.expression(symbol_table) + } + } + fn expression(&mut self, symbol_table: &mut SymbolTable) -> Expr { self.or(symbol_table) } @@ -843,11 +843,6 @@ pub enum Statement { ExpressionStmt { expression: Expression, }, - VarStmt { - name: Token, - var_type: TokenType, - initializer: Expression, - }, FunctionStmt { function: Function, }, @@ -870,7 +865,6 @@ impl Statement { pub fn line(&self) -> usize { match self { Statement::ExpressionStmt { expression } => expression.line(), - Statement::VarStmt { name, .. } => name.line, Statement::FunctionStmt { function, .. } => function.name.line, Statement::ObjectStmt { name, .. } => name.line, Statement::GuardStatement { if_expr, .. } => if_expr.line(), @@ -981,6 +975,11 @@ pub enum Expression { then_branch: Vec, else_branch: Option>, }, + LetExpression { + name: Token, + var_type: TokenType, + initializer: Box, + }, } impl Expression { @@ -1003,6 +1002,7 @@ impl Expression { ListGet { .. } => 0, FieldGet { .. } => 0, IfExpression { condition, .. } => condition.line(), + LetExpression { name, .. } => name.line, } } } diff --git a/src/compiler/compiler_tests.rs b/src/compiler/compiler_tests.rs index 394ded1..1819408 100644 --- a/src/compiler/compiler_tests.rs +++ b/src/compiler/compiler_tests.rs @@ -428,7 +428,7 @@ sum } #[test] - fn test() { + fn test_if_expression_else() { run(r#" let a:i64 = if true: 42 diff --git a/src/symbol_builder.rs b/src/symbol_builder.rs index 6e66043..27e0b07 100644 --- a/src/symbol_builder.rs +++ b/src/symbol_builder.rs @@ -1,7 +1,7 @@ use crate::compiler::ast_pass::{Expression, Parameter, Statement}; use crate::builtins::lookup; use crate::errors::CompilerError; -use crate::errors::CompilerError::IncompatibleTypes; +use crate::errors::CompilerError::{IncompatibleTypes, UndeclaredVariable}; use crate::compiler::tokens::TokenType::{ Bool, DateTime, F32, F64, FloatingPoint, Greater, GreaterEqual, I32, I64, Integer, Less, LessEqual, ListType, MapType, Minus, ObjectType, Plus, SignedInteger, StringType, U32, U64, @@ -11,6 +11,7 @@ use crate::compiler::tokens::{Token, TokenType}; use log::debug; use std::collections::HashMap; use std::ops::Deref; +use crate::compiler::assembly_pass::Op::Assign; pub enum Symbol { Function { @@ -40,13 +41,6 @@ fn make_qname(path: &str, name: &Token) -> String { pub fn build(path: &str, ast: &[Statement], symbols: &mut HashMap) { for statement in ast { match statement { - Statement::VarStmt { name, var_type, .. } => { - let key = make_qname(path, name); - symbols.entry(key).or_insert_with(|| Symbol::Variable { - name: name.lexeme.to_string(), - var_type: var_type.clone(), - }); - } Statement::FunctionStmt { function } => { symbols.insert( make_qname(path, &function.name), @@ -67,6 +61,18 @@ pub fn build(path: &str, ast: &[Statement], symbols: &mut HashMap { + match expression{ + Expression::LetExpression { name, var_type, initializer } => { + let key = make_qname(path, name); + symbols.entry(key).or_insert_with(|| Symbol::Variable { + name: name.lexeme.to_string(), + var_type: var_type.clone(), + }); + } + _ =>{} + } + } _ => {} } } @@ -219,5 +225,6 @@ pub fn infer_type(expr: &Expression, symbols: &HashMap) -> Token Expression::FieldGet { .. } => Unknown, Expression::Range { lower, .. } => infer_type(lower, symbols), Expression::IfExpression { .. } => Unknown, + Expression::LetExpression { initializer,.. } => infer_type(initializer, symbols), } }