diff --git a/examples/playground.sb b/examples/playground.sb index 7c788be..cfa9395 100644 --- a/examples/playground.sb +++ b/examples/playground.sb @@ -1,5 +1,8 @@ fn main() { - - let x = 2 + let x = two() println(x) +} + +fn two(): int { + return 2 } \ No newline at end of file diff --git a/src/parser/infer.rs b/src/parser/infer.rs index 91fc16c..4470483 100644 --- a/src/parser/infer.rs +++ b/src/parser/infer.rs @@ -1,7 +1,11 @@ use super::node_type::*; /// Try to infer types of variables +/// +/// TODO: Global symbol table is passed around randomly. +/// This could probably be cleaned up. pub(super) fn infer(program: &mut Program) -> Result<(), String> { + let table = &program.get_symbol_table(); // TODO: Fix aweful nesting for func in &mut program.func { if let Statement::Block(statements) = &mut func.body { @@ -10,7 +14,11 @@ pub(super) fn infer(program: &mut Program) -> Result<(), String> { Statement::Declare(var, expr) => { if let None = &var.ty { if let Some(e) = expr { - var.ty = infer_expression(&e); + var.ty = infer_expression(&e, table); + // Debug info + if let None = var.ty { + dbg!(&var.name); + } } } } @@ -22,18 +30,23 @@ pub(super) fn infer(program: &mut Program) -> Result<(), String> { Ok(()) } -fn infer_expression(expr: &Expression) -> Option { +/// Function table is needed to infer possible function calls +fn infer_expression(expr: &Expression, table: &SymbolTable) -> Option { match expr { Expression::Int(_) => Some(Type::Int), Expression::Bool(_) => Some(Type::Bool), Expression::Str(_) => Some(Type::Str), - Expression::Array(els) => infer_array(els), + Expression::FunctionCall(name, _) => infer_function_call(name, table), + Expression::Array(els) => infer_array(els, table), _ => None, } } -fn infer_array(elements: &Vec) -> Option { - let types: Vec> = elements.iter().map(|el| infer_expression(el)).collect(); +fn infer_array(elements: &Vec, table: &SymbolTable) -> Option { + let types: Vec> = elements + .iter() + .map(|el| infer_expression(el, table)) + .collect(); // TODO: This approach only relies on the first element. // It will not catch that types are possibly inconsistent. @@ -42,3 +55,10 @@ fn infer_array(elements: &Vec) -> Option { None => None, } } + +fn infer_function_call(name: &str, table: &SymbolTable) -> Option { + match table.get(name) { + Some(t) => t.to_owned(), + None => None, + } +} diff --git a/src/parser/node_type.rs b/src/parser/node_type.rs index b3efba3..e341184 100644 --- a/src/parser/node_type.rs +++ b/src/parser/node_type.rs @@ -15,6 +15,10 @@ */ use crate::lexer::*; use core::convert::TryFrom; +use std::collections::HashMap; + +/// Table that contains all symbol and its types +pub type SymbolTable = HashMap>; #[derive(Debug)] pub struct Program { @@ -27,6 +31,16 @@ impl Program { self.func.append(&mut other.func); self.globals.append(&mut other.globals) } + + pub fn get_symbol_table(&self) -> SymbolTable { + let mut table = SymbolTable::new(); + + for func in self.func.clone() { + table.insert(func.name, func.ret_type); + } + + table + } } #[derive(Debug, Clone)]