This commit is contained in:
Logan 2024-11-05 17:14:13 -06:00
parent 38a3a5eab0
commit c1ae2b4e48
18 changed files with 630 additions and 1762 deletions

View file

@ -1,3 +1,4 @@
/*
S :: struct { S :: struct {
a: integer, a: integer,
b: glyph, b: glyph,
@ -9,5 +10,9 @@ s := foo(S{a: 1, b: 'a', c: 1.0}, 2);
foo :: (s: S, a: integer) -> S { foo :: (s: S, a: integer) -> S {
return s; return s;
} }
*/
S :: struct { a, b, c: real }

37
readme.md Normal file
View file

@ -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).

View file

@ -1,3 +1,4 @@
/*
use crate::{Expression, ExpressionKind, Statement, StatementKind}; use crate::{Expression, ExpressionKind, Statement, StatementKind};
use super::*; use super::*;
@ -247,3 +248,4 @@ impl Compiler {
} }
} }
} }
*/

View file

@ -1,3 +1,4 @@
/*
mod generate; mod generate;
mod wasm; mod wasm;
@ -194,3 +195,4 @@ impl Compiler {
self.ir = result; self.ir = result;
} }
} }
*/

View file

@ -1,3 +1,4 @@
/*
use crate::{ use crate::{
Base, BinaryOp, Immediate, Base, BinaryOp, Immediate,
err::*, err::*,
@ -209,3 +210,4 @@ impl Compiler {
}) })
} }
} }
*/

View file

