Browse Source

feat: infer function return types

github-actions
Garrit Franke 3 years ago
parent
commit
54b971b445
  1. 7
      examples/playground.sb
  2. 30
      src/parser/infer.rs
  3. 14
      src/parser/node_type.rs

7
examples/playground.sb

@ -1,5 +1,8 @@
fn main() {
let x = 2
let x = two()
println(x)
}
fn two(): int {
return 2
}

30
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<Type> {
/// Function table is needed to infer possible function calls
fn infer_expression(expr: &Expression, table: &SymbolTable) -> Option<Type> {
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<Expression>) -> Option<Type> {
let types: Vec<Option<Type>> = elements.iter().map(|el| infer_expression(el)).collect();
fn infer_array(elements: &Vec<Expression>, table: &SymbolTable) -> Option<Type> {
let types: Vec<Option<Type>> = 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<Expression>) -> Option<Type> {
None => None,
}
}
fn infer_function_call(name: &str, table: &SymbolTable) -> Option<Type> {
match table.get(name) {
Some(t) => t.to_owned(),
None => None,
}
}

14
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<String, Option<Type>>;
#[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)]

Loading…
Cancel
Save