let -> expr

This commit is contained in:
Shautvast 2025-11-25 17:36:00 +01:00
parent 8d61189a03
commit 0e50042bb0
4 changed files with 90 additions and 83 deletions

View file

@ -169,28 +169,6 @@ impl AsmPass {
) -> Result<(), CompilerErrorAtLine> { ) -> Result<(), CompilerErrorAtLine> {
self.current_line = statement.line(); self.current_line = statement.line();
match statement { 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 } => { Statement::ExpressionStmt { expression } => {
self.compile_expression(namespace, expression, symbols, registry)?; self.compile_expression(namespace, expression, symbols, registry)?;
} }
@ -277,6 +255,28 @@ impl AsmPass {
} }
self.chunk.code[goto_addr2] = Op::Goto(self.chunk.code.len()); 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 { Expression::FunctionCall {
name, arguments, .. name, arguments, ..
} => { } => {

View file

@ -1,7 +1,7 @@
use crate::builtins::globals::GLOBAL_FUNCTIONS; use crate::builtins::globals::GLOBAL_FUNCTIONS;
use crate::compiler::ast_pass::Expression::{ use crate::compiler::ast_pass::Expression::{
Assignment, FieldGet, FunctionCall, IfExpression, ListGet, MapGet, MethodCall, NamedParameter, Assignment, FieldGet, FunctionCall, IfExpression, LetExpression, ListGet, MapGet, MethodCall,
Stop, Variable, NamedParameter, Stop, Variable,
}; };
use crate::compiler::tokens::TokenType::{ use crate::compiler::tokens::TokenType::{
Bang, Bool, Char, Colon, DateTime, Dot, Else, Eof, Eol, Equal, False, FloatingPoint, Fn, For, 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 { fn declaration(&mut self, symbol_table: &mut SymbolTable) -> Stmt {
if self.match_token(&[Fn]) { if self.match_token(&[Fn]) {
self.function_declaration(symbol_table) self.function_declaration(symbol_table)
} else if self.match_token(&[Let]) {
self.let_declaration(symbol_table)
} else if self.match_token(&[Object]) { } else if self.match_token(&[Object]) {
self.object_declaration(symbol_table) self.object_declaration(symbol_table)
} else if self.match_token(&[TokenType::Pipe]) { } else if self.match_token(&[TokenType::Pipe]) {
@ -286,47 +284,6 @@ impl AstCompiler {
Ok(Statement::FunctionStmt { function }) 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 { fn statement(&mut self, symbol_table: &mut SymbolTable) -> Stmt {
if self.match_token(&[For]) { if self.match_token(&[For]) {
self.for_statement(symbol_table) self.for_statement(symbol_table)
@ -356,13 +313,56 @@ impl AstCompiler {
} }
fn expr_statement(&mut self, symbol_table: &mut SymbolTable) -> Stmt { 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() { if !self.is_at_end() {
self.consume(&Eol, Expected("end of line after expression."))?; self.consume(&Eol, Expected("end of line after expression."))?;
} }
Ok(Statement::ExpressionStmt { expression: expr }) 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 { fn expression(&mut self, symbol_table: &mut SymbolTable) -> Expr {
self.or(symbol_table) self.or(symbol_table)
} }
@ -843,11 +843,6 @@ pub enum Statement {
ExpressionStmt { ExpressionStmt {
expression: Expression, expression: Expression,
}, },
VarStmt {
name: Token,
var_type: TokenType,
initializer: Expression,
},
FunctionStmt { FunctionStmt {
function: Function, function: Function,
}, },
@ -870,7 +865,6 @@ impl Statement {
pub fn line(&self) -> usize { pub fn line(&self) -> usize {
match self { match self {
Statement::ExpressionStmt { expression } => expression.line(), Statement::ExpressionStmt { expression } => expression.line(),
Statement::VarStmt { name, .. } => name.line,
Statement::FunctionStmt { function, .. } => function.name.line, Statement::FunctionStmt { function, .. } => function.name.line,
Statement::ObjectStmt { name, .. } => name.line, Statement::ObjectStmt { name, .. } => name.line,
Statement::GuardStatement { if_expr, .. } => if_expr.line(), Statement::GuardStatement { if_expr, .. } => if_expr.line(),
@ -981,6 +975,11 @@ pub enum Expression {
then_branch: Vec<Statement>, then_branch: Vec<Statement>,
else_branch: Option<Vec<Statement>>, else_branch: Option<Vec<Statement>>,
}, },
LetExpression {
name: Token,
var_type: TokenType,
initializer: Box<Expression>,
},
} }
impl Expression { impl Expression {
@ -1003,6 +1002,7 @@ impl Expression {
ListGet { .. } => 0, ListGet { .. } => 0,
FieldGet { .. } => 0, FieldGet { .. } => 0,
IfExpression { condition, .. } => condition.line(), IfExpression { condition, .. } => condition.line(),
LetExpression { name, .. } => name.line,
} }
} }
} }

View file

@ -428,7 +428,7 @@ sum
} }
#[test] #[test]
fn test() { fn test_if_expression_else() {
run(r#" run(r#"
let a:i64 = if true: let a:i64 = if true:
42 42

View file

@ -1,7 +1,7 @@
use crate::compiler::ast_pass::{Expression, Parameter, Statement}; use crate::compiler::ast_pass::{Expression, Parameter, Statement};
use crate::builtins::lookup; use crate::builtins::lookup;
use crate::errors::CompilerError; use crate::errors::CompilerError;
use crate::errors::CompilerError::IncompatibleTypes; use crate::errors::CompilerError::{IncompatibleTypes, UndeclaredVariable};
use crate::compiler::tokens::TokenType::{ use crate::compiler::tokens::TokenType::{
Bool, DateTime, F32, F64, FloatingPoint, Greater, GreaterEqual, I32, I64, Integer, Less, Bool, DateTime, F32, F64, FloatingPoint, Greater, GreaterEqual, I32, I64, Integer, Less,
LessEqual, ListType, MapType, Minus, ObjectType, Plus, SignedInteger, StringType, U32, U64, LessEqual, ListType, MapType, Minus, ObjectType, Plus, SignedInteger, StringType, U32, U64,
@ -11,6 +11,7 @@ use crate::compiler::tokens::{Token, TokenType};
use log::debug; use log::debug;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Deref; use std::ops::Deref;
use crate::compiler::assembly_pass::Op::Assign;
pub enum Symbol { pub enum Symbol {
Function { Function {
@ -40,13 +41,6 @@ fn make_qname(path: &str, name: &Token) -> String {
pub fn build(path: &str, ast: &[Statement], symbols: &mut HashMap<String, Symbol>) { pub fn build(path: &str, ast: &[Statement], symbols: &mut HashMap<String, Symbol>) {
for statement in ast { for statement in ast {
match statement { 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 } => { Statement::FunctionStmt { function } => {
symbols.insert( symbols.insert(
make_qname(path, &function.name), make_qname(path, &function.name),
@ -67,6 +61,18 @@ pub fn build(path: &str, ast: &[Statement], symbols: &mut HashMap<String, Symbol
}, },
); );
} }
Statement::ExpressionStmt { expression } => {
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<String, Symbol>) -> Token
Expression::FieldGet { .. } => Unknown, Expression::FieldGet { .. } => Unknown,
Expression::Range { lower, .. } => infer_type(lower, symbols), Expression::Range { lower, .. } => infer_type(lower, symbols),
Expression::IfExpression { .. } => Unknown, Expression::IfExpression { .. } => Unknown,
Expression::LetExpression { initializer,.. } => infer_type(initializer, symbols),
} }
} }