finished variable and function hoisting

This commit is contained in:
Logan 2024-10-25 01:14:44 -05:00
parent 4e13bb2ffc
commit 7e110a9560
9 changed files with 377 additions and 83 deletions

View file

@ -1,3 +1,3 @@
bar :: (a: integer) { 10 + 2 + 3 * 4;
local := a;
}

View file

@ -1,17 +1,17 @@
use std::path::Path; use std::path::Path;
use crate::{ use crate::{
Parser, Tokenizer,
err::*, err::*,
ir::{Compiler, IR},
semantic::{self}, semantic::{self},
Parser, Statement, Tokenizer,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Module { pub struct Module {
file_name: String, file_name: String,
source: String, source: String,
pub program: Vec<Statement>, pub program: Vec<IR>,
errors: Vec<Diagnostic>,
} }
impl Module { impl Module {
@ -31,20 +31,12 @@ impl Module {
let tokens = Tokenizer::new(source.chars()).filter(|t| t.0.is_meaningful()); let tokens = Tokenizer::new(source.chars()).filter(|t| t.0.is_meaningful());
let statements = Parser::new(tokens); let statements = Parser::new(tokens);
let program = semantic::Analyzer::typecheck(statements.collect()); let program = semantic::Analyzer::typecheck(statements.collect());
let mut errors = vec![]; let mut compiler = Compiler::new();
compiler.compile(program);
Self { Self {
file_name, file_name,
source: source.into(), source: source.into(),
program, program: compiler.ir,
errors,
} }
} }
pub fn errors(&self) -> &[Diagnostic] {
&self.errors
}
pub fn ok(&self) -> bool {
self.errors.len() == 0
}
} }

234
src/ir.rs
View file

@ -1,5 +1,6 @@
use crate::{ use crate::{
BinaryOp, Expression, ExpressionKind, Immediate, UnaryOp, BinaryOp, Expression, ExpressionKind, Immediate, Statement, StatementKind,
UnaryOp,
semantic::{Type, VarKind, uid}, semantic::{Type, VarKind, uid},
}; };
@ -15,43 +16,246 @@ pub enum IR {
AssignGlobal { uid: uid }, AssignGlobal { uid: uid },
GetGlobal { uid: uid }, GetGlobal { uid: uid },
StartFunc { uid: uid }, StartFunc { uid: uid },
NewParam { uid: uid, type_: Type },
EndFunc, EndFunc,
ReturnType { type_: Type },
NewParam { uid: uid, type_: Type },
Return,
Call { uid: uid },
Drop,
}
impl std::fmt::Display for IR {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use IR::*;
match self {
BinOp { op, type_ } => write!(f, "{op} ({type_})"),
UnOp { op, type_ } => write!(f, "{op}, {type_}"),
Imm(immediate) => write!(f, "push {immediate}"),
NewLocal { uid, type_ } => write!(f, "local ${uid} = {type_}"),
AssignLocal { uid } => write!(f, "pop local ${uid}"),
GetLocal { uid } => write!(f, "push local ${uid}"),
NewGlobal { uid, type_ } => write!(f, "global ${uid} = {type_}"),
AssignGlobal { uid } => write!(f, "pop global ${uid}"),
GetGlobal { uid } => write!(f, "push global ${uid}"),
StartFunc { uid } => write!(f, "<function id=${uid}>"),
EndFunc => write!(f, "</function>"),
NewParam { uid, type_ } => write!(f, "param ${uid} = {type_}"),
Return => write!(f, "return"),
Call { uid } => write!(f, "call ${uid}"),
Drop => write!(f, "pop"),
ReturnType { type_ } => write!(f, "result {type_}"),
}
}
} }
pub struct Compiler { pub struct Compiler {
ir: Vec<IR>, pub ir: Vec<IR>,
} }
impl Compiler { impl Compiler {
pub fn new() -> Self {
Self { ir: vec![] }
}
pub fn compile(&mut self, block: Vec<Statement>) {
for s in block {
self.statement(s);
}
self.ir = self.hoist_functions();
}
fn statement(&mut self, statement: Statement) {
use StatementKind::*;
match statement.kind {
Declaration {
type_actual,
value,
varkind,
..
} => {
match varkind {
VarKind::Global(uid) => self.ir.push(IR::NewGlobal {
uid,
type_: type_actual,
}),
VarKind::Local(uid) => self.ir.push(IR::NewLocal {
uid,
type_: type_actual,
}),
_ => {},
}
self.expression(value);
match varkind {
VarKind::Global(uid) => self.ir.push(IR::AssignGlobal { uid }),
VarKind::Local(uid) => self.ir.push(IR::AssignLocal { uid }),
_ => {},
};
},
Assignment {
name,
value,
varkind,
} => {
self.expression(value);
match varkind {
VarKind::Global(uid) => self.ir.push(IR::AssignGlobal { uid }),
VarKind::Local(uid) => self.ir.push(IR::AssignLocal { uid }),
_ => {},
}
},
If {
predicate,
block,
else_,
} => todo!(),
While { predicate, block } => todo!(),
Print(expression) => todo!(),
Expression(expression) => {
if expression.type_ == Type::Nothing {
self.expression(expression);
} else {
self.expression(expression);
self.ir.push(IR::Drop);
}
},
Block(statements) => {
for s in statements {
self.statement(s);
}
},
Error(diagnostic) => {
panic!("{}", diagnostic);
},
Return(expression) => {
if let Some(e) = expression {
self.expression(e);
}
self.ir.push(IR::Return);
},
}
}
fn expression(&mut self, expression: Expression) { fn expression(&mut self, expression: Expression) {
use ExpressionKind::*; use ExpressionKind::*;
match expression.kind { match expression.kind {
Immediate(immediate) => { Immediate(immediate) => {
self.ir.push(IR::Imm(immediate)); self.ir.push(IR::Imm(immediate));
}, },
Identifier(name, var_kind) => match var_kind { Identifier(_, var_kind) => match var_kind {
VarKind::Global(uid) => self.ir.push(IR::GetGlobal { uid }), VarKind::Global(uid) => self.ir.push(IR::GetGlobal { uid }),
VarKind::Local(uid) | VarKind::Param(uid) => { VarKind::Local(uid) => self.ir.push(IR::GetLocal { uid }),
self.ir.push(IR::GetLocal { uid }) VarKind::Function(_) => {},
VarKind::Undefined => panic!("Undefined var not caught by typecheck"),
}, },
VarKind::Function(_) => todo!(), Binary {
VarKind::Undefined => todo!(), op,
mut left,
mut right,
} => {
left.type_ = Type::coerce(&expression.type_, &left.type_).unwrap();
right.type_ = Type::coerce(&expression.type_, &right.type_).unwrap();
assert!(&left.type_ == &right.type_);
self.expression(*left.clone());
self.expression(*right);
self.ir.push(IR::BinOp {
op,
type_: expression.type_,
});
},
Unary { op, mut child } => {
child.type_ = Type::coerce(&expression.type_, &child.type_).unwrap();
self.expression(*child);
self.ir.push(IR::UnOp {
op,
type_: expression.type_,
})
},
Parenthesis(mut e) => {
e.type_ = Type::coerce(&expression.type_, &e.type_).unwrap();
self.expression(*e);
}, },
Binary { op, left, right } => todo!(),
Unary { op, child } => todo!(),
Parenthesis(expression) => todo!(),
FunctionDef { FunctionDef {
params, params,
returns_str,
returns_actual, returns_actual,
body, body,
id, id,
} => todo!(), ..
FunctionCall { callee, args } => todo!(), } => {
StructDef(vec) => todo!(), self.ir.push(IR::StartFunc { uid: id });
for (i, p) in params.iter().enumerate() {
self.ir.push(IR::NewParam {
uid: i as uid,
type_: p.type_actual.clone(),
})
}
self.ir.push(IR::ReturnType {
type_: returns_actual,
});
for s in body {
self.statement(s);
}
self.ir.push(IR::EndFunc);
},
FunctionCall { callee, args } => {
let Type::FunctionDef { id, .. } = callee.type_ else {
panic!()
};
for arg in args {
self.expression(arg);
}
self.ir.push(IR::Call { uid: id });
},
StructDef(_) => {},
StructLiteral { name, args } => todo!(), StructLiteral { name, args } => todo!(),
Field { namespace, field } => todo!(), Field { namespace, field } => todo!(),
} }
} }
fn hoist_functions(&self) -> Vec<IR> {
let mut functions = vec![(vec![], vec![])];
let mut result = vec![];
for index in 0..self.ir.len() {
let ir = self.ir.get(index).unwrap();
match ir {
IR::StartFunc { .. } => {
functions.push((vec![], vec![]));
},
IR::EndFunc => {
let (inits, instr) = functions.pop().unwrap();
for ir in inits {
result.push(ir);
}
for ir in instr {
result.push(ir);
}
result.push(IR::EndFunc);
continue;
},
_ => {},
}
// Push instruction to correct stack
let (inits, instr) = functions.last_mut().unwrap();
match ir {
IR::NewLocal { .. }
| IR::NewGlobal { .. }
| IR::NewParam { .. }
| IR::StartFunc { .. } => {
inits.push(ir.clone());
},
_ => instr.push(ir.clone()),
}
}
// Initialize globals
let (inits, instr) = functions.pop().unwrap();
for ir in inits {
result.push(ir);
}
// The main function (index 0)
result.push(IR::StartFunc { uid: 0 });
for ir in instr {
result.push(ir);
}
result.push(IR::EndFunc);
result
}
} }

