diff --git a/demo.hal b/demo.hal index b89ff09..20c3b7b 100644 --- a/demo.hal +++ b/demo.hal @@ -1,13 +1,2 @@ -c :: C{r: 10.0}; - -A :: struct { - b: B, -} - -B :: struct { - c: C, -} - -C :: struct { - r: real, -} +a : integer : 10; +b := a + 10; diff --git a/index.html b/index.html index 325175c..db56efe 100644 --- a/index.html +++ b/index.html @@ -4,10 +4,11 @@ + diff --git a/src/frontend.rs b/src/frontend.rs index 02dcb07..98ec929 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -1,4 +1,4 @@ -use std::{io::Write, path::Path}; +use std::path::Path; use crate::{ Parser, Tokenizer, diff --git a/src/ir/generate.rs b/src/ir/generate.rs new file mode 100644 index 0000000..4d4f172 --- /dev/null +++ b/src/ir/generate.rs @@ -0,0 +1,107 @@ +use crate::{Expression, ExpressionKind, Statement, StatementKind}; + +use super::*; + +impl Compiler { + fn statement(&mut self, stmt: Statement) { + use StatementKind as s; + match stmt.kind { + s::Declaration { + name, + type_str, + type_actual, + value, + mutable, + uid, + } => self.push(IR::New { + uid, + type_: type_actual, + }), + s::Assignment { name, value, uid } => todo!(), + s::If { + predicate, + block, + else_, + } => todo!(), + s::While { predicate, block } => todo!(), + s::Print(expression) => todo!(), + s::Expression(expression) => todo!(), + s::Block(vec) => todo!(), + s::Return(expression) => todo!(), + s::Error(diagnostic) => todo!(), + } + } + + fn expression(&mut self, expr: Expression) { + use ExpressionKind as e; + match expr.kind { + e::Immediate(immediate) => { + let Type::Prim(p) = expr.type_ else { + unreachable!(); + }; + self.push(IR::Push { + value: immediate, + prim: p, + }) + }, + e::Identifier(_, uid) => { + self.push(IR::Get { uid }); + }, + e::Binary { op, left, right } => { + self.expression(*left); + self.expression(*right); + self.push(IR::BinOp { + op, + type_: expr.type_, + }) + }, + e::Unary { op, child } => { + self.expression(*child); + self.push(IR::UnOp { + op, + type_: expr.type_, + }) + }, + e::Parenthesis(inner) => self.expression(*inner), + e::FunctionDef { + params, + returns_str, + returns_actual, + body, + id, + } => { + self.push(IR::StartFunc { + fid: id, + params: params.into_iter().map(|p| p.type_actual).collect(), + returns: returns_actual, + }); + for s in body { + self.statement(s); + } + self.push(IR::EndFunc); + }, + e::FunctionCall { + callee, args, id, .. + } => { + for arg in args { + self.expression(arg); + } + let fid = if let Type::Function(fid) = expr.type_ { + fid + } else { + unreachable!() + }; + self.push(IR::Call { fid }) + }, + e::StructDef(..) => {}, + e::StructLiteral { name, args, id } => {}, + e::Field { + namespace, + field, + uid, + } => { + self.expression(*namespace); + }, + } + } +} diff --git a/src/ir.rs b/src/ir/mod.rs similarity index 88% rename from src/ir.rs rename to src/ir/mod.rs index 748c946..a75ec01 100644 --- a/src/ir.rs +++ b/src/ir/mod.rs @@ -1,28 +1,52 @@ +mod generate; +pub use generate::*; + use crate::{ - BinaryOp, Expression, ExpressionKind, Immediate, Statement, StatementKind, - UnaryOp, - semantic::{Primitive, Type, UID}, + BinaryOp, Immediate, UnaryOp, + semantic::{FID, Primitive, Type, UID}, }; -/* + #[derive(Debug, Clone)] pub enum IR { - BinOp { op: BinaryOp, type_: Type }, - UnOp { op: UnaryOp, type_: Type }, - Push { prim: Primitive, value: Immediate }, - NewLocal { uid: UID, type_: Type }, - AssignLocal { uid: UID }, - GetLocal { uid: UID }, - NewGlobal { uid: UID, type_: Type }, - AssignGlobal { uid: UID }, - GetGlobal { uid: UID }, - StartFunc { uid: UID }, + BinOp { + op: BinaryOp, + type_: Type, + }, + UnOp { + op: UnaryOp, + type_: Type, + }, + Push { + prim: Primitive, + value: Immediate, + }, + New { + uid: UID, + type_: Type, + }, + Set { + uid: UID, + }, + Get { + uid: UID, + }, + StartFunc { + fid: FID, + params: Vec, + returns: Type, + }, EndFunc, - ReturnType { type_: Type }, - NewParam { uid: UID, type_: Type }, + ReturnType { + type_: Type, + }, Return, - Call { uid: UID }, + Call { + fid: FID, + }, Drop, - Print, + Print { + type_: Type, + }, } impl std::fmt::Display for IR { @@ -32,24 +56,43 @@ impl std::fmt::Display for IR { BinOp { op, type_ } => write!(f, "{op} ({type_})"), UnOp { op, type_ } => write!(f, "{op}, {type_}"), Push { prim, value } => write!(f, "push {value} ({prim})"), - 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, ""), + New { uid, type_ } => write!(f, "local ${uid} = {type_}"), + Set { uid } => write!(f, "pop local ${uid}"), + Get { uid } => write!(f, "push local ${uid}"), + StartFunc { + uid, + params, + returns, + } => write!( + f, + "" + ), EndFunc => write!(f, ""), - 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_}"), - Print => write!(f, "print [DEBUG]"), + Print { type_ } => write!(f, "print {type_} [DEBUG]"), } } } +#[derive(Debug, Clone)] +pub struct Compiler { + ir: Vec, +} + +impl Compiler { + pub fn new() -> Self { + Self { ir: vec![] } + } + + pub fn push(&mut self, ir: IR) { + self.ir.push(ir); + } +} + +/* impl IR { pub fn to_wat(&self) -> String { use BinaryOp as b; diff --git a/src/main.rs b/src/main.rs index 4544768..ea624f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -99,13 +99,10 @@ fn typecheck(input: &'static str) -> Vec { } fn main() -> Result<()> { - /* for s in typecheck(include_str!("../demo.hal")) { - println!("{s:#?}"); println!("------------------"); + println!("{s:#?}"); } - */ - 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 843235e..0ebea87 100644 --- a/src/parse/expression.rs +++ b/src/parse/expression.rs @@ -67,6 +67,7 @@ pub enum ExpressionKind { StructLiteral { name: String, args: Vec<(String, Expression)>, + id: UID, }, Field { namespace: Box, @@ -121,7 +122,7 @@ impl std::fmt::Debug for ExpressionKind { write!(f, "(fn({params:?}) -> {returns_actual:?})") }, e::StructDef(params, _) => write!(f, "struct {{ {params:?} }}"), - e::StructLiteral { name, args } => write!(f, "{name} {{ {args:?} }}"), + e::StructLiteral { name, args, .. } => write!(f, "{name} {{ {args:?} }}"), } } } @@ -410,7 +411,11 @@ impl> Parser { } } self.eat(t::RightBrace)?; - e::StructLiteral { name, args } + e::StructLiteral { + name, + args, + id: "".into(), + } }, t::Identifier(i) => { self.skip(1); diff --git a/src/semantic/analyzer.rs b/src/semantic/analyzer.rs index 61551c7..2b33041 100644 --- a/src/semantic/analyzer.rs +++ b/src/semantic/analyzer.rs @@ -1,10 +1,4 @@ -use crate::{ - Expression, ExpressionKind, Immediate, Statement, StatementKind, - err::*, - semantic::{Primitive, SymbolTable}, -}; - -use super::Type; +use crate::{Statement, semantic::SymbolTable}; pub struct Analyzer { pub table: SymbolTable, @@ -18,6 +12,12 @@ impl Analyzer { for s in &mut statements { *s = *this.naming_pass_stmt(s.clone().into()).unwrap(); } + for s in &mut statements { + *s = *this.bottom_up_stmt(s.clone().into()).unwrap(); + } + for s in &mut statements { + *s = *this.top_down_stmt(s.clone().into()).unwrap(); + } println!("-----TABLE------"); println!("{:#?}", this.table.table); println!("-----FUNCS------"); @@ -26,224 +26,4 @@ impl Analyzer { println!("{:#?}", this.table.structs); statements } - - 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(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.naming_pass_expr(left)?; - right = self.naming_pass_expr(right)?; - e::Binary { op, left, right } - }, - e::Unary { op, mut child } => { - child = self.naming_pass_expr(child)?; - e::Unary { op, child } - }, - e::Parenthesis(mut expression) => { - expression = self.naming_pass_expr(expression)?; - e::Parenthesis(expression) - }, - e::FunctionDef { - params, - returns_str, - returns_actual, - mut body, - mut id, - } => { - id = self - .table - .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, - returns_actual, - body, - id, - } - }, - e::FunctionCall { - mut callee, - mut args, - is_reference, - id, - } => { - callee = self.naming_pass_expr(callee)?; - for a in &mut args { - *a = *self.naming_pass_expr(a.clone().into())?; - } - e::FunctionCall { - callee, - args, - is_reference, - id, - } - }, - 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 { - mut namespace, - field, - uid, - } => { - namespace = self.naming_pass_expr(namespace)?; - e::Field { - namespace, - field, - uid, - } - }, - }; - Ok(expr) - } } diff --git a/src/semantic/bottom_up.rs b/src/semantic/bottom_up.rs index da006d9..1b89a86 100644 --- a/src/semantic/bottom_up.rs +++ b/src/semantic/bottom_up.rs @@ -1,25 +1,283 @@ use super::Analyzer; -use crate::{ - Expression, ExpressionKind, Immediate, Statement, StatementKind, - err::*, - semantic::{Primitive, SymbolTable}, -}; +use crate::{Expression, ExpressionKind, Statement, StatementKind, err::*}; use super::Type; impl Analyzer { - pub fn stmt_bottom_up( + pub fn bottom_up_stmt( &mut self, mut stmt: Box, ) -> Result> { - todo!() + use StatementKind as s; + stmt.kind = match stmt.kind { + s::Declaration { + name, + type_str, + mut type_actual, + mut value, + mutable, + uid, + } => { + value = *self.bottom_up_expr(value.into())?; + if let Some(ref uid) = type_str { + type_actual = + self.table.resolve_type(uid)?.is_alias().span(&stmt.span)?; + } + value.type_ = value + .type_ + .deduce(&type_actual) + .span(&value.span)? + .promote(); + type_actual = value.type_.clone(); + if let Type::Ambiguous = type_actual { + return error() + .reason(format!("Cannot deduce type of {name}")) + .span(&stmt.span); + } + self.table.modify_ident( + uid.clone(), + None, + Some(type_actual.clone()), + None, + true, + )?; + s::Declaration { + name, + type_str, + type_actual, + value, + mutable, + uid, + } + }, + s::Assignment { + name, + mut value, + uid, + } => { + value = *self.bottom_up_expr(value.into())?; + self.table.modify_ident( + uid.clone(), + None, + Some(value.type_.clone()), + Some(true), + true, + )?; + s::Assignment { name, value, uid } + }, + s::If { + mut predicate, + mut block, + mut else_, + } => { + predicate = *self.bottom_up_expr(predicate.into())?; + self.table.start_block(); + for s in &mut block { + *s = *self.bottom_up_stmt(s.clone().into())?; + } + self.table.end_block(); + else_ = if let Some(else_) = else_ { + Some(self.bottom_up_stmt(else_)?) + } else { + None + }; + s::If { + predicate, + block, + else_, + } + }, + s::While { + mut predicate, + mut block, + } => { + predicate = *self.bottom_up_expr(predicate.into())?; + self.table.start_block(); + for s in &mut block { + *s = *self.bottom_up_stmt(s.clone().into())?; + } + self.table.end_block(); + s::While { predicate, block } + }, + s::Print(mut expression) => { + expression = *self.bottom_up_expr(expression.into())?; + s::Print(expression) + }, + s::Expression(mut expression) => { + expression = *self.bottom_up_expr(expression.into())?; + s::Expression(expression) + }, + s::Block(mut block) => { + for s in &mut block { + *s = *self.bottom_up_stmt(s.clone().into())?; + } + s::Block(block) + }, + s::Return(mut expression) => { + expression = if let Some(e) = expression { + Some(*self.bottom_up_expr(e.into())?) + } else { + None + }; + s::Return(expression) + }, + s::Error(diagnostic) => s::Error(diagnostic), + }; + Ok(stmt) } // Bottom up type inference - pub fn expr_bottom_up( + pub fn bottom_up_expr( &mut self, mut expr: Box, ) -> Result> { - todo!() + use ExpressionKind as e; + expr.kind = match expr.kind { + // Type assigned in naming step + e::Immediate(immediate) => e::Immediate(immediate), + e::Identifier(name, mangle) => { + expr.type_ = self + .table + .resolve_type(&mangle) + .trace_span(expr.span, format!("While resolving type of '{name}'"))?; + e::Identifier(name, mangle) + }, + e::Binary { + op, + mut left, + mut right, + } => { + left = self.bottom_up_expr(left)?; + right = self.bottom_up_expr(right)?; + expr.type_ = + Type::binary_op(&left.type_, op, &right.type_).span(&expr.span)?; + e::Binary { op, left, right } + }, + e::Unary { op, mut child } => { + child = self.bottom_up_expr(child)?; + expr.type_ = Type::unary_op(op, &child.type_)?; + e::Unary { op, child } + }, + e::Parenthesis(mut expression) => { + expression = self.bottom_up_expr(expression)?; + expr.type_ = expression.type_.clone(); + e::Parenthesis(expression) + }, + e::FunctionDef { + mut params, + returns_str, + mut returns_actual, + mut body, + id, + } => { + let funcdef = self.table.functions[id].clone(); + self.table.start_function(); + for (uid, param) in funcdef.params.iter().zip(params.iter_mut()) { + let type_ = self.table.resolve_type(uid).span(&expr.span)?; + param.type_actual = type_; + } + for s in &mut body { + *s = *self.bottom_up_stmt(s.clone().into())?; + } + self.table.end_function(); + returns_actual = + self.table.resolve_type(&funcdef.returns).span(&expr.span)?; + e::FunctionDef { + params, + returns_str, + returns_actual, + body, + id, + } + }, + e::FunctionCall { + mut callee, + mut args, + is_reference, + id, + } => { + callee = self.bottom_up_expr(callee)?; + match callee.type_ { + Type::Function(fid) => { + expr.type_ = self + .table + .resolve_type(&self.table.functions[fid].returns) + .span(&callee.span)? + .is_alias() + .span(&expr.span)? + }, + _ => { + return error() + .reason(format!("Cannot call type {}", callee.type_)) + .span(&expr.span); + }, + } + for a in &mut args { + *a = *self.bottom_up_expr(a.clone().into())?; + } + e::FunctionCall { + callee, + args, + is_reference, + id, + } + }, + e::StructDef(mut params, sid) => { + let struct_ = &self.table.structs[sid].0; + for ((_, uid), p) in struct_.iter().zip(params.iter_mut()) { + p.type_actual = self + .table + .resolve_type(uid) + .trace_span(expr.span, "For struct field")?; + } + e::StructDef(params, sid) + }, + e::StructLiteral { name, mut args, id } => { + expr.type_ = self + .table + .resolve_type(&id) + .span(&expr.span)? + .is_alias() + .span(&expr.span)?; + for (_name, arg) in &mut args { + *arg = *self.bottom_up_expr(arg.clone().into())?; + } + e::StructLiteral { name, args, id } + }, + e::Field { + mut namespace, + field, + uid, + } => { + namespace = self.bottom_up_expr(namespace)?; + if let Type::Struct(s) = namespace.type_ { + if let e::Identifier(name, _) = &field.kind { + expr.type_ = self + .table + .get_field(s, name) + .span(&expr.span)? + .is_alias() + .reason("Expected type, found value") + .span(&expr.span)?; + } else { + return error().reason("Field must be identifier").span(&expr.span); + } + } else { + return error() + .reason(format!( + "Type '{}' does not contain fields", + namespace.type_ + )) + .span(&expr.span); + } + // TODO handle name mangle + e::Field { + namespace, + field, + uid, + } + }, + }; + Ok(expr) } } diff --git a/src/semantic/mod.rs b/src/semantic/mod.rs index 5893653..e797c36 100644 --- a/src/semantic/mod.rs +++ b/src/semantic/mod.rs @@ -1,5 +1,6 @@ mod analyzer; mod bottom_up; +mod naming; mod primitives; mod top_down; mod types; @@ -11,6 +12,12 @@ pub use analyzer::*; pub use primitives::*; pub use types::*; +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum Scope { + Block, + Function, +} + // Mangled name pub type UID = String; @@ -23,18 +30,6 @@ pub struct Symbol { 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)] enum Definition { Ident(Symbol), @@ -86,23 +81,47 @@ impl SymbolTable { } pub fn end_block(&mut self) { + let mut escaped = vec![]; while !self.scope.is_empty() { - if let Some(Definition::BlockStart) = self.scope.pop() { + let top = self.scope.pop(); + if let Some(Definition::BlockStart) = top { + self.scope.append(&mut escaped); return; + } else if let Some(Definition::Ident(s)) = top { + if !s.initialized { + escaped.push(Definition::Ident(s)); + } } } unreachable!("Cannot end global scope") } + pub fn resolve_type(&self, uid: &UID) -> Result { + let symbol = self.table.get(uid).unwrap(); + if symbol.initialized == false { + return error().reason("Symbol was never initialized"); + } else { + Ok(symbol.type_.clone()) + } + } + pub fn start_function(&mut self) { self.nesting += 1; self.scope.push(Definition::FuncStart); } pub fn end_function(&mut self) { + self.nesting -= 1; + let mut escaped = vec![]; while !self.scope.is_empty() { - if let Some(Definition::FuncStart) = self.scope.pop() { + let top = self.scope.pop(); + if let Some(Definition::FuncStart) = top { + self.scope.append(&mut escaped); return; + } else if let Some(Definition::Ident(s)) = top { + if !s.initialized { + escaped.push(Definition::Ident(s)); + } } } unreachable!("Cannot end global scope") @@ -114,6 +133,16 @@ impl SymbolTable { uid } + pub fn get_field(&self, struct_id: SID, field_name: &str) -> Result { + let struct_def = &self.structs[struct_id].0; + for (name, sid) in struct_def { + if name == field_name { + return self.resolve_type(sid); + } + } + error().reason(format!("Cannot find field '{field_name}'")) + } + pub fn create_struct(&mut self, params: Vec) -> SID { let sid = self.structs.len(); let mut new_params = vec![]; @@ -129,23 +158,31 @@ impl SymbolTable { &mut self, params: Vec, returns: Option, - ) -> FID { + ) -> Result { 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 mut symbols = vec![]; + for p in ¶ms { + let symbol = self.reference_ident(&p.type_str); + symbols.push(symbol); } let returns = if let Some(s) = returns { - Some(self.reference_ident(&s).uid) + self.reference_ident(&s).uid } else { - Some(nothing_mangle()) + nothing_mangle() }; + self.start_function(); + let mut new_params = vec![]; + for (p, s) in params.iter().zip(symbols.iter()) { + let s = self + .define_ident(&p.name, s.type_.clone(), false) + .trace("While initializing function parameters")?; + new_params.push(s.uid); + } self.functions.push(FunctionDef { params: new_params, returns, }); - fid + Ok(fid) } pub fn modify_ident( @@ -156,15 +193,17 @@ impl SymbolTable { 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); - } + let symbol = self.table.get_mut(&uid).unwrap(); + if let Some(ref type_) = type_ { + symbol.type_ = symbol.type_.clone().deduce(type_)?; } + symbol.mutable = match (symbol.mutable, mutable) { + (Some(true), Some(false)) | (Some(false), Some(true)) => { + return error().reason("Cannot mutate immutable symbol"); + }, + _ => mutable, + }; + symbol.initialized |= init; let mut nesting = self.nesting; for def in &mut self.scope { @@ -179,17 +218,21 @@ impl SymbolTable { 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; + symbol.mutable = match (symbol.mutable, mutable) { + (Some(true), Some(false)) | (Some(false), Some(true)) => { + return error().reason("Cannot mutate immutable symbol"); + }, + _ => mutable, + }; + symbol.initialized |= init; return Ok(()); }, Definition::FuncStart => nesting -= 1, _ => {}, } } - panic!("Symbol {uid} does not exist") + Ok(()) + //unreachable!("Symbol {uid} does not exist") } pub fn define_ident( @@ -198,7 +241,15 @@ impl SymbolTable { type_: Type, mutable: bool, ) -> Result { - if let Ok(s) = self.lookup_this_scope(name) { + println!("---{name}---"); + println!("{:#?}", self.lookup_block_scope(name)); + if let Type::Alias(_) | Type::Function(_) = &type_ { + if mutable { + return error() + .reason("Struct and function definitions cannot be mutable"); + } + } + if let Ok(s) = self.lookup_block_scope(name) { // Re-definition error // TODO support name shadowing if s.initialized { @@ -232,7 +283,7 @@ impl SymbolTable { } pub fn reference_ident(&mut self, name: &str) -> Symbol { - match self.lookup_available_scope(name) { + match self.lookup_function_scope(name) { Ok(s) => s, Err(_) => { let uid = self.generate_uid(name); @@ -250,24 +301,29 @@ impl SymbolTable { } } - pub fn lookup_this_scope(&self, name: &str) -> Result { - self.lookup_scope(name, false) + pub fn lookup_block_scope(&self, name: &str) -> Result { + self.lookup_scope(name, Scope::Block) } - pub fn lookup_available_scope(&self, name: &str) -> Result { - self.lookup_scope(name, true) + pub fn lookup_function_scope(&self, name: &str) -> Result { + self.lookup_scope(name, Scope::Function) } - fn lookup_scope(&self, name: &str, with_global: bool) -> Result { + fn lookup_scope(&self, name: &str, scope: Scope) -> Result { let mut nesting = self.nesting; - for def in &self.scope { + for def in self.scope.iter().rev() { match def { Definition::Ident(symbol) if (symbol.name == name) - && ((nesting == 0 && with_global) || nesting == self.nesting) => + && ((nesting == 0) || nesting == self.nesting) => { return Ok(symbol.clone()); }, + Definition::FuncStart | Definition::BlockStart + if scope == Scope::Block => + { + break; + }, Definition::FuncStart => nesting -= 1, _ => {}, } diff --git a/src/semantic/naming.rs b/src/semantic/naming.rs new file mode 100644 index 0000000..e1f2c10 --- /dev/null +++ b/src/semantic/naming.rs @@ -0,0 +1,234 @@ +use super::Analyzer; +use crate::{ + Expression, ExpressionKind, Immediate, Statement, StatementKind, err::*, + semantic::Primitive, +}; + +use super::Type; + +impl Analyzer { + pub fn naming_pass_stmt( + &mut self, + mut stmt: Box, + ) -> Result> { + use StatementKind as s; + stmt.kind = match stmt.kind { + s::Declaration { + name, + mut type_str, + type_actual, + mut value, + mutable, + mut uid, + } => { + value = *self.naming_pass_expr(value.into())?; + let type_ = if let Some(ref s) = type_str { + let s = self.table.reference_ident(s); + type_str = Some(s.uid.clone()); + s.type_.is_alias().unwrap_or(Type::Ambiguous) + } else { + value.type_.clone() + }; + println!("{type_:?}"); + let symbol = self.table.define_ident(&name, type_, 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(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.naming_pass_expr(left)?; + right = self.naming_pass_expr(right)?; + e::Binary { op, left, right } + }, + e::Unary { op, mut child } => { + child = self.naming_pass_expr(child)?; + e::Unary { op, child } + }, + e::Parenthesis(mut expression) => { + expression = self.naming_pass_expr(expression)?; + e::Parenthesis(expression) + }, + e::FunctionDef { + params, + returns_str, + returns_actual, + mut body, + mut id, + } => { + // Starts function + id = self + .table + .create_function(params.clone(), returns_str.clone()) + .span(&expr.span)?; + expr.type_ = Type::Function(id.clone()); + for s in &mut body { + *s = *self.naming_pass_stmt(s.clone().into())?; + } + self.table.end_function(); + e::FunctionDef { + params, + returns_str, + returns_actual, + body, + id, + } + }, + e::FunctionCall { + mut callee, + mut args, + is_reference, + id, + } => { + callee = self.naming_pass_expr(callee)?; + for a in &mut args { + *a = *self.naming_pass_expr(a.clone().into())?; + } + e::FunctionCall { + callee, + args, + is_reference, + id, + } + }, + 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, + mut id, + } => { + id = self.table.reference_ident(&name).uid; + for (_, a) in &mut args { + *a = *self.naming_pass_expr(a.clone().into())?; + } + e::StructLiteral { name, args, id } + }, + e::Field { + mut namespace, + field, + uid, + } => { + namespace = self.naming_pass_expr(namespace)?; + e::Field { + namespace, + field, + uid, + } + }, + }; + Ok(expr) + } +} diff --git a/src/semantic/primitives.rs b/src/semantic/primitives.rs index acf9f1f..5fa8c45 100644 --- a/src/semantic/primitives.rs +++ b/src/semantic/primitives.rs @@ -129,16 +129,22 @@ macro_rules! comparison { } impl Primitive { - pub fn coerce(&mut self, into: Primitive) { + pub fn coerce(self, expect: Primitive) -> Result { use Primitive::*; - *self = match (*self, into) { + match (self, expect) { ( integer_ambiguous, - i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole, - ) => into, - (real_ambiguous, r32 | r64 | real) => into, - _ => *self, - }; + a @ (i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole), + ) + | ( + a @ (i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole), + integer_ambiguous, + ) => Ok(a), + (real_ambiguous, a @ (r32 | r64 | real)) + | (a @ (r32 | r64 | real), real_ambiguous) => Ok(a), + (t1, t2) if t1 == t2 => Ok(t1), + _ => error().reason(format!("Cannot coerce '{self}' into '{expect}'")), + } } pub fn is_ambiguous(&self) -> bool { @@ -163,9 +169,9 @@ impl Primitive { ) -> Result { use Primitive::*; if lhs.is_ambiguous() && !rhs.is_ambiguous() { - lhs.coerce(rhs); + lhs = lhs.coerce(rhs)?; } else if rhs.is_ambiguous() && !lhs.is_ambiguous() { - rhs.coerce(lhs); + rhs = rhs.coerce(lhs)?; } selfsame_basic! { lhs, op, rhs; w8, w16, w32, w64, i8, i16, i32, i64, diff --git a/src/semantic/top_down.rs b/src/semantic/top_down.rs index 4c94d6f..001697d 100644 --- a/src/semantic/top_down.rs +++ b/src/semantic/top_down.rs @@ -1,24 +1,227 @@ use super::{Analyzer, Type}; use crate::{ - Expression, ExpressionKind, Immediate, Statement, StatementKind, - err::*, - semantic::{Primitive, SymbolTable}, + Expression, ExpressionKind, Statement, StatementKind, err::*, + semantic::Primitive, }; impl Analyzer { - pub fn stmt_top_down( + pub fn top_down_stmt( &mut self, mut stmt: Box, - expect: &Type, ) -> Result> { - todo!() + use StatementKind as s; + stmt.kind = match stmt.kind { + s::Declaration { + name, + type_str, + type_actual, + mut value, + mutable, + uid, + } => { + value = *self.top_down_expr(value.into(), &type_actual)?; + s::Declaration { + name, + type_str, + type_actual, + value, + mutable, + uid, + } + }, + s::Assignment { + name, + mut value, + uid, + } => { + let type_ = self.table.resolve_type(&uid).span(&stmt.span)?; + value = *self.top_down_expr(value.into(), &type_)?; + s::Assignment { name, value, uid } + }, + s::If { + mut predicate, + mut block, + mut else_, + } => { + predicate = *self + .top_down_expr(predicate.into(), &Type::Prim(Primitive::boolean))?; + for s in &mut block { + *s = *self.top_down_stmt(s.clone().into())?; + } + else_ = if let Some(else_) = else_ { + Some(self.top_down_stmt(else_)?) + } else { + None + }; + s::If { + predicate, + block, + else_, + } + }, + s::While { + mut predicate, + mut block, + } => { + predicate = *self + .top_down_expr(predicate.into(), &Type::Prim(Primitive::boolean))?; + for s in &mut block { + *s = *self.top_down_stmt(s.clone().into())?; + } + s::While { predicate, block } + }, + s::Print(mut expr) => { + let expr_t = expr.type_.clone(); + expr = *self.top_down_expr(expr.into(), &expr_t)?; + s::Print(expr) + }, + s::Expression(mut expr) => { + let expr_t = expr.type_.clone(); + expr = *self.top_down_expr(expr.into(), &expr_t)?; + s::Expression(expr) + }, + s::Block(mut block) => { + for s in &mut block { + *s = *self.top_down_stmt(s.clone().into())?; + } + s::Block(block) + }, + s::Return(expr) => { + if let Some(mut expr) = expr { + let expr_t = expr.type_.clone(); + expr = *self.top_down_expr(expr.into(), &expr_t)?; + s::Return(Some(expr)) + } else { + s::Return(None) + } + }, + s::Error(diagnostic) => s::Error(diagnostic), + }; + Ok(stmt) } - pub fn expr_top_down( + pub fn top_down_expr( &mut self, mut expr: Box, expect: &Type, ) -> Result> { - todo!() + use ExpressionKind as e; + expr.type_ = expr.type_.coerce(expect).span(&expr.span)?; + expr.kind = match expr.kind { + e::Immediate(i) => e::Immediate(i), + e::Identifier(i, m) => e::Identifier(i, m), + e::Binary { + op, + mut left, + mut right, + } => { + left = self.top_down_expr(left, expect)?; + right = self.top_down_expr(right, expect)?; + e::Binary { op, left, right } + }, + e::Unary { op, mut child } => { + child = self.top_down_expr(child, expect)?; + e::Unary { op, child } + }, + e::Parenthesis(mut expression) => { + expression = self.top_down_expr(expression, expect)?; + e::Parenthesis(expression) + }, + e::FunctionDef { + params, + returns_str, + returns_actual, + mut body, + id, + } => { + for s in &mut body { + *s = *self.top_down_stmt(s.clone().into())?; + } + e::FunctionDef { + params, + returns_str, + returns_actual, + body, + id, + } + }, + e::FunctionCall { + callee, + mut args, + is_reference, + id, + } => { + let func_def = if let Type::Function(fid) = callee.type_ { + self.table.functions[fid].clone() + } else { + unreachable!() + }; + if func_def.params.len() != args.len() { + return error() + .reason(format!( + "Wrong number of arguments; found {}, expected {}", + args.len(), + func_def.params.len() + )) + .span(&expr.span); + } + for (param, arg) in func_def.params.iter().zip(args.iter_mut()) { + let type_ = self.table.resolve_type(param).span(&arg.span)?; + *arg = *self.top_down_expr(arg.clone().into(), &type_)?; + } + e::FunctionCall { + callee, + args, + is_reference, + id, + } + }, + e::StructDef(params, sid) => e::StructDef(params, sid), + e::StructLiteral { name, mut args, id } => { + let sid = if let Type::Struct(sid) = expr.type_ { + sid + } else { + return error() + .reason(format!("Cannot create struct from type {}", expr.type_)) + .span(&expr.span); + }; + if self.table.structs[sid].0.len() != args.len() { + return error() + .reason(format!( + "Wrong number of parameters; found {}, expected {}", + args.len(), + self.table.structs[sid].0.len() + )) + .span(&expr.span); + } + let mut declared_params: Vec = vec![]; + for (name, arg) in args.iter_mut() { + if declared_params.contains(name) { + return error() + .reason(format!("Field {name} initialized more than once")) + .span(&arg.span); + } + declared_params.push(name.clone()); + let param_t = self + .table + .get_field(sid, &name) + .span(&arg.span)? + .is_alias() + .span(&arg.span)?; + *arg = *self.top_down_expr(arg.clone().into(), ¶m_t)?; + } + e::StructLiteral { name, args, id } + }, + e::Field { + namespace, + field, + uid, + } => e::Field { + namespace, + field, + uid, + }, + }; + Ok(expr) } } diff --git a/src/semantic/types.rs b/src/semantic/types.rs index 1d6cfd0..bc4ee12 100644 --- a/src/semantic/types.rs +++ b/src/semantic/types.rs @@ -1,6 +1,6 @@ use crate::{BinaryOp, UnaryOp}; -use super::{Symbol, UID, primitives::*}; +use super::{UID, primitives::*}; use crate::err::*; /// Struct ID @@ -14,7 +14,7 @@ pub type FID = usize; #[derive(Debug, Clone)] pub struct FunctionDef { pub params: Vec, - pub returns: Option, + pub returns: UID, } pub fn nothing_mangle() -> UID { @@ -60,6 +60,14 @@ impl PartialEq for Type { } impl Type { + pub fn is_alias(&self) -> Result { + if let Type::Alias(t) = self { + Ok(*t.clone()) + } else { + error().reason(format!("Expected type, found value with type {}", self)) + } + } + pub fn binary_op(lhs: &Type, op: BinaryOp, rhs: &Type) -> Result { use Type as t; let e = error().reason(format!( @@ -86,17 +94,42 @@ impl Type { pub fn deduce(self, hint: &Type) -> Result { use Type::*; - match (hint, self) { - (Ambiguous, t) => Ok(t), - (t, Ambiguous) => Ok(t.clone()), + match (self, hint) { + (Ambiguous, t) => Ok(t.clone()), + (t, Ambiguous) => Ok(t), (Prim(mut p1), Prim(p2)) => { - p1.coerce(p2); + p1 = p1.coerce(*p2)?; Ok(Prim(p1)) }, - (t1, t2) if t1 == &t2 => Ok(t1.clone()), + (t1, t2) if &t1 == t2 => Ok(t1.clone()), (t1, t2) => { error().reason(format!("Cannot coerce type '{t2}' into '{t1}'")) }, } } + + pub fn coerce(self, expect: &Type) -> Result { + use Type::*; + match (self, expect) { + (Prim(mut p1), Prim(p2)) => { + p1 = p1.coerce(*p2)?; + Ok(Prim(p1)) + }, + (t1, t2) if &t1 == t2 => Ok(t1.clone()), + (t1, t2) => { + error().reason(format!("Cannot coerce type '{t2}' into '{t1}'")) + }, + } + } + + pub fn promote(self) -> Self { + use Type::*; + match self { + Prim(mut p) => { + p.promote(); + Prim(p) + }, + t => t, + } + } } diff --git a/src/token.rs b/src/token.rs index d0e394b..9ff9085 100644 --- a/src/token.rs +++ b/src/token.rs @@ -9,6 +9,7 @@ pub enum Base { Hex = 16, } +#[allow(dead_code)] #[derive(Debug, Clone)] pub enum TokenKind { LeftParen, @@ -382,20 +383,19 @@ impl> Tokenizer { buffer.push(c); let _ = self.next_char(); } + buffer = buffer.to_lowercase(); // Determine base let base = if buffer.starts_with("0b") { Base::Binary - } else if buffer.starts_with("0o") || buffer.starts_with("0O") { + } else if buffer.starts_with("0o") { Base::Octal - } else if buffer.starts_with("0x") || buffer.starts_with("0X") { + } else if buffer.starts_with("0x") { Base::Hex } else { Base::Decimal }; // Determine integer or float - if base == Base::Decimal - && (encountered_dot || buffer.contains("e") || buffer.contains("E")) - { + if base == Base::Decimal && (encountered_dot || buffer.contains("e")) { return t(FloatLiteral(buffer), position); } else { return t(IntegerLiteral(buffer, base), position);