diff --git a/demo.hal b/demo.hal index c1680c6..b89ff09 100644 --- a/demo.hal +++ b/demo.hal @@ -1,2 +1,13 @@ -b := 10.0 / 5.0; -c := b; +c :: C{r: 10.0}; + +A :: struct { + b: B, +} + +B :: struct { + c: C, +} + +C :: struct { + r: real, +} diff --git a/src/main.rs b/src/main.rs index 2613dbb..4544768 100644 --- a/src/main.rs +++ b/src/main.rs @@ -99,10 +99,13 @@ fn typecheck(input: &'static str) -> Vec { } fn main() -> Result<()> { - for s in parse(include_str!("../demo.hal")) { + /* + for s in typecheck(include_str!("../demo.hal")) { println!("{s:#?}"); println!("------------------"); } + */ + typecheck(include_str!("../demo.hal")); //let module = frontend::Module::from_file("./demo.hal")?; //module.write_to("test"); Ok(()) diff --git a/src/parse/expression.rs b/src/parse/expression.rs index c8e57b1..843235e 100644 --- a/src/parse/expression.rs +++ b/src/parse/expression.rs @@ -20,6 +20,7 @@ pub enum Immediate { Integer(String, Base), Real(String), String(String), + Glyph(char), Boolean(bool), } @@ -27,6 +28,7 @@ impl std::fmt::Display for Immediate { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Immediate::Integer(i, b) => write!(f, "{i} ({b:?})"), + Immediate::Glyph(c) => write!(f, "{c}"), Immediate::Real(r) => write!(f, "{r}"), Immediate::String(s) => write!(f, "{s}"), Immediate::Boolean(b) => write!(f, "{b}"), @@ -53,7 +55,7 @@ pub enum ExpressionKind { returns_str: Option, returns_actual: Type, body: Vec, - id: UID, + id: usize, }, FunctionCall { callee: Box, @@ -61,7 +63,7 @@ pub enum ExpressionKind { is_reference: bool, id: UID, }, - StructDef(Vec), + StructDef(Vec, usize), StructLiteral { name: String, args: Vec<(String, Expression)>, @@ -118,7 +120,7 @@ impl std::fmt::Debug for ExpressionKind { } => { write!(f, "(fn({params:?}) -> {returns_actual:?})") }, - e::StructDef(params) => write!(f, "struct {{ {params:?} }}"), + e::StructDef(params, _) => write!(f, "struct {{ {params:?} }}"), e::StructLiteral { name, args } => write!(f, "{name} {{ {args:?} }}"), } } @@ -134,7 +136,6 @@ impl> Parser { pub fn expression(&mut self, precedence: Precedence) -> Result { use ExpressionKind as e; use TokenKind as t; - let mut type_ = Type::Ambiguous; let next = self.peek(0)?; // Unary prefix expression let mut current = if let Ok(operator) = UnaryOp::try_from(&next.0) { @@ -272,33 +273,31 @@ impl> Parser { use ExpressionKind as e; use Immediate as im; use TokenKind as t; - let mut type_ = Type::Ambiguous; let next = self.peek(0)?; let mut span = next.1; let kind = match next.0 { t::IntegerLiteral(i, b) => { self.skip(1); - type_ = Type::Prim(Primitive::integer_ambiguous); e::Immediate(im::Integer(i, b)) }, t::FloatLiteral(f) => { self.skip(1); - type_ = Type::Prim(Primitive::real_ambiguous); e::Immediate(im::Real(f)) }, t::StringLiteral(s) => { self.skip(1); - type_ = Type::Prim(Primitive::string); e::Immediate(im::String(s)) }, + t::GlyphLiteral(c) => { + self.skip(1); + e::Immediate(im::Glyph(c)) + }, t::True => { self.skip(1); - type_ = Type::Prim(Primitive::boolean); e::Immediate(im::Boolean(true)) }, t::False => { self.skip(1); - type_ = Type::Prim(Primitive::boolean); e::Immediate(im::Boolean(false)) }, // Function definition @@ -355,7 +354,7 @@ impl> Parser { returns_str, returns_actual: Type::Ambiguous, body, - id: "".into(), + id: usize::MAX, } }, // Struct definition @@ -386,7 +385,7 @@ impl> Parser { } } self.eat(t::RightBrace)?; - e::StructDef(params) + e::StructDef(params, usize::MAX) }, // Struct literal t::Identifier(name) if self.look(1, t::LeftBrace).is_ok() => { @@ -435,7 +434,7 @@ impl> Parser { .reason(format!("Expected expression, found {}", next.0)); }, }; - Ok(Expression::new(kind, span, type_)) + Ok(Expression::new(kind, span, Type::Ambiguous)) } fn identifier(&mut self) -> Result<(String, Span)> { diff --git a/src/parse/statement.rs b/src/parse/statement.rs index 0961907..1b78c8e 100644 --- a/src/parse/statement.rs +++ b/src/parse/statement.rs @@ -74,7 +74,7 @@ impl> Parser { let no_semicolon = if let ExpressionKind::FunctionDef { .. } = value.kind { true - } else if let ExpressionKind::StructDef(_) = value.kind { + } else if let ExpressionKind::StructDef(_, _) = value.kind { true } else { false diff --git a/src/semantic/analyzer.rs b/src/semantic/analyzer.rs index e150acf..61551c7 100644 --- a/src/semantic/analyzer.rs +++ b/src/semantic/analyzer.rs @@ -1,85 +1,199 @@ use crate::{ - Expression, ExpressionKind, Statement, err::*, semantic::SymbolTable, + Expression, ExpressionKind, Immediate, Statement, StatementKind, + err::*, + semantic::{Primitive, SymbolTable}, }; use super::Type; pub struct Analyzer { - table: SymbolTable, + pub table: SymbolTable, } impl Analyzer { - pub fn typecheck(statements: Vec) -> Vec { - /* + pub fn typecheck(mut statements: Vec) -> Vec { let mut this = Self { table: SymbolTable::new(), }; - this.block(statements) - */ + for s in &mut statements { + *s = *this.naming_pass_stmt(s.clone().into()).unwrap(); + } + println!("-----TABLE------"); + println!("{:#?}", this.table.table); + println!("-----FUNCS------"); + println!("{:#?}", this.table.functions); + println!("-----STRUCTS----"); + println!("{:#?}", this.table.structs); statements } - // Bottom up type inference - fn propogate_up( + pub fn naming_pass_stmt( + &mut self, + mut stmt: Box, + ) -> Result> { + use StatementKind as s; + stmt.kind = match stmt.kind { + s::Declaration { + name, + type_str, + mut type_actual, + mut value, + mutable, + mut uid, + } => { + value = *self.naming_pass_expr(value.into())?; + if let Some(ref type_str) = type_str { + type_actual = self.table.reference_ident(type_str).type_; + } else { + type_actual = value.type_.clone(); + } + let symbol = + self + .table + .define_ident(&name, type_actual.clone(), mutable)?; + uid = symbol.uid; + s::Declaration { + name, + type_str, + type_actual, + value, + mutable, + uid, + } + }, + s::Assignment { + name, + mut value, + mut uid, + } => { + uid = self.table.reference_ident(&name).uid; + value = *self.naming_pass_expr(value.into())?; + // Hint ident is rhs type and mutable + self.table.modify_ident( + uid.clone(), + None, + Some(value.type_.clone()), + Some(true), + false, + )?; + s::Assignment { name, value, uid } + }, + s::If { + mut predicate, + mut block, + mut else_, + } => { + predicate = *self.naming_pass_expr(predicate.into())?; + self.table.start_block(); + for s in &mut block { + *s = *self.naming_pass_stmt(s.clone().into())?; + } + self.table.end_block(); + else_ = if let Some(else_) = else_ { + Some(self.naming_pass_stmt(else_)?) + } else { + None + }; + s::If { + predicate, + block, + else_, + } + }, + s::While { + mut predicate, + mut block, + } => { + predicate = *self.naming_pass_expr(predicate.into())?; + self.table.start_block(); + for s in &mut block { + *s = *self.naming_pass_stmt(s.clone().into())?; + } + self.table.end_block(); + s::While { predicate, block } + }, + s::Print(mut expression) => { + expression = *self.naming_pass_expr(expression.into())?; + s::Print(expression) + }, + s::Expression(mut expression) => { + expression = *self.naming_pass_expr(expression.into())?; + s::Expression(expression) + }, + s::Block(mut block) => { + self.table.start_block(); + for s in &mut block { + *s = *self.naming_pass_stmt(s.clone().into())?; + } + self.table.end_block(); + s::Block(block) + }, + s::Return(mut expression) => { + if let Some(e) = expression { + expression = Some(*self.naming_pass_expr(e.into())?); + } + s::Return(expression) + }, + s::Error(diagnostic) => s::Error(diagnostic), + }; + Ok(stmt) + } + + pub fn naming_pass_expr( &mut self, mut expr: Box, ) -> Result> { use ExpressionKind as e; expr.kind = match expr.kind { - e::Immediate(imm) => e::Immediate(imm), - e::Identifier(id, mut mangle) => { - let symbol = self.table.lookup(&id).span(&expr.span)?; - mangle = symbol.uid; - expr.type_ = symbol.type_; - e::Identifier(id, mangle) + e::Immediate(immediate) => { + expr.type_ = Type::Prim(match &immediate { + Immediate::Integer(_, _) => Primitive::integer_ambiguous, + Immediate::Real(_) => Primitive::real_ambiguous, + Immediate::String(_) => Primitive::string, + Immediate::Glyph(_) => Primitive::glyph, + Immediate::Boolean(_) => Primitive::boolean, + }); + e::Immediate(immediate) + }, + e::Identifier(name, mut mangle) => { + let sym = self.table.reference_ident(&name); + mangle = sym.uid; + expr.type_ = sym.type_; + e::Identifier(name, mangle) }, e::Binary { op, mut left, mut right, } => { - left = self.propogate_up(left)?; - right = self.propogate_up(right)?; - expr.type_ = - Type::binary_op(&left.type_, op, &right.type_).span(&expr.span)?; + left = self.naming_pass_expr(left)?; + right = self.naming_pass_expr(right)?; e::Binary { op, left, right } }, e::Unary { op, mut child } => { - child = self.propogate_up(child)?; - expr.type_ = Type::unary_op(op, &child.type_).span(&expr.span)?; + child = self.naming_pass_expr(child)?; e::Unary { op, child } }, - e::Parenthesis(mut inner) => { - inner = self.propogate_up(inner)?; - expr.type_ = inner.type_.clone(); - e::Parenthesis(inner) + e::Parenthesis(mut expression) => { + expression = self.naming_pass_expr(expression)?; + e::Parenthesis(expression) }, - // Define anonymous function, do not evaluate body yet e::FunctionDef { - mut params, + params, returns_str, - mut returns_actual, - body, + returns_actual, + mut body, mut id, } => { - for p in &mut params { - p.type_actual = - self.table.lookup_typedef(&p.type_str).span(&expr.span)?; - } - let param_types: Vec<_> = - params.iter().map(|p| p.type_actual.clone()).collect(); - returns_actual = match returns_str { - Some(ref s) => self.table.lookup_typedef(s).span(&expr.span)?, - None => Type::Nothing, - }; id = self .table - .start_func(param_types.clone(), returns_actual.clone()); - expr.type_ = Type::FunctionDef { - params: param_types, - returns: returns_actual.clone().into(), - id: id.clone(), - }; + .create_function(params.clone(), returns_str.clone()); + expr.type_ = Type::Function(id.clone()); + self.table.start_function(); + for s in &mut body { + *s = *self.naming_pass_stmt(s.clone().into())?; + } + self.table.end_function(); e::FunctionDef { params, returns_str, @@ -91,47 +205,12 @@ impl Analyzer { e::FunctionCall { mut callee, mut args, - mut is_reference, - mut id, + is_reference, + id, } => { - callee = self.propogate_up(callee)?; - let (params, returns) = match callee.type_.clone() { - Type::FunctionRef { - id: uid, - params, - returns, - } => { - is_reference = true; - id = uid; - (params, returns) - }, - Type::FunctionDef { - id: uid, - params, - returns, - } => { - is_reference = false; - id = uid; - (params, returns) - }, - _ => { - return error() - .reason(format!("Cannot call type '{}'", callee.type_)) - .span(&expr.span); - }, - }; - expr.type_ = *returns; - // Check that args are correct - if args.len() != params.len() { - return error().reason(format!( - "Expected {} arguments, found {}", - params.len(), - args.len() - )); - } - for (index, a) in args.iter_mut().enumerate() { - *a = *self.propogate_up(a.clone().into())?; - *a = *self.propogate_down(a.clone().into(), params[index].clone())?; + callee = self.naming_pass_expr(callee)?; + for a in &mut args { + *a = *self.naming_pass_expr(a.clone().into())?; } e::FunctionCall { callee, @@ -140,405 +219,31 @@ impl Analyzer { id, } }, - e::StructDef(vec) => todo!(), - e::StructLiteral { ref name, mut args } => { - self.table.lookup_typedef(name).span(&expr.span)?; - todo!() + e::StructDef(params, mut sid) => { + sid = self.table.create_struct(params.clone()); + expr.type_ = Type::Alias(Box::new(Type::Struct(sid))); + e::StructDef(params, sid) + }, + e::StructLiteral { name, mut args } => { + self.table.reference_ident(&name); + for (_, a) in &mut args { + *a = *self.naming_pass_expr(a.clone().into())?; + } + e::StructLiteral { name, args } }, e::Field { - namespace, + mut namespace, field, uid, - } => todo!(), + } => { + namespace = self.naming_pass_expr(namespace)?; + e::Field { + namespace, + field, + uid, + } + }, }; Ok(expr) } - - // Top down type assertion - fn propogate_down( - &mut self, - expr: Box, - expect: Type, - ) -> Result> { - todo!() - } - - /* - fn block(&mut self, block: Vec) -> Vec { - let mut new_block = vec![]; - for st in block { - let span = st.span; - let st = match self.statement(st.into()) { - Ok(st) => *st, - Err(e) => Statement { - kind: StatementKind::Error(e), - span, - }, - }; - new_block.push(st); - } - new_block - } - - fn statement(&mut self, mut stmt: Box) -> Result> { - use Primitive as p; - use StatementKind as s; - match stmt.kind { - // Variable declaration - s::Declaration { - name, - type_str, - value, - mutable, - .. - } => { - let type_lhs = if let Some(ref s) = type_str { - self.table.get_type(s).span(&stmt.span)? - } else { - Type::Ambiguous - }; - 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_) - .reason(format!( - "Expected type '{:?}', found type '{:?}'", - type_lhs, value.type_ - )) - .span(&stmt.span)?; - value.type_ = type_actual.clone(); - let varkind = self - .table - .define_symbol(name.clone(), type_actual.clone(), mutable) - .span(&stmt.span)?; - stmt.kind = s::Declaration { - name, - type_str, - type_actual, - value: *value, - mutable, - varkind, - }; - }, - // Variable assignment - s::Assignment { name, value, .. } => { - let symbol = self.table.find_symbol(&name).span(&stmt.span)?; - // Check that it is mutable - if !symbol.mutable { - return error() - .reason(format!("Cannot assign to immutable '{}'", name)) - .span(&stmt.span); - } - let mut value = - *self.expression(value.into(), Some(symbol.type_.clone()))?; - let type_actual = - Type::coerce(&symbol.type_, &value.type_).span(&stmt.span)?; - value.type_ = type_actual; - stmt.kind = s::Assignment { - name, - value, - varkind: symbol.kind, - }; - }, - s::If { - predicate, - block, - else_, - } => { - self.table.start_block(); - let predicate = - *self.expression(predicate.into(), Some(Type::Prim(p::boolean)))?; - Type::coerce(&Type::Prim(p::boolean), &predicate.type_) - .span(&predicate.span)?; - let block = self.block(block); - let else_ = if let Some(else_) = else_ { - Some(self.statement(else_)?) - } else { - None - }; - stmt.kind = s::If { - predicate, - block, - else_, - }; - self.table.end_block(); - }, - s::While { predicate, block } => { - self.table.start_block(); - let predicate = - *self.expression(predicate.into(), Some(Type::Prim(p::boolean)))?; - Type::coerce(&Type::Prim(p::boolean), &predicate.type_) - .span(&predicate.span)?; - let block = self.block(block); - stmt.kind = s::While { predicate, block }; - self.table.end_block(); - }, - s::Print(e) => { - let mut e = *self.expression(e.into(), None)?; - e.type_ = Type::coerce(&Type::Prim(p::integer), &e.type_)?; - stmt.kind = s::Print(e); - }, - s::Expression(e) => { - 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) => { - self.table.start_block(); - let block = self.block(block); - stmt.kind = s::Block(block); - self.table.end_block(); - }, - 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 mut e = self.expression(e.into(), Some(return_type.clone()))?; - e.type_ = Type::coerce(&return_type, &e.type_).span(&e.span)?; - 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) - } - - fn expression( - &mut self, - mut expr: Box, - type_hint: Option, - ) -> Result> { - // TODO implement type hinting - use ExpressionKind as e; - use Immediate as i; - use Primitive as p; - let type_ = match expr.kind { - e::Immediate(ref i) => Type::Prim(match i { - i::Integer(_, _) => p::integer_ambiguous, - i::Real(_) => p::real_ambiguous, - i::String(_) => p::string, - i::Boolean(_) => p::boolean, - }), - e::Identifier(ref i, ref mut kind) => { - let symbol = self.table.find_symbol(i)?; - *kind = symbol.kind; - self.table.find_symbol(i)?.type_ - }, - e::Binary { op, left, right } => { - let left = self.expression(left, type_hint.clone())?; - let right = self.expression(right, type_hint.clone())?; - let type_ = Type::binary_op(&left.type_, op, &right.type_)?; - expr.kind = e::Binary { left, right, op }; - type_ - }, - e::Unary { op, child } => { - let child = self.expression(child, type_hint.clone())?; - let type_ = Type::unary_op(op, &child.type_)?; - expr.kind = e::Unary { child, op }; - type_ - }, - e::Parenthesis(inner) => { - let inner = self.expression(inner, type_hint.clone())?; - let type_ = inner.type_.clone(); - expr.kind = e::Parenthesis(inner); - type_ - }, - e::FunctionDef { - mut params, - returns_str, - mut returns_actual, - body, - id: _, - } => { - 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 { - p.type_actual = self.table.get_type(&p.type_str).span(&expr.span)?; - self - .table - .define_param(p.name.clone(), p.type_actual.clone())?; - } - let body = self.block(body); - self.table.end_func(); - expr.kind = e::FunctionDef { - params: params.clone(), - returns_str, - returns_actual: returns_actual.clone(), - body, - id, - }; - Type::FunctionDef { - params: params.into_iter().map(|p| p.type_actual).collect(), - returns: returns_actual.into(), - id, - } - }, - e::FunctionCall { callee, mut args } => { - let callee = self.expression(callee, None)?; - // Check that this is actually a function - // TODO allow function references to be called - let Type::FunctionDef { - ref params, - ref returns, - .. - } = callee.type_ - else { - return error() - .reason(format!("Cannot call type {:?}", callee.type_)) - .span(&callee.span); - }; - // Check for correct number of args - if params.len() != args.len() { - return error() - .reason(format!( - "Wrong number of arguments, function expects {}, found {}", - params.len(), - args.len() - )) - .span(&callee.span); - } - // Check for correct arg types - for (expect, actual) in params.iter().zip(args.iter_mut()) { - *actual = - *self.expression(actual.clone().into(), Some(expect.clone()))?; - let coerced_type = Type::coerce(expect, &actual.type_); - if let Ok(t) = coerced_type { - actual.type_ = t; - } else { - return error() - .reason(format!( - "Expected type {expect:?}, found {:?}", - actual.type_ - )) - .span(&actual.span); - } - } - let returns = *returns.clone(); - expr.kind = e::FunctionCall { callee, args }; - returns - }, - e::StructDef(mut params) => { - for p in &mut params { - p.type_actual = self.table.get_type(&p.type_str).span(&expr.span)?; - } - expr.kind = e::StructDef(params.clone()); - Type::StructDef(params) - }, - e::StructLiteral { name, args } => { - let type_ = self.table.get_type(&name).span(&expr.span)?; - let Type::Struct(params) = type_ else { - return error().reason(format!( - "Cannot construct type {:?} as struct literal", - type_ - )); - }; - if args.len() != params.len() { - return error().reason(format!( - "Incorrect number of parameters for struct '{}'; expected {}, \ - found {}", - name, - params.len(), - args.len() - )); - } - // TODO out of order params - let mut new_args = vec![]; - for ( - (argname, argexpr), - Parameter { - name: pname, - type_actual: ptype, - .. - }, - ) in args.iter().zip(params.iter()) - { - if argname != pname { - return error() - .reason(format!( - "In struct literal, expected parameter '{pname}', found \ - '{argname}'" - )) - .span(&argexpr.span); - } - let argspan = argexpr.span; - let mut arg = *self - .expression(argexpr.clone().into(), Some(ptype.clone())) - .trace_span(expr.span, "while parsing struct literal")?; - let coerced_type = Type::coerce(ptype, &arg.type_); - if let Ok(t) = coerced_type { - arg.type_ = t; - } else { - return error() - .reason(format!( - "In struct literal, expected type '{ptype:?}', found '{:?}", - arg.type_, - )) - .span(&argspan); - } - new_args.push((argname.clone(), arg)); - } - expr.kind = e::StructLiteral { - name, - args: new_args, - }; - Type::Struct(params) - }, - e::Field { namespace, field } => { - let namespace = self.expression(namespace, None)?; - // Check that namespace is struct - // TODO: fields in other types - let Type::Struct(ref params) = namespace.type_ else { - return error() - .reason(format!("Type {:?} does not have fields", namespace.type_)) - .span(&namespace.span); - }; - // Check that field is identifier - // TODO: tuple fields? - let e::Identifier(ref name, _) = field.kind else { - return error() - .reason("Field must be an identifier") - .span(&field.span); - }; - let mut type_ = None; - for p in params { - if &p.name == name { - type_ = Some(p.type_actual.clone()); - break; - } - } - let type_ = type_ - .reason(format!( - "Type {:?} does not contain field {}", - namespace, name - )) - .span(&field.span)?; - expr.kind = e::Field { namespace, field }; - type_ - }, - }; - /* - if let Some(expect) = &type_hint { - if let Type::Ambiguous = expect { - } else { - expr.type_ = Type::coerce(expect, &expr.type_)?; - } - } - */ - expr.type_ = type_; - Ok(expr) - } - */ } diff --git a/src/semantic/bottom_up.rs b/src/semantic/bottom_up.rs new file mode 100644 index 0000000..da006d9 --- /dev/null +++ b/src/semantic/bottom_up.rs @@ -0,0 +1,25 @@ +use super::Analyzer; +use crate::{ + Expression, ExpressionKind, Immediate, Statement, StatementKind, + err::*, + semantic::{Primitive, SymbolTable}, +}; + +use super::Type; + +impl Analyzer { + pub fn stmt_bottom_up( + &mut self, + mut stmt: Box, + ) -> Result> { + todo!() + } + + // Bottom up type inference + pub fn expr_bottom_up( + &mut self, + mut expr: Box, + ) -> Result> { + todo!() + } +} diff --git a/src/semantic/mod.rs b/src/semantic/mod.rs index c31e658..5893653 100644 --- a/src/semantic/mod.rs +++ b/src/semantic/mod.rs @@ -1,8 +1,12 @@ mod analyzer; +mod bottom_up; mod primitives; +mod top_down; mod types; -use crate::err::*; +use std::collections::HashMap; + +use crate::{Parameter, err::*}; pub use analyzer::*; pub use primitives::*; pub use types::*; @@ -15,6 +19,20 @@ pub struct Symbol { name: String, type_: Type, uid: UID, + initialized: bool, + mutable: Option, +} + +impl Symbol { + pub fn assert_is_type(&self) -> Result { + if let Type::Alias(ref t) = self.type_ { + return Ok(*t.clone()); + } + error().reason(format!( + "The name '{}' refers to a value, not a type", + self.name + )) + } } #[derive(Debug, Clone)] @@ -26,121 +44,253 @@ enum Definition { #[derive(Debug, Clone)] pub struct SymbolTable { - defs: Vec, + pub structs: Vec, + pub functions: Vec, + scope: Vec, + pub table: HashMap, mangle_num: usize, nesting: usize, } impl SymbolTable { pub fn new() -> Self { + // Setup builtin symbols + let prims = primitive_symbols(); + let mut scope = vec![]; + let mut table = HashMap::new(); + for p in prims { + scope.push(Definition::Ident(p.clone())); + table.insert(p.uid.clone(), p); + } + let nothing_symbol = Symbol { + name: "Nothing".to_string(), + type_: Type::Alias(Box::new(Type::Nothing)), + uid: nothing_mangle(), + initialized: true, + mutable: Some(false), + }; + scope.push(Definition::Ident(nothing_symbol.clone())); + table.insert(nothing_symbol.uid.clone(), nothing_symbol); Self { - defs: vec![], + structs: vec![], + functions: vec![], + scope, + table, mangle_num: 0, nesting: 0, } } + pub fn start_block(&mut self) { + self.scope.push(Definition::BlockStart); + } + + pub fn end_block(&mut self) { + while !self.scope.is_empty() { + if let Some(Definition::BlockStart) = self.scope.pop() { + return; + } + } + unreachable!("Cannot end global scope") + } + + pub fn start_function(&mut self) { + self.nesting += 1; + self.scope.push(Definition::FuncStart); + } + + pub fn end_function(&mut self) { + while !self.scope.is_empty() { + if let Some(Definition::FuncStart) = self.scope.pop() { + return; + } + } + unreachable!("Cannot end global scope") + } + fn generate_uid(&mut self, name: &str) -> UID { - let uid = format!("${name}${}", self.mangle_num); + let uid = format!("${}${name}", self.mangle_num); self.mangle_num += 1; uid } - pub fn start_func(&mut self, params: Vec, returns: Type) -> UID { - self.nesting += 1; - let uid = self.generate_uid("func"); - let type_ = Type::FunctionDef { - params, - returns: returns.into(), - id: uid.clone(), + pub fn create_struct(&mut self, params: Vec) -> SID { + let sid = self.structs.len(); + let mut new_params = vec![]; + for p in params { + let s = self.reference_ident(&p.type_str); + new_params.push((p.name, s.uid)); + } + self.structs.push(StructureDef(new_params)); + sid + } + + pub fn create_function( + &mut self, + params: Vec, + returns: Option, + ) -> FID { + let fid = self.functions.len(); + let mut new_params = vec![]; + for p in params { + let s = self.reference_ident(&p.type_str); + new_params.push(s.uid); + } + let returns = if let Some(s) = returns { + Some(self.reference_ident(&s).uid) + } else { + Some(nothing_mangle()) }; - self.define("", type_.clone()); - self.defs.push(Definition::FuncStart); - uid + self.functions.push(FunctionDef { + params: new_params, + returns, + }); + fid } - pub fn end_func(&mut self) { - while !self.defs.is_empty() { - if let Some(Definition::FuncStart) = self.defs.pop() { - return; + pub fn modify_ident( + &mut self, + uid: UID, + name: Option, + type_: Option, + mutable: Option, + init: bool, + ) -> Result<()> { + { + let symbol = self.table.get_mut(&uid).unwrap(); + if let Some(ref type_) = type_ { + symbol.type_ = symbol.type_.clone().deduce(type_)?; + } + if let Some(m) = mutable { + symbol.mutable = Some(m); } } - unreachable!("Cannot end global scope") - } - pub fn start_block(&mut self) { - while !self.defs.is_empty() { - if let Some(Definition::BlockStart) = self.defs.pop() { - return; - } - } - unreachable!("Cannot end global scope") - } - - pub fn define(&mut self, name: &str, type_: Type) -> UID { - let uid = self.generate_uid(name); - self.defs.push(Definition::Ident(Symbol { - name: name.to_string(), - type_, - uid: uid.clone(), - })); - uid - } - - pub fn define_func(&mut self, name: &str, uid: UID) { - for def in &mut self.defs { - match def { - Definition::Ident(symbol) if symbol.uid == uid => { - symbol.name = name.to_string(); - return; - }, - _ => {}, - } - panic!("Tried to name nonexistant function"); - } - } - - pub fn lookup_typedef(&self, name: &str) -> Result { let mut nesting = self.nesting; - for def in &self.defs { + for def in &mut self.scope { match def { Definition::Ident(symbol) - if (symbol.name == name) + if (symbol.uid == uid) && (nesting == 0 || nesting == self.nesting) => { - if let Type::StructDef(vec) = &symbol.type_ { - return Ok(Type::Struct( - vec.iter().map(|p| p.type_actual.clone()).collect(), - )); + if let Some(ref name) = name { + symbol.name = name.clone(); } + if let Some(ref type_) = type_ { + symbol.type_ = symbol.type_.clone().deduce(type_)?; + } + if let Some(m) = mutable { + symbol.mutable = Some(m); + } + symbol.initialized &= init; + return Ok(()); }, Definition::FuncStart => nesting -= 1, _ => {}, } } - if let Some(p) = Primitive::from_string(name) { - return Ok(Type::Prim(p)); - } - error().reason(format!("Cannot find type definition '{}'", name)) + panic!("Symbol {uid} does not exist") } - pub fn lookup(&self, name: &str) -> Result { + pub fn define_ident( + &mut self, + name: &str, + type_: Type, + mutable: bool, + ) -> Result { + if let Ok(s) = self.lookup_this_scope(name) { + // Re-definition error + // TODO support name shadowing + if s.initialized { + return error() + .reason(format!("Multiple definitions of '{name}' in this scope")); + } + // Referenced before init, modify existing entry + else { + self.modify_ident( + s.uid.clone(), + None, + Some(type_), + Some(mutable), + true, + )?; + return Ok(s); + } + } + // First initialization in this scope + let uid = self.generate_uid(name); + let sym = Symbol { + name: name.into(), + type_, + uid: uid.clone(), + initialized: true, + mutable: Some(mutable), + }; + self.scope.push(Definition::Ident(sym.clone())); + self.table.insert(uid, sym.clone()); + Ok(sym) + } + + pub fn reference_ident(&mut self, name: &str) -> Symbol { + match self.lookup_available_scope(name) { + Ok(s) => s, + Err(_) => { + let uid = self.generate_uid(name); + let sym = Symbol { + name: name.into(), + type_: Type::Ambiguous, + uid: uid.clone(), + initialized: false, + mutable: None, + }; + self.scope.push(Definition::Ident(sym.clone())); + self.table.insert(uid, sym.clone()); + sym + }, + } + } + + pub fn lookup_this_scope(&self, name: &str) -> Result { + self.lookup_scope(name, false) + } + + pub fn lookup_available_scope(&self, name: &str) -> Result { + self.lookup_scope(name, true) + } + + fn lookup_scope(&self, name: &str, with_global: bool) -> Result { let mut nesting = self.nesting; - for def in &self.defs { + for def in &self.scope { match def { Definition::Ident(symbol) if (symbol.name == name) - && (nesting == 0 || nesting == self.nesting) => + && ((nesting == 0 && with_global) || nesting == self.nesting) => { - if let Type::StructDef(_) = symbol.type_ { - continue; - } return Ok(symbol.clone()); }, Definition::FuncStart => nesting -= 1, _ => {}, } } - error().reason(format!("Cannot find the definition of '{}'", name)) + error().reason(format!( + "Cannot find the definition of '{}' in the current scope", + name + )) + } +} + +// I think this works? Box pattern matching weirdness +// going on. If this is ever even used +fn unwrap_aliases(mut t: Type) -> Type { + loop { + if let Type::Alias(ref t1) = t { + if let Type::Alias(t2) = &**t1 { + t = *t2.clone(); + } else { + return t; + } + } else { + return t; + } } } diff --git a/src/semantic/primitives.rs b/src/semantic/primitives.rs index 3a42acc..acf9f1f 100644 --- a/src/semantic/primitives.rs +++ b/src/semantic/primitives.rs @@ -1,6 +1,7 @@ use crate::{BinaryOp, UnaryOp}; use crate::err::*; +use crate::semantic::{Symbol, Type, UID}; macro_rules! primitives { ( $($i:ident),* ) => { @@ -19,6 +20,16 @@ macro_rules! primitives { _ => None, } } + + pub fn mangle(&self) -> UID { + match self { + Primitive::integer_ambiguous => "$$integer_amgibuous".into(), + Primitive::real_ambiguous => "$$real_amgibuous".into(), + $( + Primitive::$i => format!("$${}", stringify!{$i}), + )* + } + } } impl std::fmt::Display for Primitive { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -29,6 +40,17 @@ macro_rules! primitives { } } } + pub fn primitive_symbols() -> Vec { + vec![ + $(Symbol { + name: stringify!{$i}.into(), + type_: Type::Alias(Box::new(Type::Prim(Primitive::$i))), + uid: format!("$${}", stringify!{$i}), + initialized: true, + mutable: Some(false), + },)* + ] + } }; } @@ -114,7 +136,7 @@ impl Primitive { integer_ambiguous, i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole, ) => into, - (real_ambiguous, r32 | r64) => into, + (real_ambiguous, r32 | r64 | real) => into, _ => *self, }; } diff --git a/src/semantic/top_down.rs b/src/semantic/top_down.rs new file mode 100644 index 0000000..4c94d6f --- /dev/null +++ b/src/semantic/top_down.rs @@ -0,0 +1,24 @@ +use super::{Analyzer, Type}; +use crate::{ + Expression, ExpressionKind, Immediate, Statement, StatementKind, + err::*, + semantic::{Primitive, SymbolTable}, +}; + +impl Analyzer { + pub fn stmt_top_down( + &mut self, + mut stmt: Box, + expect: &Type, + ) -> Result> { + todo!() + } + + pub fn expr_top_down( + &mut self, + mut expr: Box, + expect: &Type, + ) -> Result> { + todo!() + } +} diff --git a/src/semantic/types.rs b/src/semantic/types.rs index f26a1ce..1d6cfd0 100644 --- a/src/semantic/types.rs +++ b/src/semantic/types.rs @@ -1,28 +1,34 @@ -use crate::{ - BinaryOp, Expression, ExpressionKind, Immediate, Parameter, Statement, - StatementKind, UnaryOp, -}; +use crate::{BinaryOp, UnaryOp}; -use super::{UID, primitives::*}; +use super::{Symbol, UID, primitives::*}; use crate::err::*; +/// Struct ID +pub type SID = usize; + +#[derive(Debug, Clone)] +pub struct StructureDef(pub Vec<(String, UID)>); + +pub type FID = usize; + +#[derive(Debug, Clone)] +pub struct FunctionDef { + pub params: Vec, + pub returns: Option, +} + +pub fn nothing_mangle() -> UID { + "$$nothing".into() +} + #[derive(Debug, Clone)] pub enum Type { Ambiguous, Nothing, + Alias(Box), Prim(Primitive), - Struct(Vec), - StructDef(Vec), - FunctionRef { - params: Vec, - returns: Box, - id: UID, - }, - FunctionDef { - params: Vec, - returns: Box, - id: UID, - }, + Struct(SID), + Function(FID), } impl std::fmt::Display for Type { @@ -32,15 +38,8 @@ impl std::fmt::Display for Type { Type::Nothing => write!(f, "nothing"), Type::Prim(primitive) => write!(f, "{primitive}"), Type::Struct(vec) => write!(f, "struct {vec:?}"), - Type::StructDef(_) => write!(f, "struct definition"), - Type::FunctionRef { - params, returns, .. - } => { - write!(f, "({params:?}) -> {returns}") - }, - Type::FunctionDef { - params, returns, .. - } => write!(f, "({params:?}) -> {returns}"), + Type::Alias(t) => write!(f, "type alias ({t})"), + Type::Function(fid) => write!(f, "func {fid:?}"), } } } @@ -51,9 +50,9 @@ impl PartialEq for Type { match (self, other) { (Ambiguous, Ambiguous) => true, (Prim(p1), Prim(p2)) if p1 == p2 => true, - (Struct(p1), Struct(p2)) => p1.iter().eq(p2.iter()), - (FunctionRef { id: id1, .. }, FunctionRef { id: id2, .. }) => id1 == id2, - (FunctionDef { id: id1, .. }, FunctionDef { id: id2, .. }) => id1 == id2, + (Struct(p1), Struct(p2)) => p1 == p2, + (Function(id1), Function(id2)) => id1 == id2, + (Alias(t1), Alias(t2)) => t1 == t2, (Nothing, Nothing) => true, _ => false, } @@ -85,17 +84,19 @@ impl Type { } } - pub fn coerce(&mut self, expect: &Type) { + pub fn deduce(self, hint: &Type) -> Result { use Type::*; - *self = match (expect, self.clone()) { - (Ambiguous, Ambiguous) => Ambiguous, - (Ambiguous, t) => t.clone(), + match (hint, self) { + (Ambiguous, t) => Ok(t), + (t, Ambiguous) => Ok(t.clone()), (Prim(mut p1), Prim(p2)) => { p1.coerce(p2); - Prim(p1) + Ok(Prim(p1)) }, - (t1, t2) if t1 == &t2 => t1.clone(), - _ => Ambiguous, - }; + (t1, t2) if t1 == &t2 => Ok(t1.clone()), + (t1, t2) => { + error().reason(format!("Cannot coerce type '{t2}' into '{t1}'")) + }, + } } }