diff --git a/demo.hal b/demo.hal index e31e383..f685080 100644 --- a/demo.hal +++ b/demo.hal @@ -1,3 +1,4 @@ +/* S :: struct { a: integer, b: glyph, @@ -9,5 +10,9 @@ s := foo(S{a: 1, b: 'a', c: 1.0}, 2); foo :: (s: S, a: integer) -> S { return s; } +*/ + +S :: struct { a, b, c: real } + diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..c8c7a0c --- /dev/null +++ b/readme.md @@ -0,0 +1,37 @@ +# Halcyon Compiler +The Halcyon language is a strongly typed compiled language for the +[WebAssembly](https://webassembly.org/) virtual machine. Its major features +are implicit types, move semantics, and memory safety. + +## Semantics +The syntax of Halcyon is designed to be minimal and readable. While Halcyon is +strongly typed, types can be assumed from context at compile time. Below is an +annotated "FizzBuzz" program +``` +fizzbuzz :: (number) { + sum := 0; + if number == 0 { + println("Input cannot be zero"); + break sum; // Early return + } + for i : 0..number { + if (i % 3 == 0) and (i % 5 == 0) { + println("fizzbuzz"); + sum += 1; + } + else if i % 3 == 0 { + println("fizz"); + } + else if i % 5 == 0 { + println("buzz"); + } + } + sum // return the number of fizzbuzz's +} + +fizzbuzz(15); +``` + +## In Depth +I have written a more comprehensive (but outdated) language specification +on my blog [here](https://lgatlin.dev/writings/2-language-ideas.html). diff --git a/src/ir/generate.rs b/src/ir/generate.rs index a1e79e3..1229933 100644 --- a/src/ir/generate.rs +++ b/src/ir/generate.rs @@ -1,3 +1,4 @@ +/* use crate::{Expression, ExpressionKind, Statement, StatementKind}; use super::*; @@ -247,3 +248,4 @@ impl Compiler { } } } +*/ diff --git a/src/ir/mod.rs b/src/ir/mod.rs index d9a11ed..9effe5b 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -1,3 +1,4 @@ +/* mod generate; mod wasm; @@ -194,3 +195,4 @@ impl Compiler { self.ir = result; } } +*/ diff --git a/src/ir/wasm.rs b/src/ir/wasm.rs index fb1d2c5..75aa94a 100644 --- a/src/ir/wasm.rs +++ b/src/ir/wasm.rs @@ -1,3 +1,4 @@ +/* use crate::{ Base, BinaryOp, Immediate, err::*, @@ -209,3 +210,4 @@ impl Compiler { }) } } +*/ diff --git a/src/main.rs b/src/main.rs index c711110..a02a468 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,13 +3,11 @@ mod ir; mod lookahead; mod parse; mod semantic; -mod semantic2; mod token; mod treewalk; use std::ops::Add; use err::*; -use ir::Compiler; use lookahead::*; use parse::*; use semantic::Analyzer; @@ -64,29 +62,6 @@ fn test_expression(expr: &str) { println!("{:?}", parser.expression(0).unwrap()); } -fn prints(st: &Statement) { - use StatementKind as s; - println!("{st:?}"); - match &st.kind { - s::Declaration { - value: - Expression { - kind: ExpressionKind::FunctionDef { body: block, .. }, - .. - }, - .. - } - | s::If { block, .. } - | s::While { block, .. } - | s::Block(block) => { - for s in block { - prints(s); - } - }, - _ => {}, - }; -} - fn tokenize(input: &'static str) -> impl Iterator { Tokenizer::new(input.chars()).filter(|t| t.0.is_meaningful()) } @@ -95,25 +70,23 @@ fn parse(input: &'static str) -> impl Iterator { Parser::new(tokenize(input)) } -fn typecheck(input: &'static str) -> Vec { - Analyzer::new().typecheck(parse(input).collect()) -} - -fn compile(input: &'static str) { - let mut a = Analyzer::new(); - let s = a.typecheck(parse(input).collect()); - let mut c = Compiler::new(a.table); - c.compile(s); +fn typecheck(input: &'static str) { + let parsed: Vec<_> = parse(input).collect(); + let mut s = semantic::Analyzer::new(); + s.block(parsed); } fn main() -> Result<()> { + for p in parse(include_str!("../demo.hal")) { + println!("------------------"); + println!("{p:#?}"); + } /* for s in typecheck(include_str!("../demo.hal")) { println!("------------------"); println!("{s:#?}"); } */ - compile(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 210795a..ebfe56a 100644 --- a/src/parse/expression.rs +++ b/src/parse/expression.rs @@ -2,16 +2,22 @@ use crate::{Base, semantic::*}; use super::*; -#[derive(Clone)] -pub struct Parameter { - pub name: String, - pub type_str: String, - pub type_actual: Type, +#[derive(Clone, Debug)] +pub struct Parameters { + pub arity: usize, + pub names: Vec, + pub type_names: Vec, + pub types: Vec, } -impl std::fmt::Debug for Parameter { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {:?}", self.name, self.type_actual) +impl Default for Parameters { + fn default() -> Self { + Self { + arity: 0, + names: vec![], + type_names: vec![], + types: vec![], + } } } @@ -39,7 +45,10 @@ impl std::fmt::Display for Immediate { #[derive(Clone, Debug)] pub enum ExpressionKind { Immediate(Immediate), - Identifier(String, UID), + Identifier { + name: String, + uid: UID, + }, Binary { op: BinaryOp, left: Box, @@ -51,29 +60,34 @@ pub enum ExpressionKind { }, Parenthesis(Box), FunctionDef { - params: Vec, + params: Parameters, returns_str: Option, returns_actual: Type, body: Vec, - id: UID, + uid: UID, }, FunctionCall { callee: Box, args: Vec, - is_reference: bool, - id: UID, + uid: UID, }, - StructDef(Vec, usize), + StructDef(Parameters, UID), StructLiteral { name: String, args: Vec<(String, Expression)>, - id: UID, + uid: UID, }, Field { namespace: Box, field: Box, uid: UID, }, + Block(Vec), + If { + predicate: Box, + block: Vec, + else_: Option>, + }, } #[derive(Clone, Debug)] @@ -105,7 +119,7 @@ impl std::fmt::Display for ExpressionKind { e::Unary { op: token, child } => { write!(f, "({token} {child})") }, - e::Identifier(i, _) => write!(f, "{i}"), + e::Identifier { name, .. } => write!(f, "{name}"), e::FunctionCall { callee, args, .. } => { write!(f, "({callee} call {args:?})") }, @@ -123,6 +137,28 @@ impl std::fmt::Display for ExpressionKind { }, e::StructDef(params, _) => write!(f, "struct {{ {params:?} }}"), e::StructLiteral { name, args, .. } => write!(f, "{name} {{ {args:?} }}"), + e::Block(block) => { + write!(f, "{{\n")?; + for s in block { + write!(f, "{:#?}", s)?; + } + write!(f, "}}") + }, + e::If { + predicate, + block, + else_, + } => { + write!(f, "{{\n")?; + for s in block { + write!(f, "{:#?}", s)?; + } + write!(f, "}}")?; + if let Some(else_) = else_ { + write!(f, "{else_}")?; + } + Ok(()) + }, } } } @@ -161,7 +197,7 @@ impl> Parser { Type::Ambiguous, ) } - // Terminal or paren + // Primary else { self.primary().reason("Expected expression")? }; @@ -236,8 +272,7 @@ impl> Parser { e::FunctionCall { callee: current.into(), args, - is_reference: false, - id: "".into(), + uid: "".into(), }, span + span2, Type::Ambiguous, @@ -270,6 +305,73 @@ impl> Parser { Ok(current) } + pub fn parameters(&mut self, mut span: Span) -> Result { + use TokenKind as t; + let mut arity = 0; + let mut names = vec![]; + let mut type_names = vec![]; + let mut types = vec![]; + let mut strongly_typed = false; + loop { + // Param name + let (name, span2) = match self.identifier() { + Ok((ident, span)) => (ident, span), + Err(_) => break, + }; + println!("{name}"); + span = span + span2; + names.push(name.clone()); + // Param type (optional) + if self.eat(t::Colon).is_ok() { + let (type_name, span2) = self.identifier().trace_span( + span + span2, + format!("While parsing type of '{}'", name), + )?; + strongly_typed = true; + span = span + span2; + type_names.push(type_name); + } else { + type_names.push("".into()); + } + types.push("".into()); + arity += 1; + // Comma + if !self.eat(t::Comma).is_ok() { + if self.look(0, t::Identifier("".into())).is_ok() { + return error().reason("Expected comma (,) here").span(&span); + } + break; + } + } + // Back-propogate type names + if strongly_typed { + let mut last_name = "".to_string(); + for name in type_names.iter_mut().rev() { + if name.is_empty() { + if last_name.is_empty() { + return error() + .reason("Cannot mix typed and untyped parameters") + .span(&span); + } else { + *name = last_name.clone(); + } + } else { + last_name = name.clone(); + } + } + } else { + return error() + .reason("Untyped parameters are not allowed (temporarily)") + .span(&span); + } + Ok(Parameters { + arity, + names, + type_names, + types, + }) + } + fn primary(&mut self) -> Result { use ExpressionKind as e; use Immediate as im; @@ -301,36 +403,21 @@ impl> Parser { self.skip(1); e::Immediate(im::Boolean(false)) }, + t::If => return self.if_else(), + t::LeftBrace => { + let (block, span1) = self.block()?; + span = span + span1; + e::Block(block) + }, // Function definition t::LeftParen if (self.look(1, t::Identifier("".into())).is_ok() - && self.look(2, t::Colon).is_ok()) + && (self.look(2, t::Colon).is_ok() + || self.look(2, t::Comma).is_ok())) || self.look(1, t::RightParen).is_ok() => { self.skip(1); - let mut params = vec![]; - loop { - let (name, span2) = match self.identifier() { - Ok((name, span)) => (name, span), - Err(_) => break, - }; - span = span + span2; - self - .eat(t::Colon) - .trace_span(span, "while parsing function parameter type")?; - let (type_, span2) = self - .identifier() - .trace_span(span, "while parsing function parameter type")?; - span = span + span2; - params.push(Parameter { - name, - type_str: type_, - type_actual: Type::Ambiguous, - }); - if !self.eat(t::Comma).is_ok() { - break; - } - } + let params = self.parameters(span)?; let Token(_, span2) = self .eat(t::RightParen) .span(&span) @@ -355,38 +442,16 @@ impl> Parser { returns_str, returns_actual: Type::Ambiguous, body, - id: "".into(), + uid: "".into(), } }, // Struct definition t::Struct => { self.skip(1); self.eat(t::LeftBrace)?; - let mut params = vec![]; - loop { - let (name, span2) = match self.identifier() { - Ok((name, span)) => (name, span), - Err(_) => break, - }; - span = span + span2; - self - .eat(t::Colon) - .trace_span(span, "while parsing struct parameter type")?; - let (type_, span2) = self - .identifier() - .trace_span(span, "while parsing struct parameter type")?; - span = span + span2; - params.push(Parameter { - name, - type_str: type_, - type_actual: Type::Ambiguous, - }); - if !self.eat(t::Comma).is_ok() { - break; - } - } + let params = self.parameters(span)?; self.eat(t::RightBrace)?; - e::StructDef(params, usize::MAX) + e::StructDef(params, "".into()) }, // Struct literal t::Identifier(name) if self.look(1, t::LeftBrace).is_ok() => { @@ -414,12 +479,15 @@ impl> Parser { e::StructLiteral { name, args, - id: "".into(), + uid: "".into(), } }, t::Identifier(i) => { self.skip(1); - e::Identifier(i, "".into()) + e::Identifier { + name: i, + uid: "".into(), + } }, // Parenthetical t::LeftParen => { @@ -442,6 +510,41 @@ impl> Parser { Ok(Expression::new(kind, span, Type::Ambiguous)) } + fn if_else(&mut self) -> Result { + use TokenKind as t; + if let Ok(Token(_, span)) = self.eat(t::If) { + let predicate = self + .expression(0) + .trace_span(span, "in predicate of 'if' statement")?; + let span = span + predicate.span; + let block = self + .block() + .trace_span(span, "in block of 'if' statement")?; + let (block, span) = (block.0, span + block.1); + let else_ = if self.eat(t::Else).is_ok() { + Some(Box::new(self.if_else()?)) + } else { + None + }; + Ok(Expression { + kind: ExpressionKind::If { + predicate: predicate.into(), + block, + else_, + }, + span, + type_: Type::Ambiguous, + }) + } else { + let (block, span) = self.block()?; + Ok(Expression { + kind: ExpressionKind::Block(block), + span, + type_: Type::Ambiguous, + }) + } + } + fn identifier(&mut self) -> Result<(String, Span)> { use TokenKind as t; match self.peek(0) { diff --git a/src/parse/statement.rs b/src/parse/statement.rs index 1b78c8e..ca92829 100644 --- a/src/parse/statement.rs +++ b/src/parse/statement.rs @@ -1,4 +1,4 @@ -use crate::semantic::{Type, UID}; +use crate::semantic::UID; use super::*; @@ -7,7 +7,7 @@ pub enum StatementKind { Declaration { name: String, type_str: Option, - type_actual: Type, + type_uid: UID, value: Expression, mutable: bool, uid: UID, @@ -17,18 +17,13 @@ pub enum StatementKind { value: Expression, uid: UID, }, - If { - predicate: Expression, - block: Vec, - else_: Option>, - }, While { predicate: Expression, block: Vec, }, Print(Expression), Expression(Expression), - Block(Vec), + Remainder(Expression), Return(Option), Error(Diagnostic), } @@ -83,7 +78,7 @@ impl> Parser { kind: s::Declaration { name, type_str, - type_actual: Type::Ambiguous, + type_uid: "".into(), value, mutable, uid: "".into(), @@ -111,10 +106,6 @@ impl> Parser { }, } }, - // If - (Token(t::If, _), _) => { - return self.if_else(); - }, // While (Token(t::While, span2), _) => { self.skip(1); @@ -149,19 +140,6 @@ impl> Parser { kind: s::Print(expr), } }, - // Block - (Token(t::LeftBrace, span2), _) => { - // Skip check for semicolon - span = span + span2; - let (block, span2) = self - .block() - .trace_span(span, "while parsing block statement")?; - span = span + span2; - return Ok(Statement { - kind: s::Block(block), - span, - }); - }, // Return (Token(t::Return, span2), _) => { span = span + span2; @@ -182,9 +160,26 @@ impl> Parser { .expression(0) .trace_span(span, "while parsing expression statement")?; span = span + expr.span; - Statement { - span, - kind: s::Expression(expr), + if self.look(0, t::RightBrace).is_ok() { + return Ok(Statement { + span, + kind: s::Remainder(expr), + }); + } else { + use ExpressionKind as e; + // Optional semicolon for some expressions + match expr.kind { + e::Block(..) | e::If { .. } => { + return Ok(Statement { + span, + kind: s::Expression(expr), + }); + }, + _ => Statement { + span, + kind: s::Expression(expr), + }, + } } }, }; @@ -195,37 +190,4 @@ impl> Parser { error().reason("Expected ;").span(&span) } } - - fn if_else(&mut self) -> Result { - use TokenKind as t; - if let Ok(Token(_, span)) = self.eat(t::If) { - let predicate = self - .expression(0) - .trace_span(span, "in predicate of 'if' statement")?; - let span = span + predicate.span; - let block = self - .block() - .trace_span(span, "in block of 'if' statement")?; - let (block, span) = (block.0, span + block.1); - let else_ = if self.eat(t::Else).is_ok() { - Some(Box::new(self.if_else()?)) - } else { - None - }; - Ok(Statement { - kind: StatementKind::If { - predicate, - block, - else_, - }, - span, - }) - } else { - let (block, span) = self.block()?; - Ok(Statement { - kind: StatementKind::Block(block), - span, - }) - } - } } diff --git a/src/semantic/analyzer.rs b/src/semantic/analyzer.rs index beb7fa4..94a4b95 100644 --- a/src/semantic/analyzer.rs +++ b/src/semantic/analyzer.rs @@ -1,7 +1,9 @@ -use crate::{Statement, semantic::SymbolTable}; +use crate::{Expression, ExpressionKind, Statement, StatementKind}; + +use super::*; pub struct Analyzer { - pub table: SymbolTable, + table: SymbolTable, } impl Analyzer { @@ -11,25 +13,79 @@ impl Analyzer { } } - pub fn typecheck( - &mut self, - mut statements: Vec, - ) -> Vec { - for s in &mut statements { - *s = *self.naming_pass_stmt(s.clone().into()).unwrap(); + pub fn typecheck() { + todo!() + } + + /// Analyzing a block: + /// 1. Name structs + /// 2. Type structs + /// 3. Name and type functions + /// 4. Name variables (recurse on blocks) (track moves) + /// 5. Type variables + /// 6. Type assert variables + pub fn block(&mut self, mut block: Vec) -> Result> { + // 1. Name structs + for s in &mut block { + if let StatementKind::Declaration { + name, + value: + Expression { + kind: ExpressionKind::StructDef(params, _), + type_, + .. + }, + .. + } = &mut s.kind + { + *type_ = Type::Nothing; + self.table.declare_struct(name, s.span)?; + } } - for s in &mut statements { - *s = *self.bottom_up_stmt(s.clone().into()).unwrap(); + // 2. Type structs + for s in &mut block { + if let StatementKind::Declaration { + name, + value: + Expression { + kind: ExpressionKind::StructDef(params, _), + .. + }, + .. + } = &mut s.kind + { + self.table.declare_struct(name, s.span)?; + } } - for s in &mut statements { - *s = *self.top_down_stmt(s.clone().into()).unwrap(); + // 3. Name and type functions + for s in &mut block { + if let StatementKind::Declaration { + name, + value: + Expression { + kind: + ExpressionKind::FunctionDef { + params, + returns_str, + returns_actual, + body, + uid, + }, + type_, + span, + }, + .. + } = &mut s.kind + { + let uid = self.table.define_function( + name, + params.clone(), + returns_str.as_ref().map(|s| s.as_str()), + *span, + )?; + *type_ = Type::Function(uid); + } } - println!("-----TABLE------"); - println!("{:#?}", self.table.table); - println!("-----FUNCS------"); - println!("{:#?}", self.table.functions); - println!("-----STRUCTS----"); - println!("{:#?}", self.table.structs); - statements + Ok(block) } } diff --git a/src/semantic/bottom_up.rs b/src/semantic/bottom_up.rs deleted file mode 100644 index 10f1d3f..0000000 --- a/src/semantic/bottom_up.rs +++ /dev/null @@ -1,297 +0,0 @@ -use super::Analyzer; -use crate::{Expression, ExpressionKind, Statement, StatementKind, err::*}; - -use super::Type; - -impl Analyzer { - pub fn bottom_up_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, - 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, - self.table.in_global_scope(), - )?; - 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, - false, - )?; - 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 bottom_up_expr( - &mut self, - mut expr: Box, - ) -> Result> { - 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.get(&id).unwrap().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.name = uid.clone(); - 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)? - .is_alias() - .span(&expr.span)?; - e::FunctionDef { - params, - returns_str, - returns_actual, - body, - id, - } - }, - e::FunctionCall { - mut callee, - mut args, - is_reference, - mut id, - } => { - callee = self.bottom_up_expr(callee)?; - match callee.type_ { - Type::Function(ref uid) => { - id = uid.clone(); - expr.type_ = self - .table - .resolve_type(&self.table.functions.get(uid).unwrap().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, - mut uid, - } => { - namespace = self.bottom_up_expr(namespace)?; - let field_name = 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)?; - name.clone() - } 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); - }; - // Name mangling - if let e::Identifier(_, mangle) = &namespace.kind { - uid = mangle.clone() + "$" + &field_name; - } else if uid != "" { - uid = uid + "$" + &field_name; - } - e::Field { - namespace, - field, - uid, - } - }, - }; - Ok(expr) - } -} diff --git a/src/semantic/mod.rs b/src/semantic/mod.rs index 4cfb649..54c9955 100644 --- a/src/semantic/mod.rs +++ b/src/semantic/mod.rs @@ -1,369 +1,357 @@ -mod analyzer; -mod bottom_up; -mod naming; -mod primitives; -mod sizing; -mod top_down; -mod types; +pub mod analyzer; +pub mod primitives; + +pub use analyzer::*; +pub use primitives::*; use std::collections::HashMap; -use crate::{Parameter, err::*}; -pub use analyzer::*; -pub use primitives::*; -pub use types::*; +use crate::{Parameters, Span, err::*, semantic::Primitive}; -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -enum Scope { - Block, - Function, +pub type UID = String; + +#[derive(Debug, Clone)] +pub enum Type { + Ambiguous, + Prim(Primitive), + Nothing, + Struct(UID), + Function(UID), } -// Mangled name -pub type UID = String; +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::Prim(primitive) => write!(f, "{primitive}"), + Type::Nothing => write!(f, "nothing"), + Type::Struct(s) => write!(f, "struct {s}"), + Type::Function(func) => write!(f, "func {func}"), + } + } +} + +#[derive(Debug, Clone)] +pub enum SymbolKind { + Variable { + type_: UID, + mutable: bool, + global: bool, + children: Vec, + }, + Function { + params: Parameters, + returns: UID, + }, + Struct { + params: Parameters, + size: usize, + align: usize, + }, + TypeDef { + actual: Type, + }, +} #[derive(Debug, Clone)] pub struct Symbol { pub name: String, - pub type_: Type, pub uid: UID, - initialized: bool, - pub mutable: Option, - pub global: bool, + pub span: Option, + pub kind: SymbolKind, +} + +impl Symbol { + pub fn is_variable(&self) -> Result<()> { + let name = &self.name; + match &self.kind { + SymbolKind::Variable { .. } => Ok(()), + SymbolKind::Function { .. } => { + error().reason(format!("'{name}' refers to a function, not a value")) + }, + _ => error().reason(format!("'{name}' refers to a type, not a value")), + } + } + + pub fn is_type(&self) -> Result { + let name = &self.name; + match &self.kind { + SymbolKind::Struct { .. } => Ok(Type::Struct(self.uid.clone())), + SymbolKind::TypeDef { actual } => Ok(actual.clone()), + _ => error().reason(format!("'{name}' refers to a value, not a type")), + } + } } #[derive(Debug, Clone)] -enum Definition { - Ident(Symbol), - FuncStart, - BlockStart, +pub enum Event { + Declared { name: String, uid: UID }, + Moved { name: String, uid: UID, span: Span }, + Func { returns: Vec, uid: UID }, + Block { returns: UID }, } -#[derive(Debug, Clone)] pub struct SymbolTable { - pub structs: Vec, - pub functions: HashMap, - scope: Vec, - pub table: HashMap, - mangle_num: usize, + syms: HashMap, + scope: Vec, nesting: usize, + mangle_num: 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), - global: true, - }; - let mut functions = HashMap::new(); - functions.insert("$$main".into(), FunctionDef { - params: vec![], - returns: "Nothing".into(), - }); - scope.push(Definition::Ident(nothing_symbol.clone())); - table.insert(nothing_symbol.uid.clone(), nothing_symbol); Self { - structs: vec![], - functions, - scope, - table, - mangle_num: 0, + syms: HashMap::new(), + scope: vec![], nesting: 0, + mangle_num: 0, } } - pub fn start_block(&mut self) { - self.scope.push(Definition::BlockStart); - } - - pub fn end_block(&mut self) { - let mut escaped = vec![]; - while !self.scope.is_empty() { - 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 in_global_scope(&self) -> bool { - for def in &self.scope { - if let Definition::Ident(..) = def { - continue; - } else { - return false; - } - } - true - } - - 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 get_field_no(&self, sid: SID, argname: &str) -> usize { - let struct_def = &self.structs[sid].0; - for (id, (name, _)) in struct_def.iter().enumerate() { - if name == argname { - return id; - } - } - unreachable!() - } - - 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() { - 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") - } - fn generate_uid(&mut self, name: &str) -> UID { let uid = format!("${}${name}", self.mangle_num); self.mangle_num += 1; 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); + pub fn get(&self, uid: &UID) -> &Symbol { + self.syms.get(uid).unwrap() + } + + pub fn get_mut(&mut self, uid: &UID) -> &mut Symbol { + self.syms.get_mut(uid).unwrap() + } + + // Find the definition of a symbol in local and global scope + pub fn find(&self, name: &str) -> Result<&Symbol> { + let mut nesting = self.nesting; + for e in self.scope.iter().rev() { + match e { + Event::Declared { uid, .. } + if nesting == self.nesting || nesting == 0 => + { + return Ok(self.get(uid)); + }, + Event::Moved { name, span, .. } + if nesting == self.nesting || nesting == 0 => + { + return error() + .reason(format!("Symbol '{name}' moved out of scope here")) + .span(&span); + }, + Event::Func { .. } => { + nesting -= 1; + }, + _ => {}, } } - error().reason(format!("Cannot find field '{field_name}'")) + error().reason(format!("Cannot find symbol '{name}'")) } - 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)); + // Get all nested members of a struct variable + fn get_all_children(&self, uid: &UID) -> Vec { + use SymbolKind as s; + match &self.get(uid).kind { + s::Variable { children, .. } => { + let mut new_children = children.clone(); + for uid in children { + new_children.append(&mut self.get_all_children(uid)) + } + new_children + }, + _ => { + vec![] + }, } - self.structs.push(StructureDef(new_params)); - sid } - pub fn create_function( - &mut self, - params: Vec, - returns: Option, - ) -> Result { - let uid = self.generate_uid("func"); - 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 { - self.reference_ident(&s).uid + // Move a symbol out of scope + pub fn move_symbol(&mut self, move_uid: &UID, span: Span) -> Result<()> { + if let SymbolKind::Variable { global, .. } = self.get(move_uid).kind { + if global { + return error().reason("Cannot move global symbol").span(&span); + } } else { - 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_.is_alias()?, false) - .trace("While initializing function parameters")?; - new_params.push(s.uid); + panic!("Moved non-variable {move_uid}"); } - self.functions.insert(uid.clone(), FunctionDef { - params: new_params, - returns, + let children = self.get_all_children(move_uid); + for e in self.scope.iter().rev() { + match e { + Event::Declared { uid, .. } => { + if move_uid == uid { + break; + } + }, + Event::Moved { uid, span, .. } => { + if children.contains(uid) { + return error() + .reason("Symbol was partially moved here") + .span(&span); + } else if move_uid == uid { + return error() + .reason("Symbol was previously moved here") + .span(&span); + } + }, + _ => {}, + } + } + self.scope.push(Event::Moved { + name: self.get(move_uid).name.clone(), + uid: move_uid.clone(), + span, + }); + Ok(()) + } + + fn in_global_scope(&self) -> bool { + for e in self.scope.iter().rev() { + if let Event::Func { .. } = e { + return false; + } + } + true + } + + pub fn define_var( + &mut self, + name: &str, + mutable: bool, + type_: &UID, + span: Span, + ) -> UID { + let uid = self.generate_uid(name); + self.syms.insert(uid.clone(), Symbol { + name: name.to_string(), + span: Some(span), + uid: uid.clone(), + kind: SymbolKind::Variable { + type_: type_.clone(), + mutable, + global: self.in_global_scope(), + children: vec![], + }, + }); + self.scope.push(Event::Declared { + name: name.to_string(), + uid: uid.clone(), + }); + uid + } + + pub fn declare_struct( + &mut self, + struct_name: &str, + span: Span, + ) -> Result { + // Check for multiple definition + for e in self.scope.iter().rev() { + match e { + Event::Declared { name, uid } => { + if name == struct_name { + let e = error().reason(format!( + "Structure '{struct_name}' is defined multiple times" + )); + if let Some(s) = &self.get(uid).span { + return e.span(s); + } else { + return e; + } + } + }, + Event::Moved { .. } => {}, + _ => break, + } + } + let uid = self.generate_uid(struct_name); + self.syms.insert(uid.clone(), Symbol { + name: struct_name.to_string(), + uid: uid.clone(), + span: Some(span), + kind: SymbolKind::Struct { + params: Parameters::default(), + size: 0, + align: 0, + }, + }); + self.scope.push(Event::Declared { + name: struct_name.to_string(), + uid: uid.clone(), }); Ok(uid) } - pub fn modify_ident( - &mut self, - uid: UID, - name: Option, - type_: Option, - mutable: Option, - init: bool, - global: bool, - ) -> Result<()> { - let symbol = self.table.get_mut(&uid).unwrap(); - if let Some(ref type_) = type_ { - symbol.type_ = symbol.type_.clone().deduce(type_)?; + fn type_params(&mut self, mut params: Parameters) -> Result { + for i in 0..params.arity { + params.types[i] = self + .find(¶ms.type_names[i]) + .trace(format!( + "while resolving type of field '{}'", + params.type_names[i] + ))? + .uid + .clone(); } - 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; - symbol.global |= global; + Ok(params) + } - let mut nesting = self.nesting; - for def in &mut self.scope { - match def { - Definition::Ident(symbol) - if (symbol.uid == uid) - && (nesting == 0 || nesting == self.nesting) => - { - if let Some(ref name) = name { - symbol.name = name.clone(); + pub fn define_function( + &mut self, + func_name: &str, + params: Parameters, + returns_str: Option<&str>, + span: Span, + ) -> Result { + // Check for multiple definition + for e in self.scope.iter().rev() { + match e { + Event::Declared { name, uid } => { + if name == func_name { + let e = error().reason(format!( + "Function '{func_name}' is defined multiple times" + )); + if let Some(s) = &self.get(uid).span { + return e.span(s); + } else { + return e; + } } - 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; - symbol.global |= global; - return Ok(()); }, - Definition::FuncStart => nesting -= 1, - _ => {}, + Event::Moved { .. } => {}, + _ => break, } } + let uid = self.generate_uid(func_name); + // Check types + let params = self.type_params(params)?; + let returns = { + let sym = self.find(returns_str)?; + sym.is_type()?; + sym.uid.clone() + }; + self.syms.insert(uid.clone(), Symbol { + name: func_name.to_string(), + uid: uid.clone(), + span: Some(span), + kind: SymbolKind::Function { params, returns }, + }); + self.scope.push(Event::Declared { + name: func_name.to_string(), + uid: uid.clone(), + }); + Ok(uid) + } + + pub fn define_struct(&mut self, uid: &UID, params: Parameters) -> Result<()> { + let params = self.type_params(params)?; + if let SymbolKind::Struct { + params: old_params, .. + } = &mut self.get_mut(uid).kind + { + *old_params = params; + } else { + unreachable!("Defined non-existent struct") + } Ok(()) - //unreachable!("Symbol {uid} does not exist") - } - - pub fn define_ident( - &mut self, - name: &str, - type_: Type, - mutable: bool, - ) -> Result { - 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 { - 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, - self.in_global_scope(), - )?; - 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), - global: self.in_global_scope(), - }; - 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_function_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, - global: false, - }; - self.scope.push(Definition::Ident(sym.clone())); - self.table.insert(uid, sym.clone()); - sym - }, - } - } - - pub fn lookup_block_scope(&self, name: &str) -> Result { - self.lookup_scope(name, Scope::Block) - } - - pub fn lookup_function_scope(&self, name: &str) -> Result { - self.lookup_scope(name, Scope::Function) - } - - fn lookup_scope(&self, name: &str, scope: Scope) -> Result { - let mut nesting = self.nesting; - for def in self.scope.iter().rev() { - match def { - Definition::Ident(symbol) - if (symbol.name == name) - && ((nesting == 0) || nesting == self.nesting) => - { - return Ok(symbol.clone()); - }, - Definition::FuncStart | Definition::BlockStart - if scope == Scope::Block => - { - break; - }, - Definition::FuncStart => nesting -= 1, - _ => {}, - } - } - error().reason(format!( - "Cannot find the definition of '{}' in the current scope", - name - )) } } diff --git a/src/semantic/naming.rs b/src/semantic/naming.rs deleted file mode 100644 index 4abd795..0000000 --- a/src/semantic/naming.rs +++ /dev/null @@ -1,234 +0,0 @@ -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() - }; - 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, - 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 19a4ba2..f7cda6a 100644 --- a/src/semantic/primitives.rs +++ b/src/semantic/primitives.rs @@ -40,18 +40,6 @@ 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), - global: true, - },)* - ] - } }; } diff --git a/src/semantic/sizing.rs b/src/semantic/sizing.rs deleted file mode 100644 index 603a8dc..0000000 --- a/src/semantic/sizing.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub enum DataType { - i32, - i64, - f32, - f64, -} diff --git a/src/semantic/top_down.rs b/src/semantic/top_down.rs deleted file mode 100644 index d929792..0000000 --- a/src/semantic/top_down.rs +++ /dev/null @@ -1,231 +0,0 @@ -use super::{Analyzer, Type}; -use crate::{ - Expression, ExpressionKind, Statement, StatementKind, err::*, - semantic::Primitive, -}; - -impl Analyzer { - pub fn top_down_stmt( - &mut self, - mut stmt: Box, - ) -> Result> { - 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(); - println!("{expr_t}"); - 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 top_down_expr( - &mut self, - mut expr: Box, - expect: &Type, - ) -> Result> { - use ExpressionKind as e; - println!("{} -> {expect}", expr.type_); - 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(ref uid) = callee.type_ { - self.table.functions.get(uid).unwrap().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)?; - println!("{param_t}"); - *arg = *self.top_down_expr(arg.clone().into(), ¶m_t)?; - println!("/{param_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 deleted file mode 100644 index 98d2a1d..0000000 --- a/src/semantic/types.rs +++ /dev/null @@ -1,133 +0,0 @@ -use crate::{BinaryOp, UnaryOp}; - -use super::{UID, primitives::*}; -use crate::err::*; - -/// Struct ID -pub type SID = usize; - -#[derive(Debug, Clone)] -pub struct StructureDef(pub Vec<(String, UID)>); - -#[derive(Debug, Clone)] -pub struct FunctionDef { - pub params: Vec, - pub returns: UID, -} - -pub fn nothing_mangle() -> UID { - "$$nothing".into() -} - -#[derive(Debug, Clone)] -pub enum Type { - Ambiguous, - Nothing, - Alias(Box), - Prim(Primitive), - Struct(SID), - Function(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::Alias(t) => write!(f, "type alias ({t})"), - Type::Function(fid) => write!(f, "func {fid:?}"), - } - } -} - -impl PartialEq for Type { - fn eq(&self, other: &Self) -> bool { - use Type::*; - match (self, other) { - (Ambiguous, Ambiguous) => true, - (Prim(p1), Prim(p2)) if p1 == p2 => true, - (Struct(p1), Struct(p2)) => p1 == p2, - (Function(id1), Function(id2)) => id1 == id2, - (Alias(t1), Alias(t2)) => t1 == t2, - (Nothing, Nothing) => true, - _ => false, - } - } -} - -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!( - "Binary {op} is not defined for {lhs:?} and {rhs:?}", - )); - match (lhs, rhs) { - (t::Prim(a), t::Prim(b)) => { - let p = Primitive::binary_op(*a, op, *b)?; - Ok(t::Prim(p)) - }, - _ => e, - } - } - - pub fn unary_op(op: UnaryOp, child: &Type) -> Result { - use Type as t; - if let t::Prim(p) = child { - let p = Primitive::unary_op(op, *p)?; - Ok(t::Prim(p)) - } else { - error().reason(format!("Unary {op} is not defined for {child:?}")) - } - } - - pub fn deduce(self, hint: &Type) -> Result { - use Type::*; - match (self, hint) { - (Ambiguous, t) => Ok(t.clone()), - (t, Ambiguous) => Ok(t), - (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 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/semantic2/analyzer.rs b/src/semantic2/analyzer.rs deleted file mode 100644 index 8289546..0000000 --- a/src/semantic2/analyzer.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::{Expression, ExpressionKind, Statement, StatementKind}; - -use super::*; - -pub struct Analyzer { - table: SymbolTable, -} - -impl Analyzer { - /// Analyzing a block: - /// 1. Name structs - /// 2. Type structs - /// 3. Name functions - /// 4. Name variables (recurse on blocks) (track moves) - /// 5. Type variables - /// 6. Type assert variables - pub fn block(&mut self, mut block: Vec) -> Result> { - // Name structs - for s in &mut block { - if let StatementKind::Declaration { - name, - value: - Expression { - kind: ExpressionKind::StructDef(params, _), - type_, - .. - }, - .. - } = &mut s.kind - { - self.table.declare_struct(name, s.span)?; - } - } - Ok(block) - } -} diff --git a/src/semantic2/mod.rs b/src/semantic2/mod.rs deleted file mode 100644 index db39bf0..0000000 --- a/src/semantic2/mod.rs +++ /dev/null @@ -1,313 +0,0 @@ -mod analyzer; - -use std::collections::HashMap; - -use crate::{Span, err::*, semantic::Primitive}; - -pub type UID = String; - -#[derive(Debug, Clone)] -pub enum Type { - Ambiguous, - Prim(Primitive), - Nothing, - Struct(UID), - Function(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::Prim(primitive) => write!(f, "{primitive}"), - Type::Nothing => write!(f, "nothing"), - Type::Struct(s) => write!(f, "struct {s}"), - Type::Function(func) => write!(f, "func {func}"), - } - } -} - -#[derive(Debug, Clone)] -pub enum SymbolKind { - Variable { - type_: UID, - mutable: bool, - global: bool, - children: Vec, - }, - Function { - arg_names: Vec, - arg_types: Vec, - }, - Struct { - field_names: Vec, - field_types: Vec, - size: usize, - align: usize, - }, - TypeDef { - actual: Type, - }, -} - -#[derive(Debug, Clone)] -pub struct Symbol { - pub name: String, - pub span: Option, - pub kind: SymbolKind, -} - -impl Symbol { - pub fn is_variable(&self) -> Result<()> { - let name = &self.name; - match &self.kind { - SymbolKind::Variable { .. } => Ok(()), - SymbolKind::Function { .. } => { - error().reason(format!("'{name}' refers to a function, not a value")) - }, - _ => error().reason(format!("'{name}' refers to a type, not a value")), - } - } - - pub fn is_type(&self) -> Result { - let name = &self.name; - match &self.kind { - SymbolKind::TypeDef { actual } => Ok(actual.clone()), - _ => error().reason(format!("'{name}' refers to a value, not a type")), - } - } -} - -#[derive(Debug, Clone)] -pub enum Event { - Declared { name: String, uid: UID }, - Moved { name: String, uid: UID, span: Span }, - Func { returns: Vec, uid: UID }, - Block { returns: UID }, -} - -pub struct SymbolTable { - syms: HashMap, - scope: Vec, - nesting: usize, - mangle_num: usize, -} - -impl SymbolTable { - pub fn new() -> Self { - Self { - syms: HashMap::new(), - scope: vec![], - nesting: 0, - mangle_num: 0, - } - } - - fn generate_uid(&mut self, name: &str) -> UID { - let uid = format!("${}${name}", self.mangle_num); - self.mangle_num += 1; - uid - } - - pub fn get(&self, uid: &UID) -> &Symbol { - self.syms.get(uid).unwrap() - } - - pub fn get_mut(&mut self, uid: &UID) -> &mut Symbol { - self.syms.get_mut(uid).unwrap() - } - - // Find the definition of a symbol in local and global scope - pub fn find(&self, name: &str) -> Result<&Symbol> { - let mut nesting = self.nesting; - for e in self.scope.iter().rev() { - match e { - Event::Declared { uid, .. } - if nesting == self.nesting || nesting == 0 => - { - return Ok(self.get(uid)); - }, - Event::Moved { name, span, .. } - if nesting == self.nesting || nesting == 0 => - { - return error() - .reason(format!("Symbol '{name}' moved out of scope here")) - .span(&span); - }, - Event::Func { .. } => { - nesting -= 1; - }, - _ => {}, - } - } - error().reason(format!("Cannot find symbol '{name}'")) - } - - // Get all nested members of a struct variable - fn get_all_children(&self, uid: &UID) -> Vec { - use SymbolKind as s; - match &self.get(uid).kind { - s::Variable { children, .. } => { - let mut new_children = children.clone(); - for uid in children { - new_children.append(&mut self.get_all_children(uid)) - } - new_children - }, - _ => { - vec![] - }, - } - } - - // Move a symbol out of scope - pub fn move_symbol(&mut self, move_uid: &UID, span: Span) -> Result<()> { - let children = self.get_all_children(move_uid); - for e in self.scope.iter().rev() { - match e { - Event::Declared { uid, .. } => { - if move_uid == uid { - break; - } - }, - Event::Moved { uid, span, .. } => { - if children.contains(uid) { - return error() - .reason("Symbol was partially moved here") - .span(&span); - } else if move_uid == uid { - return error() - .reason("Symbol was previously moved here") - .span(&span); - } - }, - _ => {}, - } - } - self.scope.push(Event::Moved { - name: self.get(move_uid).name.clone(), - uid: move_uid.clone(), - span, - }); - Ok(()) - } - - fn in_global_scope(&self) -> bool { - for e in self.scope.iter().rev() { - if let Event::Func { .. } = e { - return false; - } - } - true - } - - pub fn define_var( - &mut self, - name: &str, - mutable: bool, - type_: &UID, - span: Span, - ) -> UID { - let uid = self.generate_uid(name); - self.syms.insert(uid.clone(), Symbol { - name: name.to_string(), - span: Some(span), - kind: SymbolKind::Variable { - type_: type_.clone(), - mutable, - global: self.in_global_scope(), - children: vec![], - }, - }); - self.scope.push(Event::Declared { - name: name.to_string(), - uid: uid.clone(), - }); - uid - } - - pub fn declare_struct( - &mut self, - struct_name: &str, - span: Span, - ) -> Result { - // Check for multiple definition () - for e in self.scope.iter().rev() { - match e { - Event::Declared { name, uid } => { - if name == struct_name { - let e = error().reason(format!( - "Structure {struct_name} is defined multiple times" - )); - if let Some(s) = &self.get(uid).span { - return e.span(s); - } else { - return e; - } - } - }, - Event::Moved { .. } => {}, - _ => break, - } - } - let uid = self.generate_uid(struct_name); - self.syms.insert(uid.clone(), Symbol { - name: struct_name.to_string(), - span: Some(span), - kind: SymbolKind::Struct { - field_names: vec![], - field_types: vec![], - size: 0, - align: 0, - }, - }); - self.scope.push(Event::Declared { - name: struct_name.to_string(), - uid: uid.clone(), - }); - Ok(uid) - } - - pub fn define_struct( - &mut self, - uid: &UID, - field_names: Vec, - field_types: Vec, - ) { - if let SymbolKind::Struct { - field_names: old_names, - field_types: old_types, - size, - align, - } = &mut self.get_mut(uid).kind - { - *old_names = field_names; - *old_types = field_types; - } else { - unreachable!("Defined non-existent struct") - } - } - - pub fn define_function( - &mut self, - name: &str, - arg_names: Vec, - arg_types: Vec, - span: Span, - ) -> UID { - let uid = self.generate_uid(name); - self.syms.insert(uid.clone(), Symbol { - name: name.to_string(), - span: Some(span), - kind: SymbolKind::Function { - arg_names, - arg_types, - }, - }); - self.scope.push(Event::Declared { - name: name.to_string(), - uid: uid.clone(), - }); - uid - } -}