@ -3,13 +3,11 @@ mod ir;
mod lookahead; mod lookahead;
mod parse; mod parse;
mod semantic; mod semantic;
mod semantic2;
mod token; mod token;
mod treewalk; mod treewalk;
use std::ops::Add; use std::ops::Add;
use err::*; use err::*;
use ir::Compiler;
use lookahead::*; use lookahead::*;
use parse::*; use parse::*;
use semantic::Analyzer; use semantic::Analyzer;
@ -64,29 +62,6 @@ fn test_expression(expr: &str) {
println!("{:?}", parser.expression(0).unwrap()); 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<Item = Token> { fn tokenize(input: &'static str) -> impl Iterator<Item = Token> {
Tokenizer::new(input.chars()).filter(|t| t.0.is_meaningful()) Tokenizer::new(input.chars()).filter(|t| t.0.is_meaningful())
} }
@ -95,25 +70,23 @@ fn parse(input: &'static str) -> impl Iterator<Item = Statement> {
Parser::new(tokenize(input)) Parser::new(tokenize(input))
} }
fn typecheck(input: &'static str) -> Vec<Statement> { fn typecheck(input: &'static str) {
Analyzer::new().typecheck(parse(input).collect()) let parsed: Vec<_> = parse(input).collect();
} let mut s = semantic::Analyzer::new();
s.block(parsed);
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 main() -> Result<()> { fn main() -> Result<()> {
for p in parse(include_str!("../demo.hal")) {
println!("------------------");
println!("{p:#?}");
}
/* /*
for s in typecheck(include_str!("../demo.hal")) { for s in typecheck(include_str!("../demo.hal")) {
println!("------------------"); println!("------------------");
println!("{s:#?}"); println!("{s:#?}");
} }
*/ */
compile(include_str!("../demo.hal"));
//let module = frontend::Module::from_file("./demo.hal")?; //let module = frontend::Module::from_file("./demo.hal")?;
//module.write_to("test"); //module.write_to("test");
Ok(()) Ok(())

View file

@ -2,16 +2,22 @@ use crate::{Base, semantic::*};
use super::*; use super::*;
#[derive(Clone)] #[derive(Clone, Debug)]
pub struct Parameter { pub struct Parameters {
pub name: String, pub arity: usize,
pub type_str: String, pub names: Vec<String>,
pub type_actual: Type, pub type_names: Vec<String>,
pub types: Vec<String>,
} }
impl std::fmt::Debug for Parameter { impl Default for Parameters {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn default() -> Self {
write!(f, "{}: {:?}", self.name, self.type_actual) Self {
arity: 0,
names: vec![],
type_names: vec![],
types: vec![],
}
} }
} }
@ -39,7 +45,10 @@ impl std::fmt::Display for Immediate {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum ExpressionKind { pub enum ExpressionKind {
Immediate(Immediate), Immediate(Immediate),
Identifier(String, UID), Identifier {
name: String,
uid: UID,
},
Binary { Binary {
op: BinaryOp, op: BinaryOp,
left: Box<Expression>, left: Box<Expression>,
@ -51,29 +60,34 @@ pub enum ExpressionKind {
}, },
Parenthesis(Box<Expression>), Parenthesis(Box<Expression>),
FunctionDef { FunctionDef {
params: Vec<Parameter>, params: Parameters,
returns_str: Option<String>, returns_str: Option<String>,
returns_actual: Type, returns_actual: Type,
body: Vec<Statement>, body: Vec<Statement>,
id: UID, uid: UID,
}, },
FunctionCall { FunctionCall {
callee: Box<Expression>, callee: Box<Expression>,
args: Vec<Expression>, args: Vec<Expression>,
is_reference: bool, uid: UID,
id: UID,
}, },
StructDef(Vec<Parameter>, usize), StructDef(Parameters, UID),
StructLiteral { StructLiteral {
name: String, name: String,
args: Vec<(String, Expression)>, args: Vec<(String, Expression)>,
id: UID, uid: UID,
}, },
Field { Field {
namespace: Box<Expression>, namespace: Box<Expression>,
field: Box<Expression>, field: Box<Expression>,
uid: UID, uid: UID,
}, },
Block(Vec<Statement>),
If {
predicate: Box<Expression>,
block: Vec<Statement>,
else_: Option<Box<Expression>>,
},
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -105,7 +119,7 @@ impl std::fmt::Display for ExpressionKind {
e::Unary { op: token, child } => { e::Unary { op: token, child } => {
write!(f, "({token} {child})") write!(f, "({token} {child})")
}, },
e::Identifier(i, _) => write!(f, "{i}"), e::Identifier { name, .. } => write!(f, "{name}"),
e::FunctionCall { callee, args, .. } => { e::FunctionCall { callee, args, .. } => {
write!(f, "({callee} call {args:?})") write!(f, "({callee} call {args:?})")
}, },
@ -123,6 +137,28 @@ impl std::fmt::Display for ExpressionKind {
}, },
e::StructDef(params, _) => write!(f, "struct {{ {params:?} }}"), e::StructDef(params, _) => write!(f, "struct {{ {params:?} }}"),
e::StructLiteral { name, args, .. } => write!(f, "{name} {{ {args:?} }}"), 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<I: Iterator<Item = Token>> Parser<I> {
Type::Ambiguous, Type::Ambiguous,
) )
} }
// Terminal or paren // Primary
else { else {
self.primary().reason("Expected expression")? self.primary().reason("Expected expression")?
}; };
@ -236,8 +272,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
e::FunctionCall { e::FunctionCall {
callee: current.into(), callee: current.into(),
args, args,
is_reference: false, uid: "".into(),
id: "".into(),
}, },
span + span2, span + span2,
Type::Ambiguous, Type::Ambiguous,
@ -270,6 +305,73 @@ impl<I: Iterator<Item = Token>> Parser<I> {
Ok(current) Ok(current)
} }
pub fn parameters(&mut self, mut span: Span) -> Result<Parameters> {
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<Expression> { fn primary(&mut self) -> Result<Expression> {
use ExpressionKind as e; use ExpressionKind as e;
use Immediate as im; use Immediate as im;
@ -301,36 +403,21 @@ impl<I: Iterator<Item = Token>> Parser<I> {
self.skip(1); self.skip(1);
e::Immediate(im::Boolean(false)) 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 // Function definition
t::LeftParen t::LeftParen
if (self.look(1, t::Identifier("".into())).is_ok() 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.look(1, t::RightParen).is_ok() =>
{ {
self.skip(1); self.skip(1);
let mut params = vec![]; let params = self.parameters(span)?;
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 Token(_, span2) = self let Token(_, span2) = self
.eat(t::RightParen) .eat(t::RightParen)
.span(&span) .span(&span)
@ -355,38 +442,16 @@ impl<I: Iterator<Item = Token>> Parser<I> {
returns_str, returns_str,
returns_actual: Type::Ambiguous, returns_actual: Type::Ambiguous,
body, body,
id: "".into(), uid: "".into(),
} }
}, },
// Struct definition // Struct definition
t::Struct => { t::Struct => {
self.skip(1); self.skip(1);
self.eat(t::LeftBrace)?; self.eat(t::LeftBrace)?;
let mut params = vec![]; let params = self.parameters(span)?;
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;
}
}
self.eat(t::RightBrace)?; self.eat(t::RightBrace)?;
e::StructDef(params, usize::MAX) e::StructDef(params, "".into())
}, },
// Struct literal // Struct literal
t::Identifier(name) if self.look(1, t::LeftBrace).is_ok() => { t::Identifier(name) if self.look(1, t::LeftBrace).is_ok() => {
@ -414,12 +479,15 @@ impl<I: Iterator<Item = Token>> Parser<I> {
e::StructLiteral { e::StructLiteral {
name, name,
args, args,
id: "".into(), uid: "".into(),
} }
}, },
t::Identifier(i) => { t::Identifier(i) => {
self.skip(1); self.skip(1);
e::Identifier(i, "".into()) e::Identifier {
name: i,
uid: "".into(),
}
}, },
// Parenthetical // Parenthetical
t::LeftParen => { t::LeftParen => {
@ -442,6 +510,41 @@ impl<I: Iterator<Item = Token>> Parser<I> {
Ok(Expression::new(kind, span, Type::Ambiguous)) Ok(Expression::new(kind, span, Type::Ambiguous))
} }
fn if_else(&mut self) -> Result<Expression> {
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)> { fn identifier(&mut self) -> Result<(String, Span)> {
use TokenKind as t; use TokenKind as t;
match self.peek(0) { match self.peek(0) {

View file

@ -1,4 +1,4 @@
use crate::semantic::{Type, UID}; use crate::semantic::UID;
use super::*; use super::*;
@ -7,7 +7,7 @@ pub enum StatementKind {
Declaration { Declaration {
name: String, name: String,
type_str: Option<String>, type_str: Option<String>,
type_actual: Type, type_uid: UID,
value: Expression, value: Expression,
mutable: bool, mutable: bool,
uid: UID, uid: UID,
@ -17,18 +17,13 @@ pub enum StatementKind {
value: Expression, value: Expression,
uid: UID, uid: UID,
}, },
If {
predicate: Expression,
block: Vec<Statement>,
else_: Option<Box<Statement>>,
},
While { While {
predicate: Expression, predicate: Expression,
block: Vec<Statement>, block: Vec<Statement>,
}, },
Print(Expression), Print(Expression),
Expression(Expression), Expression(Expression),
Block(Vec<Statement>), Remainder(Expression),
Return(Option<Expression>), Return(Option<Expression>),
Error(Diagnostic), Error(Diagnostic),
} }
@ -83,7 +78,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
kind: s::Declaration { kind: s::Declaration {
name, name,
type_str, type_str,
type_actual: Type::Ambiguous, type_uid: "".into(),
value, value,
mutable, mutable,
uid: "".into(), uid: "".into(),
@ -111,10 +106,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
}, },
} }
}, },
// If
(Token(t::If, _), _) => {
return self.if_else();
},
// While // While
(Token(t::While, span2), _) => { (Token(t::While, span2), _) => {
self.skip(1); self.skip(1);
@ -149,19 +140,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
kind: s::Print(expr), 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 // Return
(Token(t::Return, span2), _) => { (Token(t::Return, span2), _) => {
span = span + span2; span = span + span2;
@ -182,9 +160,26 @@ impl<I: Iterator<Item = Token>> Parser<I> {
.expression(0) .expression(0)
.trace_span(span, "while parsing expression statement")?; .trace_span(span, "while parsing expression statement")?;
span = span + expr.span; span = span + expr.span;
Statement { 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, span,
kind: s::Expression(expr), kind: s::Expression(expr),
});
},
_ => Statement {
span,
kind: s::Expression(expr),
},
}
} }
}, },
}; };
@ -195,37 +190,4 @@ impl<I: Iterator<Item = Token>> Parser<I> {
error().reason("Expected ;").span(&span) error().reason("Expected ;").span(&span)
} }
} }
fn if_else(&mut self) -> Result<Statement> {
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,
})
}
}
} }

