if-else expression, simple case

This commit is contained in:
Shautvast 2025-11-30 09:11:25 +01:00
parent d1658bbec6
commit f4de9d1158
4 changed files with 126 additions and 99 deletions

View file

@ -229,14 +229,12 @@ impl AsmPass {
self.emit(Goto(0)); self.emit(Goto(0));
let goto_addr2 = self.chunk.code.len() - 1; // placeholder let goto_addr2 = self.chunk.code.len() - 1; // placeholder
self.chunk.code[goto_addr1] = GotoIfNot(self.chunk.code.len()); self.chunk.code[goto_addr1] = GotoIfNot(self.chunk.code.len());
if else_branch.is_some() {
self.compile_statements( self.compile_statements(
else_branch.as_ref().unwrap(), else_branch,
symbols, symbols,
registry, registry,
namespace, namespace,
)?; )?;
}
self.chunk.code[goto_addr2] = Op::Goto(self.chunk.code.len()); self.chunk.code[goto_addr2] = Op::Goto(self.chunk.code.len());
} }
Expression::LetExpression { Expression::LetExpression {
@ -245,12 +243,12 @@ impl AsmPass {
let name = name.lexeme.as_str(); let name = name.lexeme.as_str();
let var = symbols.get(name); let var = symbols.get(name);
if let Some(Symbol::Variable { var_type, .. }) = var { if let Some(Symbol::Variable { var_type, .. }) = var {
let inferred_type = infer_type(initializer, symbols); let inferred_type = infer_type(initializer, symbols).map_err(|e| self.error_at_line(e))?;
let calculated_type = let calculated_type =
calculate_type(var_type, &inferred_type).map_err(|e| self.raise(e))?; calculate_type(var_type, &inferred_type).map_err(|e| self.error_at_line(e))?;
if var_type != &Unknown && var_type != &calculated_type { if var_type != &Unknown && var_type != &calculated_type {
return Err( return Err(
self.raise(IncompatibleTypes(var_type.clone(), calculated_type)) self.error_at_line(IncompatibleTypes(var_type.clone(), calculated_type))
); );
} }
let name_index = self.chunk.add_var(var_type, name); let name_index = self.chunk.add_var(var_type, name);
@ -258,7 +256,7 @@ impl AsmPass {
self.compile_expression(namespace, initializer, symbols, registry)?; self.compile_expression(namespace, initializer, symbols, registry)?;
self.emit(Assign(name_index)); self.emit(Assign(name_index));
} else { } else {
return Err(self.raise(UndeclaredVariable(name.to_string()))); return Err(self.error_at_line(UndeclaredVariable(name.to_string())));
} }
} }
Expression::FunctionCall { Expression::FunctionCall {
@ -290,7 +288,7 @@ impl AsmPass {
self.emit(Call(name_index, fun.arity())); self.emit(Call(name_index, fun.arity()));
} else { } else {
return Err( return Err(
self.raise(CompilerError::FunctionNotFound(name.to_string())) self.error_at_line(CompilerError::FunctionNotFound(name.to_string()))
); );
} }
} }
@ -303,7 +301,7 @@ impl AsmPass {
.. ..
} => { } => {
self.compile_expression(namespace, receiver, symbols, registry)?; self.compile_expression(namespace, receiver, symbols, registry)?;
let receiver_type = infer_type(receiver, symbols).to_string(); let receiver_type = infer_type(receiver, symbols).map_err(|e|self.error_at_line(e))?.to_string();
let type_index = self.chunk.find_constant(&receiver_type).unwrap_or_else(|| { let type_index = self.chunk.find_constant(&receiver_type).unwrap_or_else(|| {
self.chunk self.chunk
@ -314,9 +312,9 @@ impl AsmPass {
self.chunk self.chunk
.add_constant(Value::String(method_name.to_string())) .add_constant(Value::String(method_name.to_string()))
}); });
let signature = lookup(&receiver_type, method_name).map_err(|e| self.raise(e))?; let signature = lookup(&receiver_type, method_name).map_err(|e| self.error_at_line(e))?;
if signature.arity() != arguments.len() { if signature.arity() != arguments.len() {
return Err(self.raise(CompilerError::IllegalArgumentsException( return Err(self.error_at_line(CompilerError::IllegalArgumentsException(
format!("{}.{}", receiver_type, method_name), format!("{}.{}", receiver_type, method_name),
signature.parameters.len(), signature.parameters.len(),
arguments.len(), arguments.len(),
@ -336,7 +334,7 @@ impl AsmPass {
if let Some(name_index) = name_index { if let Some(name_index) = name_index {
self.emit(Get(*name_index)); self.emit(Get(*name_index));
} else { } else {
return Err(self.raise(UndeclaredVariable(name.to_string()))); return Err(self.error_at_line(UndeclaredVariable(name.to_string())));
} }
} }
Expression::Assignment { Expression::Assignment {
@ -349,7 +347,7 @@ impl AsmPass {
if let Some(name_index) = name_index { if let Some(name_index) = name_index {
self.emit(Assign(*name_index)); self.emit(Assign(*name_index));
} else { } else {
return Err(self.raise(UndeclaredVariable(variable_name.to_string()))); return Err(self.error_at_line(UndeclaredVariable(variable_name.to_string())));
} }
} }
Expression::Literal { value, .. } => { Expression::Literal { value, .. } => {
@ -402,7 +400,7 @@ impl AsmPass {
self.emit(Assign(*index)); self.emit(Assign(*index));
self.emit(Pop); self.emit(Pop);
} else { } else {
return Err(self.raise(UndeclaredVariable("".to_string()))); return Err(self.error_at_line(UndeclaredVariable("".to_string())));
} }
} }
TokenType::EqualEqual => self.emit(Equal), TokenType::EqualEqual => self.emit(Equal),
@ -489,10 +487,10 @@ impl AsmPass {
for parameter in parameters { for parameter in parameters {
if let NamedParameter { name, value, .. } = argument { if let NamedParameter { name, value, .. } = argument {
if name.lexeme == parameter.name.lexeme { if name.lexeme == parameter.name.lexeme {
let value_type = infer_type(value, symbols); let value_type = infer_type(value, symbols).map_err(|e| self.error_at_line(e))?;
if parameter.var_type != value_type { if parameter.var_type != value_type {
return Err(self return Err(self
.raise(IncompatibleTypes(parameter.var_type.clone(), value_type))); .error_at_line(IncompatibleTypes(parameter.var_type.clone(), value_type)));
} else { } else {
self.compile_expression(namespace, argument, symbols, registry)?; self.compile_expression(namespace, argument, symbols, registry)?;
break; break;
@ -517,7 +515,7 @@ impl AsmPass {
index index
} }
fn raise(&self, error: CompilerError) -> CompilerErrorAtLine { fn error_at_line(&self, error: CompilerError) -> CompilerErrorAtLine {
CompilerErrorAtLine::raise(error, self.current_line) CompilerErrorAtLine::raise(error, self.current_line)
} }
} }

View file

@ -87,11 +87,11 @@ impl AstCompiler {
debug!("AST {:?}", statements); debug!("AST {:?}", statements);
Ok(statements) Ok(statements)
} else { } else {
Err(self.raise(CompilerError::Failure)) Err(self.error_at_line(CompilerError::Failure))
} }
} }
fn raise(&self, error: CompilerError) -> CompilerErrorAtLine { fn error_at_line(&self, error: CompilerError) -> CompilerErrorAtLine {
CompilerErrorAtLine::raise(error, self.current_line()) CompilerErrorAtLine::raise(error, self.current_line())
} }
@ -111,7 +111,7 @@ impl AstCompiler {
indent_on_line += 1; indent_on_line += 1;
} }
if indent_on_line > expected_indent { if indent_on_line > expected_indent {
Err(self.raise(UnexpectedIndent(indent_on_line, expected_indent))) Err(self.error_at_line(UnexpectedIndent(indent_on_line, expected_indent)))
} else if indent_on_line < expected_indent { } else if indent_on_line < expected_indent {
self.indent.pop(); self.indent.pop();
Ok(None) Ok(None)
@ -148,7 +148,7 @@ impl AstCompiler {
} else if self.match_token(&[TokenType::Question]) { } else if self.match_token(&[TokenType::Question]) {
self.query_guard_expr(symbol_table) self.query_guard_expr(symbol_table)
} else { } else {
Err(self.raise(Expected("-> or ?"))) Err(self.error_at_line(Expected("-> or ?")))
}; };
} }
Ok(Stop { Ok(Stop {
@ -181,7 +181,7 @@ impl AstCompiler {
} }
fn match_expression(&mut self) -> Expr { fn match_expression(&mut self) -> Expr {
Err(self.raise(Expected("unimplemented"))) Err(self.error_at_line(Expected("unimplemented")))
} }
fn object_declaration(&mut self, symbol_table: &mut SymbolTable) -> Stmt { fn object_declaration(&mut self, symbol_table: &mut SymbolTable) -> Stmt {
@ -208,7 +208,7 @@ impl AstCompiler {
if field_type.is_type() { if field_type.is_type() {
self.advance(); self.advance();
} else { } else {
Err(self.raise(Expected("a type")))? Err(self.error_at_line(Expected("a type")))?
} }
fields.push(Parameter { fields.push(Parameter {
name: field_name, name: field_name,
@ -236,7 +236,7 @@ impl AstCompiler {
fn function_declaration(&mut self, symbol_table: &mut SymbolTable) -> Stmt { fn function_declaration(&mut self, symbol_table: &mut SymbolTable) -> Stmt {
let name_token = self.consume(&Identifier, Expected("function name."))?; let name_token = self.consume(&Identifier, Expected("function name."))?;
if GLOBAL_FUNCTIONS.contains_key(name_token.lexeme.as_str()) { if GLOBAL_FUNCTIONS.contains_key(name_token.lexeme.as_str()) {
return Err(self.raise(CompilerError::ReservedFunctionName( return Err(self.error_at_line(CompilerError::ReservedFunctionName(
name_token.lexeme.clone(), name_token.lexeme.clone(),
))); )));
} }
@ -244,7 +244,7 @@ impl AstCompiler {
let mut parameters = vec![]; let mut parameters = vec![];
while !self.check(&RightParen) { while !self.check(&RightParen) {
if parameters.len() >= 25 { if parameters.len() >= 25 {
return Err(self.raise(TooManyParameters)); return Err(self.error_at_line(TooManyParameters));
} }
let parm_name = self.consume(&Identifier, Expected("a parameter name."))?; let parm_name = self.consume(&Identifier, Expected("a parameter name."))?;
@ -292,11 +292,7 @@ impl AstCompiler {
let expr = if self.match_token(&[For]) { let expr = if self.match_token(&[For]) {
self.for_expression(symbol_table)? self.for_expression(symbol_table)?
} else if self.match_token(&[Let]) { } else if self.match_token(&[Let]) {
let expr = self.let_exp(symbol_table)?; self.let_exp(symbol_table)?
if !self.is_at_end() {
self.consume(&Eol, Expected("end of line after expression."))?;
}
expr
} else { } else {
self.expression(symbol_table)? self.expression(symbol_table)?
}; };
@ -321,9 +317,11 @@ impl AstCompiler {
fn let_exp(&mut self, symbol_table: &mut SymbolTable) -> Expr { fn let_exp(&mut self, symbol_table: &mut SymbolTable) -> Expr {
if self.peek().token_type.is_type() { if self.peek().token_type.is_type() {
return Err(self.raise(CompilerError::KeywordNotAllowedAsIdentifier( return Err(
self.error_at_line(CompilerError::KeywordNotAllowedAsIdentifier(
self.peek().token_type.clone(), self.peek().token_type.clone(),
))); )),
);
} }
let name_token = self.consume(&Identifier, Expected("variable name."))?; let name_token = self.consume(&Identifier, Expected("variable name."))?;
@ -337,9 +335,10 @@ impl AstCompiler {
if self.match_token(&[Equal]) { if self.match_token(&[Equal]) {
let initializer = self.expression(symbol_table)?; let initializer = self.expression(symbol_table)?;
let declared_type = declared_type.unwrap_or(Unknown); let declared_type = declared_type.unwrap_or(Unknown);
let inferred_type = infer_type(&initializer, symbol_table); let inferred_type =
let var_type = infer_type(&initializer, symbol_table).map_err(|e| self.error_at_line(e))?;
calculate_type(&declared_type, &inferred_type).map_err(|e| self.raise(e))?; let var_type = calculate_type(&declared_type, &inferred_type)
.map_err(|e| self.error_at_line(e))?;
symbol_table.insert( symbol_table.insert(
name_token.lexeme.clone(), name_token.lexeme.clone(),
Symbol::Variable { Symbol::Variable {
@ -354,7 +353,7 @@ impl AstCompiler {
initializer: Box::new(initializer), initializer: Box::new(initializer),
}) })
} else { } else {
Err(self.raise(UninitializedVariable))? Err(self.error_at_line(UninitializedVariable))?
} }
} }
@ -399,7 +398,7 @@ impl AstCompiler {
value: Box::new(right), value: Box::new(right),
}) })
} else { } else {
Err(self.raise(CompilerError::Failure)) Err(self.error_at_line(CompilerError::Failure))
} }
} else { } else {
Ok(expr) Ok(expr)
@ -503,7 +502,7 @@ impl AstCompiler {
Ok(IfElseExpression { Ok(IfElseExpression {
condition: Box::new(condition), condition: Box::new(condition),
then_branch, then_branch,
else_branch: Some(self.compile(symbol_table)?), else_branch: self.compile(symbol_table)?,
}) })
} else { } else {
Ok(IfExpression { Ok(IfExpression {
@ -555,10 +554,16 @@ impl AstCompiler {
key: Box::new(index), key: Box::new(index),
}, },
_ => { _ => {
return Err(self.raise(CompilerError::IllegalTypeToIndex(var_type.to_string()))); return Err(
self.error_at_line(CompilerError::IllegalTypeToIndex(var_type.to_string()))
);
} }
}, },
_ => return Err(self.raise(CompilerError::IllegalTypeToIndex("Unknown".to_string()))), _ => {
return Err(
self.error_at_line(CompilerError::IllegalTypeToIndex("Unknown".to_string()))
);
}
}; };
self.consume(&RightBracket, Expected("']' after index."))?; self.consume(&RightBracket, Expected("']' after index."))?;
Ok(get) Ok(get)
@ -613,7 +618,7 @@ impl AstCompiler {
self.previous() self.previous()
.lexeme .lexeme
.parse() .parse()
.map_err(|e| self.raise(ParseError(format!("{:?}", e))))?, .map_err(|e| self.error_at_line(ParseError(format!("{:?}", e))))?,
), ),
} }
} else if self.match_token(&[U32]) { } else if self.match_token(&[U32]) {
@ -622,7 +627,7 @@ impl AstCompiler {
literaltype: Integer, literaltype: Integer,
value: Value::U32( value: Value::U32(
u32::from_str_radix(self.previous().lexeme.trim_start_matches("0x"), 16) u32::from_str_radix(self.previous().lexeme.trim_start_matches("0x"), 16)
.map_err(|e| self.raise(ParseError(format!("{:?}", e))))?, .map_err(|e| self.error_at_line(ParseError(format!("{:?}", e))))?,
), ),
} }
} else if self.match_token(&[U64]) { } else if self.match_token(&[U64]) {
@ -631,7 +636,7 @@ impl AstCompiler {
literaltype: Integer, literaltype: Integer,
value: Value::U64( value: Value::U64(
u64::from_str_radix(self.previous().lexeme.trim_start_matches("0x"), 16) u64::from_str_radix(self.previous().lexeme.trim_start_matches("0x"), 16)
.map_err(|e| self.raise(ParseError(format!("{:?}", e))))?, .map_err(|e| self.error_at_line(ParseError(format!("{:?}", e))))?,
), ),
} }
} else if self.match_token(&[FloatingPoint]) { } else if self.match_token(&[FloatingPoint]) {
@ -642,7 +647,7 @@ impl AstCompiler {
self.previous() self.previous()
.lexeme .lexeme
.parse() .parse()
.map_err(|e| self.raise(ParseError(format!("{:?}", e))))?, .map_err(|e| self.error_at_line(ParseError(format!("{:?}", e))))?,
), ),
} }
} else if self.match_token(&[StringType]) { } else if self.match_token(&[StringType]) {
@ -663,7 +668,9 @@ impl AstCompiler {
literaltype: DateTime, literaltype: DateTime,
value: Value::DateTime(Box::new( value: Value::DateTime(Box::new(
chrono::DateTime::parse_from_str(&self.previous().lexeme, DATE_FORMAT_TIMEZONE) chrono::DateTime::parse_from_str(&self.previous().lexeme, DATE_FORMAT_TIMEZONE)
.map_err(|_| self.raise(ParseError(self.previous().lexeme.clone())))? .map_err(|_| {
self.error_at_line(ParseError(self.previous().lexeme.clone()))
})?
.into(), .into(),
)), )),
} }
@ -766,7 +773,7 @@ impl AstCompiler {
let mut arguments = vec![]; let mut arguments = vec![];
while !self.match_token(&[RightParen]) { while !self.match_token(&[RightParen]) {
if arguments.len() >= 25 { if arguments.len() >= 25 {
return Err(self.raise(TooManyParameters)); return Err(self.error_at_line(TooManyParameters));
} }
let arg = self.expression(symbol_table)?; let arg = self.expression(symbol_table)?;
arguments.push(arg); arguments.push(arg);
@ -789,7 +796,7 @@ impl AstCompiler {
self.advance(); self.advance();
} else { } else {
self.had_error = true; self.had_error = true;
return Err(self.raise(message)); return Err(self.error_at_line(message));
} }
Ok(self.previous().clone()) Ok(self.previous().clone())
} }
@ -969,7 +976,7 @@ pub enum Expression {
IfElseExpression { IfElseExpression {
condition: Box<Expression>, condition: Box<Expression>,
then_branch: Vec<Statement>, then_branch: Vec<Statement>,
else_branch: Option<Vec<Statement>>, else_branch: Vec<Statement>,
}, },
LetExpression { LetExpression {
name: Token, name: Token,

View file

@ -73,6 +73,9 @@ pub enum CompilerError {
IllegalArgumentsException(String, usize, usize), IllegalArgumentsException(String, usize, usize),
#[error("Function name {0} is a global function and cannot be used here.")] #[error("Function name {0} is a global function and cannot be used here.")]
ReservedFunctionName(String), ReservedFunctionName(String),
#[error("The if expression branches do not match. Was {0} and {1}")]
IfElseBranchesDoNotMatch(TokenType, TokenType),
} }
#[derive(Error, Debug, PartialEq)] #[derive(Error, Debug, PartialEq)]

View file

@ -118,7 +118,7 @@ pub fn calculate_type(
}) })
} }
pub fn infer_type(expr: &Expression, symbols: &HashMap<String, Symbol>) -> TokenType { pub fn infer_type(expr: &Expression, symbols: &HashMap<String, Symbol>) -> Result<TokenType, CompilerError> {
match expr { match expr {
Expression::Binary { Expression::Binary {
left, left,
@ -126,35 +126,35 @@ pub fn infer_type(expr: &Expression, symbols: &HashMap<String, Symbol>) -> Token
right, right,
.. ..
} => { } => {
let left_type = infer_type(left, symbols); let left_type = infer_type(left, symbols)?;
let right_type = infer_type(right, symbols); let right_type = infer_type(right, symbols)?;
if [Greater, Less, GreaterEqual, LessEqual].contains(&operator.token_type) { if [Greater, Less, GreaterEqual, LessEqual].contains(&operator.token_type) {
Bool Ok(Bool)
} else if left_type == right_type { } else if left_type == right_type {
// map to determined numeric type if yet undetermined (32 or 64 bits) // map to determined numeric type if yet undetermined (32 or 64 bits)
match left_type { Ok(match left_type {
FloatingPoint => F64, FloatingPoint => F64,
Integer => I64, Integer => I64,
_ => left_type, _ => left_type,
} })
} else if let Plus = operator.token_type { } else if let Plus = operator.token_type {
// includes string concatenation with numbers // includes string concatenation with numbers
// followed by type coercion to 64 bits for numeric types // followed by type coercion to 64 bits for numeric types
debug!("coerce {} : {}", left_type, right_type); debug!("coerce {} : {}", left_type, right_type);
match (left_type, right_type) { match (left_type, right_type) {
(_, StringType) => StringType, (_, StringType) => Ok(StringType),
(StringType, _) => StringType, (StringType, _) => Ok(StringType),
(FloatingPoint, _) => F64, (FloatingPoint, _) => Ok(F64),
(Integer, FloatingPoint) => F64, (Integer, FloatingPoint) => Ok(F64),
(Integer, _) => I64, (Integer, _) => Ok(I64),
(I64, Integer) => I64, (I64, Integer) => Ok(I64),
(F64, _) => F64, (F64, _) => Ok(F64),
(U64, U32) => U64, (U64, U32) => Ok(U64),
(I64, I32) => I64, (I64, I32) => Ok(I64),
// could add a date and a duration. future work // could add a date and a duration. future work
// could add a List and a value. also future work // could add a List and a value. also future work
// could add a Map and a tuple. Will I add tuple types? Future work! // could add a Map and a tuple. Will I add tuple types? Future work!
_ => panic!("Unexpected coercion"), _ => Err(CompilerError::Failure), //TODO better error message
} }
// could have done some fall through here, but this will fail less gracefully, // could have done some fall through here, but this will fail less gracefully,
// so if my thinking is wrong or incomplete it will panic // so if my thinking is wrong or incomplete it will panic
@ -162,40 +162,40 @@ pub fn infer_type(expr: &Expression, symbols: &HashMap<String, Symbol>) -> Token
// type coercion to 64 bits for numeric types // type coercion to 64 bits for numeric types
debug!("coerce {} : {}", left_type, right_type); debug!("coerce {} : {}", left_type, right_type);
match (left_type, right_type) { match (left_type, right_type) {
(FloatingPoint, _) => F64, (FloatingPoint, _) => Ok(F64),
(Integer, FloatingPoint) => F64, (Integer, FloatingPoint) => Ok(F64),
(Integer, I64) => I64, (Integer, I64) => Ok(I64),
(I64, FloatingPoint) => F64, (I64, FloatingPoint) => Ok(F64),
(F64, _) => F64, (F64, _) => Ok(F64),
(U64, U32) => U64, (U64, U32) => Ok(U64),
(I64, I32) => I64, (I64, I32) => Ok(I64),
(I64, Integer) => I64, (I64, Integer) => Ok(I64),
_ => panic!("Unexpected coercion"), _ => Err(CompilerError::Failure), // TODO
} }
} }
} }
Expression::Grouping { expression, .. } => infer_type(expression, symbols), Expression::Grouping { expression, .. } => infer_type(expression, symbols),
Expression::Literal { literaltype, .. } => literaltype.clone(), Expression::Literal { literaltype, .. } => Ok(literaltype.clone()),
Expression::List { literaltype, .. } => literaltype.clone(), Expression::List { literaltype, .. } => Ok(literaltype.clone()),
Expression::Map { literaltype, .. } => literaltype.clone(), Expression::Map { literaltype, .. } => Ok(literaltype.clone()),
Expression::Unary { Expression::Unary {
right, operator, .. right, operator, ..
} => { } => {
let literal_type = infer_type(right, symbols); let literal_type = infer_type(right, symbols)?;
if literal_type == Integer && operator.token_type == Minus { if literal_type == Integer && operator.token_type == Minus {
SignedInteger Ok(SignedInteger)
} else { } else {
UnsignedInteger Ok(UnsignedInteger)
} }
} }
Expression::Variable { var_type, .. } => var_type.clone(), Expression::Variable { var_type, .. } => Ok(var_type.clone()),
Expression::Assignment { value, .. } => infer_type(value, symbols), Expression::Assignment { value, .. } => infer_type(value, symbols),
Expression::FunctionCall { name, .. } => { Expression::FunctionCall { name, .. } => {
let symbol = symbols.get(name); let symbol = symbols.get(name);
match symbol { match symbol {
Some(Symbol::Function { return_type, .. }) => return_type.clone(), Some(Symbol::Function { return_type, .. }) => Ok(return_type.clone()),
Some(Symbol::Object { name, .. }) => ObjectType(name.clone()), Some(Symbol::Object { name, .. }) => Ok(ObjectType(name.clone())),
_ => Unknown, _ => Err(CompilerError::Failure), // TODO
} }
} }
Expression::MethodCall { Expression::MethodCall {
@ -205,7 +205,7 @@ pub fn infer_type(expr: &Expression, symbols: &HashMap<String, Symbol>) -> Token
} => { } => {
if let Expression::Literal { value, .. } = receiver.deref() { if let Expression::Literal { value, .. } = receiver.deref() {
if let Ok(signature) = lookup(&value.to_string(), method_name) { if let Ok(signature) = lookup(&value.to_string(), method_name) {
signature.return_type.clone() Ok(signature.return_type.clone())
} else { } else {
unreachable!() //? unreachable!() //?
} }
@ -213,15 +213,34 @@ pub fn infer_type(expr: &Expression, symbols: &HashMap<String, Symbol>) -> Token
infer_type(receiver, symbols) infer_type(receiver, symbols)
} }
} }
Expression::Stop { .. } => Unknown, Expression::Stop { .. } => Ok(Unknown),
Expression::NamedParameter { .. } => Unknown, Expression::NamedParameter { .. } => Ok(Unknown),
Expression::ListGet { .. } => Unknown, Expression::ListGet { .. } => Ok(Unknown),
Expression::MapGet { .. } => Unknown, Expression::MapGet { .. } => Ok(Unknown),
Expression::FieldGet { .. } => Unknown, Expression::FieldGet { .. } => Ok(Unknown),
Expression::Range { lower, .. } => infer_type(lower, symbols), Expression::Range { lower, .. } => infer_type(lower, symbols),
Expression::IfExpression { .. } => Unknown, Expression::IfExpression { .. } => Ok(Unknown),
Expression::IfElseExpression { .. } => Unknown, Expression::IfElseExpression { then_branch, else_branch, .. } => {
Expression::LetExpression { .. } => Void, let mut then_type = Void;
Expression::ForStatement { .. } => Void, for statement in then_branch {
if let Statement::ExpressionStmt { expression } = statement {
then_type = infer_type(expression, symbols)?
}
}
let mut else_type = Void;
for statement in else_branch {
if let Statement::ExpressionStmt { expression } = statement {
else_type = infer_type(expression, symbols)?
}
}
if then_type != else_type{
Err(CompilerError::IfElseBranchesDoNotMatch(then_type, else_type))
} else {
Ok(then_type)
}
},
Expression::LetExpression { .. } => Ok(Void),
Expression::ForStatement { .. } => Ok(Void),
} }
} }