View file

@ -86,12 +86,10 @@ fn prints(st: &Statement) {
} }
fn main() -> Result<()> { fn main() -> Result<()> {
test_expression("asdf.asdf()"); //test_expression("a.b.c()");
/*
let module = frontend::Module::from_file("./demo.hal")?; let module = frontend::Module::from_file("./demo.hal")?;
for s in &module.program { for s in &module.program {
prints(s); println!("{s}");
} }
*/
Ok(()) Ok(())
} }

View file

@ -23,6 +23,17 @@ pub enum Immediate {
Boolean(bool), Boolean(bool),
} }
impl std::fmt::Display for Immediate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Immediate::Integer(i) => write!(f, "{i}"),
Immediate::Real(r) => write!(f, "{r}"),
Immediate::String(s) => write!(f, "{s}"),
Immediate::Boolean(b) => write!(f, "{b}"),
}
}
}
#[derive(Clone)] #[derive(Clone)]
pub enum ExpressionKind { pub enum ExpressionKind {
Immediate(Immediate), Immediate(Immediate),
@ -99,7 +110,7 @@ impl std::fmt::Debug for ExpressionKind {
write!(f, "({token:?} {child:?})") write!(f, "({token:?} {child:?})")
}, },
e::Identifier(i, _) => write!(f, "{i}"), e::Identifier(i, _) => write!(f, "{i}"),
e::FunctionCall { callee, args } => { e::FunctionCall { callee, args, .. } => {
write!(f, "({callee:?} call {args:?})") write!(f, "({callee:?} call {args:?})")
}, },
e::Field { namespace, field } => { e::Field { namespace, field } => {

View file

@ -29,6 +29,7 @@ pub enum StatementKind {
Print(Expression), Print(Expression),
Expression(Expression), Expression(Expression),
Block(Vec<Statement>), Block(Vec<Statement>),
Return(Option<Expression>),
Error(Diagnostic), Error(Diagnostic),
} }
@ -161,6 +162,19 @@ impl<I: Iterator<Item = Token>> Parser<I> {
span, span,
}); });
}, },
// Return
(Token(t::Return, span2), _) => {
span = span + span2;
self.skip(1);
let expr = self.expression(0).ok();
if let Some(expr) = &expr {
span = span + expr.span;
}
Statement {
span,
kind: s::Return(expr),
}
},
// Expression // Expression
(Token(_, span2), _) => { (Token(_, span2), _) => {
span = span + span2; span = span + span2;

View file

@ -1,3 +1,5 @@
use std::any::Any;
use crate::{ use crate::{
BinaryOp, Expression, ExpressionKind, Immediate, Parameter, Statement, BinaryOp, Expression, ExpressionKind, Immediate, Parameter, Statement,
StatementKind, UnaryOp, StatementKind, UnaryOp,
@ -52,7 +54,12 @@ impl Analyzer {
} else { } else {
Type::Ambiguous Type::Ambiguous
}; };
let mut value = self.expression(value.into())?; let type_hint = if let Type::Ambiguous = type_lhs {
None
} else {
Some(type_lhs.clone())
};
let mut value = self.expression(value.into(), type_hint)?;
let type_actual = Type::coerce(&type_lhs, &value.type_) let type_actual = Type::coerce(&type_lhs, &value.type_)
.reason(format!( .reason(format!(
"Expected type '{:?}', found type '{:?}'", "Expected type '{:?}', found type '{:?}'",
@ -82,7 +89,8 @@ impl Analyzer {
.reason(format!("Cannot assign to immutable '{}'", name)) .reason(format!("Cannot assign to immutable '{}'", name))
.span(&stmt.span); .span(&stmt.span);
} }
let mut value = *self.expression(value.into())?; let mut value =
*self.expression(value.into(), Some(symbol.type_.clone()))?;
let type_actual = let type_actual =
Type::coerce(&symbol.type_, &value.type_).span(&stmt.span)?; Type::coerce(&symbol.type_, &value.type_).span(&stmt.span)?;
value.type_ = type_actual; value.type_ = type_actual;
@ -98,7 +106,8 @@ impl Analyzer {
else_, else_,
} => { } => {
self.table.start_block(); self.table.start_block();
let predicate = *self.expression(predicate.into())?; let predicate =
*self.expression(predicate.into(), Some(Type::Prim(p::boolean)))?;
Type::coerce(&Type::Prim(p::boolean), &predicate.type_) Type::coerce(&Type::Prim(p::boolean), &predicate.type_)
.span(&predicate.span)?; .span(&predicate.span)?;
let block = self.block(block); let block = self.block(block);
@ -116,7 +125,8 @@ impl Analyzer {
}, },
s::While { predicate, block } => { s::While { predicate, block } => {
self.table.start_block(); self.table.start_block();
let predicate = *self.expression(predicate.into())?; let predicate =
*self.expression(predicate.into(), Some(Type::Prim(p::boolean)))?;
Type::coerce(&Type::Prim(p::boolean), &predicate.type_) Type::coerce(&Type::Prim(p::boolean), &predicate.type_)
.span(&predicate.span)?; .span(&predicate.span)?;
let block = self.block(block); let block = self.block(block);
@ -124,10 +134,13 @@ impl Analyzer {
self.table.end_block(); self.table.end_block();
}, },
s::Print(e) => { s::Print(e) => {
stmt.kind = s::Print(*self.expression(e.into())?); stmt.kind = s::Print(*self.expression(e.into(), None)?);
}, },
s::Expression(e) => { s::Expression(e) => {
stmt.kind = s::Expression(*self.expression(e.into())?); let mut expr = *self.expression(e.into(), None)?;
expr.type_ =
Type::coerce(&Type::Ambiguous, &expr.type_).span(&expr.span)?;
stmt.kind = s::Expression(expr);
}, },
s::Block(block) => { s::Block(block) => {
self.table.start_block(); self.table.start_block();
@ -136,6 +149,20 @@ impl Analyzer {
self.table.end_block(); self.table.end_block();
}, },
s::Error(e) => return Err(e), s::Error(e) => return Err(e),
s::Return(mut expression) => {
let return_type = self.table.get_return_type().span(&stmt.span)?;
let type_ = match expression {
Some(e) => {
let e = self.expression(e.into(), Some(return_type.clone()))?;
let type_ = e.type_.clone();
expression = Some(*e);
type_
},
None => Type::Nothing,
};
Type::coerce(&return_type, &type_).span(&stmt.span)?;
stmt.kind = s::Return(expression);
},
} }
Ok(stmt) Ok(stmt)
} }
@ -143,7 +170,9 @@ impl Analyzer {
fn expression( fn expression(
&mut self, &mut self,
mut expr: Box<Expression>, mut expr: Box<Expression>,
type_hint: Option<Type>,
) -> Result<Box<Expression>> { ) -> Result<Box<Expression>> {
// TODO implement type hinting
use ExpressionKind as e; use ExpressionKind as e;
use Immediate as i; use Immediate as i;
use Primitive as p; use Primitive as p;
@ -160,20 +189,20 @@ impl Analyzer {
self.table.find_symbol(i)?.type_ self.table.find_symbol(i)?.type_
}, },
e::Binary { op, left, right } => { e::Binary { op, left, right } => {
let left = self.expression(left)?; let left = self.expression(left, type_hint.clone())?;
let right = self.expression(right)?; let right = self.expression(right, type_hint.clone())?;
let type_ = Type::binary_op(&left.type_, op, &right.type_)?; let type_ = Type::binary_op(&left.type_, op, &right.type_)?;
expr.kind = e::Binary { left, right, op }; expr.kind = e::Binary { left, right, op };
type_ type_
}, },
e::Unary { op, child } => { e::Unary { op, child } => {
let child = self.expression(child)?; let child = self.expression(child, type_hint.clone())?;
let type_ = Type::unary_op(op, &child.type_)?; let type_ = Type::unary_op(op, &child.type_)?;
expr.kind = e::Unary { child, op }; expr.kind = e::Unary { child, op };
type_ type_
}, },
e::Parenthesis(inner) => { e::Parenthesis(inner) => {
let inner = self.expression(inner)?; let inner = self.expression(inner, type_hint.clone())?;
let type_ = inner.type_.clone(); let type_ = inner.type_.clone();
expr.kind = e::Parenthesis(inner); expr.kind = e::Parenthesis(inner);
type_ type_
@ -183,19 +212,19 @@ impl Analyzer {
returns_str, returns_str,
mut returns_actual, mut returns_actual,
body, body,
id, id: _,
} => { } => {
self.table.start_func(); returns_actual = match &returns_str {
Some(s) => self.table.get_type(s).span(&expr.span)?,
None => Type::Nothing,
};
let id = self.table.start_func(returns_actual.clone());
for p in &mut params { for p in &mut params {
p.type_actual = self.table.get_type(&p.type_str).span(&expr.span)?; p.type_actual = self.table.get_type(&p.type_str).span(&expr.span)?;
self self
.table .table
.define_param(p.name.clone(), p.type_actual.clone())?; .define_param(p.name.clone(), p.type_actual.clone())?;
} }
returns_actual = match &returns_str {
Some(s) => self.table.get_type(s).span(&expr.span)?,
None => Type::Nothing,
};
let body = self.block(body); let body = self.block(body);
self.table.end_func(); self.table.end_func();
expr.kind = e::FunctionDef { expr.kind = e::FunctionDef {
@ -205,17 +234,20 @@ impl Analyzer {
body, body,
id, id,
}; };
Type::Function { Type::FunctionDef {
params: params.into_iter().map(|p| p.type_actual).collect(), params: params.into_iter().map(|p| p.type_actual).collect(),
returns: returns_actual.into(), returns: returns_actual.into(),
id,
} }
}, },
e::FunctionCall { callee, mut args } => { e::FunctionCall { callee, mut args } => {
let callee = self.expression(callee)?; let callee = self.expression(callee, None)?;
// Check that this is actually a function // Check that this is actually a function
let Type::Function { // TODO allow function references to be called
let Type::FunctionDef {
ref params, ref params,
ref returns, ref returns,
..
} = callee.type_ } = callee.type_
else { else {
return error() return error()
@ -234,7 +266,8 @@ impl Analyzer {
} }
// Check for correct arg types // Check for correct arg types
for (expect, actual) in params.iter().zip(args.iter_mut()) { for (expect, actual) in params.iter().zip(args.iter_mut()) {
*actual = *self.expression(actual.clone().into())?; *actual =
*self.expression(actual.clone().into(), Some(expect.clone()))?;
let coerced_type = Type::coerce(expect, &actual.type_); let coerced_type = Type::coerce(expect, &actual.type_);
if let Ok(t) = coerced_type { if let Ok(t) = coerced_type {
actual.type_ = t; actual.type_ = t;
@ -296,7 +329,7 @@ impl Analyzer {
} }
let argspan = argexpr.span; let argspan = argexpr.span;
let mut arg = *self let mut arg = *self
.expression(argexpr.clone().into()) .expression(argexpr.clone().into(), Some(ptype.clone()))
.trace_span(expr.span, "while parsing struct literal")?; .trace_span(expr.span, "while parsing struct literal")?;
let coerced_type = Type::coerce(ptype, &arg.type_); let coerced_type = Type::coerce(ptype, &arg.type_);
if let Ok(t) = coerced_type { if let Ok(t) = coerced_type {
@ -318,7 +351,7 @@ impl Analyzer {
Type::Struct(params) Type::Struct(params)
}, },
e::Field { namespace, field } => { e::Field { namespace, field } => {
let namespace = self.expression(namespace)?; let namespace = self.expression(namespace, None)?;
// Check that namespace is struct // Check that namespace is struct
// TODO: fields in other types // TODO: fields in other types
let Type::Struct(ref params) = namespace.type_ else { let Type::Struct(ref params) = namespace.type_ else {
@ -350,6 +383,14 @@ impl Analyzer {
type_ type_
}, },
}; };
/*
if let Some(expect) = &type_hint {
if let Type::Ambiguous = expect {
} else {
expr.type_ = Type::coerce(expect, &expr.type_)?;
}
}
*/
expr.type_ = type_; expr.type_ = type_;
Ok(expr) Ok(expr)
} }

View file

@ -14,7 +14,6 @@ pub type uid = u32;
pub enum VarKind { pub enum VarKind {
Global(uid), Global(uid),
Local(uid), Local(uid),
Param(uid),
Function(uid), Function(uid),
Undefined, Undefined,
} }
@ -22,10 +21,7 @@ pub enum VarKind {
impl VarKind { impl VarKind {
pub fn unwrap(self) -> uid { pub fn unwrap(self) -> uid {
match self { match self {
VarKind::Global(i) VarKind::Global(i) | VarKind::Local(i) | VarKind::Function(i) => i,
| VarKind::Local(i)
| VarKind::Param(i)
| VarKind::Function(i) => i,
VarKind::Undefined => unreachable!("Failed unwrapping uid"), VarKind::Undefined => unreachable!("Failed unwrapping uid"),
} }
} }
@ -43,7 +39,7 @@ pub struct Symbol {
pub enum Definition { pub enum Definition {
Symbol(Symbol), Symbol(Symbol),
BlockStart, BlockStart,
FuncStart, FuncStart(Type),
} }
fn next(array: &mut [uid]) -> uid { fn next(array: &mut [uid]) -> uid {
@ -59,7 +55,7 @@ pub struct SymbolTable {
nesting: usize, nesting: usize,
local_varno: Vec<uid>, local_varno: Vec<uid>,
global_varno: Vec<uid>, global_varno: Vec<uid>,
funcno: Vec<uid>, funcno: uid,
} }
impl SymbolTable { impl SymbolTable {
@ -69,7 +65,7 @@ impl SymbolTable {
nesting: 0, nesting: 0,
global_varno: vec![0], global_varno: vec![0],
local_varno: vec![0], local_varno: vec![0],
funcno: vec![0], funcno: 1,
} }
} }
@ -80,7 +76,7 @@ impl SymbolTable {
mutable: bool, mutable: bool,
) -> Result<VarKind> { ) -> Result<VarKind> {
let kind = match type_ { let kind = match type_ {
Type::Prim(_) | Type::Struct(_) => { Type::Prim(_) | Type::Struct(_) | Type::FunctionRef { .. } => {
if self.nesting == 0 { if self.nesting == 0 {
VarKind::Global(next(&mut self.global_varno)) VarKind::Global(next(&mut self.global_varno))
} else { } else {
@ -93,9 +89,9 @@ impl SymbolTable {
} }
VarKind::Undefined VarKind::Undefined
}, },
Type::Function { .. } => { Type::FunctionDef { id, .. } => {
if !mutable { if !mutable {
VarKind::Function(next(&mut self.funcno)) VarKind::Function(id)
} else { } else {
return error().reason("Function declaration must be immutable"); return error().reason("Function declaration must be immutable");
} }
@ -112,7 +108,7 @@ impl SymbolTable {
} }
fn define_param(&mut self, name: String, type_: Type) -> Result<VarKind> { fn define_param(&mut self, name: String, type_: Type) -> Result<VarKind> {
let kind = VarKind::Param(next(&mut self.local_varno)); let kind = VarKind::Local(next(&mut self.local_varno));
self.syms.push(Definition::Symbol(Symbol { self.syms.push(Definition::Symbol(Symbol {
name, name,
type_, type_,
@ -122,17 +118,29 @@ impl SymbolTable {
Ok(kind) Ok(kind)
} }
fn start_func(&mut self) { fn start_func(&mut self, returns: Type) -> uid {
self.nesting += 1; self.nesting += 1;
self.local_varno.push(0); self.local_varno.push(0);
self.syms.push(Definition::FuncStart); self.syms.push(Definition::FuncStart(returns));
let old = self.funcno;
self.funcno += 1;
old
}
fn get_return_type(&mut self) -> Result<Type> {
for def in &self.syms {
if let Definition::FuncStart(t) = def {
return Ok(t.clone());
}
}
error().reason("Return outside of function")
} }
fn end_func(&mut self) { fn end_func(&mut self) {
self.nesting -= 1; self.nesting -= 1;
self.local_varno.pop(); self.local_varno.pop();
while !self.syms.is_empty() { while !self.syms.is_empty() {
if let Some(Definition::FuncStart) = self.syms.pop() { if let Some(Definition::FuncStart(_)) = self.syms.pop() {
return; return;
} }
} }
@ -154,18 +162,17 @@ impl SymbolTable {
fn find_symbol(&self, find_name: &str) -> Result<Symbol> { fn find_symbol(&self, find_name: &str) -> Result<Symbol> {
let mut nesting = self.nesting; let mut nesting = self.nesting;
println!("Looking for {find_name}, scope = {nesting}");
for s in self.syms.iter().rev() { for s in self.syms.iter().rev() {
match s { match s {
Definition::Symbol(sym) Definition::Symbol(sym)
// Only search function local and global scope // Only search function local and global scope
if nesting == self.nesting || nesting == 0 => { if nesting == self.nesting || nesting == 0 => {
println!("{}, {:?}, {nesting}", sym.name, sym.type_); // Convert function definition to function reference
if find_name == sym.name { if find_name == sym.name {
return Ok(sym.clone()); return Ok(sym.clone());
} }
}, },
Definition::FuncStart => { Definition::FuncStart(_) => {
nesting -= 1; nesting -= 1;
}, },
_ => {}, _ => {},

View file

@ -1,10 +1,10 @@
use crate::{ use crate::{
semantic::{Symbol, SymbolTable},
BinaryOp, Expression, ExpressionKind, Immediate, Parameter, Statement, BinaryOp, Expression, ExpressionKind, Immediate, Parameter, Statement,
StatementKind, UnaryOp, StatementKind, UnaryOp,
semantic::{Symbol, SymbolTable},
}; };
use super::primitives::*; use super::{primitives::*, uid};
use crate::err::*; use crate::err::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -14,10 +14,35 @@ pub enum Type {
Prim(Primitive), Prim(Primitive),
Struct(Vec<Parameter>), Struct(Vec<Parameter>),
StructDef(Vec<Parameter>), StructDef(Vec<Parameter>),
Function { FunctionRef {
params: Vec<Type>, params: Vec<Type>,
returns: Box<Type>, returns: Box<Type>,
}, },
FunctionDef {
params: Vec<Type>,
returns: Box<Type>,
id: uid,
},
}
impl std::fmt::Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Type::Ambiguous => write!(f, "ambiguous"),
Type::Nothing => write!(f, "nothing"),
Type::Prim(primitive) => write!(f, "{primitive}"),
Type::Struct(vec) => write!(f, "struct {vec:?}"),
Type::StructDef(vec) => write!(f, "struct definition"),
Type::FunctionRef { params, returns } => {
write!(f, "({params:?}) -> {returns}")
},
Type::FunctionDef {
params,
returns,
id,
} => write!(f, "({params:?}) -> {returns}"),
}
}
} }
impl PartialEq for Type { impl PartialEq for Type {
@ -31,15 +56,16 @@ impl PartialEq for Type {
.map(|p| p.type_actual.clone()) .map(|p| p.type_actual.clone())
.eq(p2.iter().map(|p| p.type_actual.clone())), .eq(p2.iter().map(|p| p.type_actual.clone())),
( (
Function { FunctionRef {
params: p1, params: p1,
returns: r1, returns: r1,
}, },
Function { FunctionRef {
params: p2, params: p2,
returns: r2, returns: r2,
}, },
) => p1.iter().eq(p2.iter()) && r1 == r2, ) => p1.iter().eq(p2.iter()) && r1 == r2,
(FunctionDef { id: id1, .. }, FunctionDef { id: id2, .. }) => id1 == id2,
(Nothing, Nothing) => true, (Nothing, Nothing) => true,
_ => false, _ => false,
} }
@ -88,6 +114,7 @@ impl Type {
let (p1, p2) = Primitive::coerce_ambiguous(*p1, *p2); let (p1, p2) = Primitive::coerce_ambiguous(*p1, *p2);
if p1 != p2 { e() } else { Ok(Type::Prim(p1)) } if p1 != p2 { e() } else { Ok(Type::Prim(p1)) }
}, },
(t1, t2) if t1 == t2 => Ok(t1.clone()),
_ => e(), _ => e(),
} }
} }