View file

@ -1,7 +1,9 @@
use crate::{Statement, semantic::SymbolTable}; use crate::{Expression, ExpressionKind, Statement, StatementKind};
use super::*;
pub struct Analyzer { pub struct Analyzer {
pub table: SymbolTable, table: SymbolTable,
} }
impl Analyzer { impl Analyzer {
@ -11,25 +13,79 @@ impl Analyzer {
} }
} }
pub fn typecheck( pub fn typecheck() {
&mut self, todo!()
mut statements: Vec<Statement>,
) -> Vec<Statement> {
for s in &mut statements {
*s = *self.naming_pass_stmt(s.clone().into()).unwrap();
} }
for s in &mut statements {
*s = *self.bottom_up_stmt(s.clone().into()).unwrap(); /// Analyzing a block:
} /// 1. Name structs
for s in &mut statements { /// 2. Type structs
*s = *self.top_down_stmt(s.clone().into()).unwrap(); /// 3. Name and type functions
} /// 4. Name variables (recurse on blocks) (track moves)
println!("-----TABLE------"); /// 5. Type variables
println!("{:#?}", self.table.table); /// 6. Type assert variables
println!("-----FUNCS------"); pub fn block(&mut self, mut block: Vec<Statement>) -> Result<Vec<Statement>> {
println!("{:#?}", self.table.functions); // 1. Name structs
println!("-----STRUCTS----"); for s in &mut block {
println!("{:#?}", self.table.structs); if let StatementKind::Declaration {
statements name,
value:
Expression {
kind: ExpressionKind::StructDef(params, _),
type_,
..
},
..
} = &mut s.kind
{
*type_ = Type::Nothing;
self.table.declare_struct(name, s.span)?;
}
}
// 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)?;
}
}
// 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);
}
}
Ok(block)
} }
} }

View file

@ -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<Statement>,
) -> Result<Box<Statement>> {
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<Expression>,
) -> Result<Box<Expression>> {
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)
}
}

View file

@ -1,369 +1,357 @@
mod analyzer; pub mod analyzer;
mod bottom_up; pub mod primitives;
mod naming;
mod primitives; pub use analyzer::*;
mod sizing; pub use primitives::*;
mod top_down;
mod types;
use std::collections::HashMap; use std::collections::HashMap;
use crate::{Parameter, err::*}; use crate::{Parameters, Span, err::*, semantic::Primitive};
pub use analyzer::*;
pub use primitives::*;
pub use types::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub type UID = String;
enum Scope {
Block, #[derive(Debug, Clone)]
Function, pub enum Type {
Ambiguous,
Prim(Primitive),
Nothing,
Struct(UID),
Function(UID),
} }
// Mangled name impl std::fmt::Display for Type {
pub type UID = String; 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<UID>,
},
Function {
params: Parameters,
returns: UID,
},
Struct {
params: Parameters,
size: usize,
align: usize,
},
TypeDef {
actual: Type,
},
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Symbol { pub struct Symbol {
pub name: String, pub name: String,
pub type_: Type,
pub uid: UID, pub uid: UID,
initialized: bool, pub span: Option<Span>,
pub mutable: Option<bool>, pub kind: SymbolKind,
pub global: bool, }
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<Type> {
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)] #[derive(Debug, Clone)]
enum Definition { pub enum Event {
Ident(Symbol), Declared { name: String, uid: UID },
FuncStart, Moved { name: String, uid: UID, span: Span },
BlockStart, Func { returns: Vec<UID>, uid: UID },
Block { returns: UID },
} }
#[derive(Debug, Clone)]
pub struct SymbolTable { pub struct SymbolTable {
pub structs: Vec<StructureDef>, syms: HashMap<UID, Symbol>,
pub functions: HashMap<UID, FunctionDef>, scope: Vec<Event>,
scope: Vec<Definition>,
pub table: HashMap<UID, Symbol>,
mangle_num: usize,
nesting: usize, nesting: usize,
mangle_num: usize,
} }
impl SymbolTable { impl SymbolTable {
pub fn new() -> Self { 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 { Self {
structs: vec![], syms: HashMap::new(),
functions, scope: vec![],
scope,
table,
mangle_num: 0,
nesting: 0, 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<Type> {
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 { fn generate_uid(&mut self, name: &str) -> UID {
let uid = format!("${}${name}", self.mangle_num); let uid = format!("${}${name}", self.mangle_num);
self.mangle_num += 1; self.mangle_num += 1;
uid uid
} }
pub fn get_field(&self, struct_id: SID, field_name: &str) -> Result<Type> { pub fn get(&self, uid: &UID) -> &Symbol {
let struct_def = &self.structs[struct_id].0; self.syms.get(uid).unwrap()
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<Parameter>) -> SID { pub fn get_mut(&mut self, uid: &UID) -> &mut Symbol {
let sid = self.structs.len(); self.syms.get_mut(uid).unwrap()
let mut new_params = vec![];
for p in params {
let s = self.reference_ident(&p.type_str);
new_params.push((p.name, s.uid));
}
self.structs.push(StructureDef(new_params));
sid
} }
pub fn create_function( // Find the definition of a symbol in local and global scope
&mut self, pub fn find(&self, name: &str) -> Result<&Symbol> {
params: Vec<Parameter>, let mut nesting = self.nesting;
returns: Option<String>, for e in self.scope.iter().rev() {
) -> Result<UID> { match e {
let uid = self.generate_uid("func"); Event::Declared { uid, .. }
let mut symbols = vec![]; if nesting == self.nesting || nesting == 0 =>
for p in &params { {
let symbol = self.reference_ident(&p.type_str); return Ok(self.get(uid));
symbols.push(symbol); },
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<UID> {
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<()> {
if let SymbolKind::Variable { global, .. } = self.get(move_uid).kind {
if global {
return error().reason("Cannot move global symbol").span(&span);
} }
let returns = if let Some(s) = returns {
self.reference_ident(&s).uid
} else { } else {
nothing_mangle() panic!("Moved non-variable {move_uid}");
};
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);
} }
self.functions.insert(uid.clone(), FunctionDef { let children = self.get_all_children(move_uid);
params: new_params, for e in self.scope.iter().rev() {
returns, 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<UID> {
// 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) Ok(uid)
} }
pub fn modify_ident( fn type_params(&mut self, mut params: Parameters) -> Result<Parameters> {
&mut self, for i in 0..params.arity {
uid: UID, params.types[i] = self
name: Option<String>, .find(&params.type_names[i])
type_: Option<Type>, .trace(format!(
mutable: Option<bool>, "while resolving type of field '{}'",
init: bool, params.type_names[i]
global: bool, ))?
) -> Result<()> { .uid
let symbol = self.table.get_mut(&uid).unwrap(); .clone();
if let Some(ref type_) = type_ { }
symbol.type_ = symbol.type_.clone().deduce(type_)?; Ok(params)
} }
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;
let mut nesting = self.nesting; pub fn define_function(
for def in &mut self.scope { &mut self,
match def { func_name: &str,
Definition::Ident(symbol) params: Parameters,
if (symbol.uid == uid) returns_str: Option<&str>,
&& (nesting == 0 || nesting == self.nesting) => span: Span,
{ ) -> Result<UID> {
if let Some(ref name) = name { // Check for multiple definition
symbol.name = name.clone(); 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, 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()
}; };
symbol.initialized |= init; self.syms.insert(uid.clone(), Symbol {
symbol.global |= global; name: func_name.to_string(),
return Ok(()); uid: uid.clone(),
}, span: Some(span),
Definition::FuncStart => nesting -= 1, 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(()) Ok(())
//unreachable!("Symbol {uid} does not exist")
}
pub fn define_ident(
&mut self,
name: &str,
type_: Type,
mutable: bool,
) -> Result<Symbol> {
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<Symbol> {
self.lookup_scope(name, Scope::Block)
}
pub fn lookup_function_scope(&self, name: &str) -> Result<Symbol> {
self.lookup_scope(name, Scope::Function)
}
fn lookup_scope(&self, name: &str, scope: Scope) -> Result<Symbol> {
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
))
} }
} }

View file

@ -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<Statement>,
) -> Result<Box<Statement>> {
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<Expression>,
) -> Result<Box<Expression>> {
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)
}
}

View file

@ -40,18 +40,6 @@ macro_rules! primitives {
} }
} }
} }
pub fn primitive_symbols() -> Vec<Symbol> {
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,
},)*
]
}
}; };
} }

View file

@ -1,6 +0,0 @@
pub enum DataType {
i32,
i64,
f32,
f64,
}

View file

@ -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<Statement>,
) -> Result<Box<Statement>> {
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<Expression>,
expect: &Type,
) -> Result<Box<Expression>> {
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<String> = 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(), &param_t)?;
println!("/{param_t}");
}
e::StructLiteral { name, args, id }
},
e::Field {
namespace,
field,
uid,
} => e::Field {
namespace,
field,
uid,
},
};
Ok(expr)
}
}

View file

@ -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<UID>,
pub returns: UID,
}
pub fn nothing_mangle() -> UID {
"$$nothing".into()
}
#[derive(Debug, Clone)]
pub enum Type {
Ambiguous,
Nothing,
Alias(Box<Type>),
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<Type> {
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<Type> {
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<Type> {
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<Self> {
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<Self> {
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,
}
}
}

View file

@ -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<Statement>) -> Result<Vec<Statement>> {
// 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)
}
}

View file

@ -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<UID>,
},
Function {
arg_names: Vec<String>,
arg_types: Vec<UID>,
},
Struct {
field_names: Vec<String>,
field_types: Vec<UID>,
size: usize,
align: usize,
},
TypeDef {
actual: Type,
},
}
#[derive(Debug, Clone)]
pub struct Symbol {
pub name: String,
pub span: Option<Span>,
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<Type> {
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: UID },
Block { returns: UID },
}
pub struct SymbolTable {
syms: HashMap<UID, Symbol>,
scope: Vec<Event>,
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<UID> {
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<UID> {
// 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<String>,
field_types: Vec<UID>,
) {
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<String>,
arg_types: Vec<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::Function {
arg_names,
arg_types,
},
});
self.scope.push(Event::Declared {
name: name.to_string(),
uid: uid.clone(),
});
uid
}
}