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 {
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 }

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 super::*;
@ -247,3 +248,4 @@ impl Compiler {
}
}
}
*/

View file

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

View file

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

View file

@ -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<Item = Token> {
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))
}
fn typecheck(input: &'static str) -> Vec<Statement> {
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(())

View file

@ -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<String>,
pub type_names: Vec<String>,
pub types: Vec<String>,
}
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<Expression>,
@ -51,29 +60,34 @@ pub enum ExpressionKind {
},
Parenthesis(Box<Expression>),
FunctionDef {
params: Vec<Parameter>,
params: Parameters,
returns_str: Option<String>,
returns_actual: Type,
body: Vec<Statement>,
id: UID,
uid: UID,
},
FunctionCall {
callee: Box<Expression>,
args: Vec<Expression>,
is_reference: bool,
id: UID,
uid: UID,
},
StructDef(Vec<Parameter>, usize),
StructDef(Parameters, UID),
StructLiteral {
name: String,
args: Vec<(String, Expression)>,
id: UID,
uid: UID,
},
Field {
namespace: Box<Expression>,
field: Box<Expression>,
uid: UID,
},
Block(Vec<Statement>),
If {
predicate: Box<Expression>,
block: Vec<Statement>,
else_: Option<Box<Expression>>,
},
}
#[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<I: Iterator<Item = Token>> Parser<I> {
Type::Ambiguous,
)
}
// Terminal or paren
// Primary
else {
self.primary().reason("Expected expression")?
};
@ -236,8 +272,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
e::FunctionCall {
callee: current.into(),
args,
is_reference: false,
id: "".into(),
uid: "".into(),
},
span + span2,
Type::Ambiguous,
@ -270,6 +305,73 @@ impl<I: Iterator<Item = Token>> Parser<I> {
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> {
use ExpressionKind as e;
use Immediate as im;
@ -301,36 +403,21 @@ impl<I: Iterator<Item = Token>> Parser<I> {
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<I: Iterator<Item = Token>> Parser<I> {
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<I: Iterator<Item = Token>> Parser<I> {
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<I: Iterator<Item = Token>> Parser<I> {
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)> {
use TokenKind as t;
match self.peek(0) {

View file

@ -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<String>,
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<Statement>,
else_: Option<Box<Statement>>,
},
While {
predicate: Expression,
block: Vec<Statement>,
},
Print(Expression),
Expression(Expression),
Block(Vec<Statement>),
Remainder(Expression),
Return(Option<Expression>),
Error(Diagnostic),
}
@ -83,7 +78,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
kind: s::Declaration {
name,
type_str,
type_actual: Type::Ambiguous,
type_uid: "".into(),
value,
mutable,
uid: "".into(),
@ -111,10 +106,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
},
}
},
// If
(Token(t::If, _), _) => {
return self.if_else();
},
// While
(Token(t::While, span2), _) => {
self.skip(1);
@ -149,19 +140,6 @@ impl<I: Iterator<Item = Token>> Parser<I> {
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<I: Iterator<Item = Token>> Parser<I> {
.expression(0)
.trace_span(span, "while parsing expression statement")?;
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,
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)
}
}
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 table: SymbolTable,
table: SymbolTable,
}
impl Analyzer {
@ -11,25 +13,79 @@ impl Analyzer {
}
}
pub fn typecheck(
&mut self,
mut statements: Vec<Statement>,
) -> Vec<Statement> {
for s in &mut statements {
*s = *self.naming_pass_stmt(s.clone().into()).unwrap();
pub fn typecheck() {
todo!()
}
for s in &mut statements {
*s = *self.bottom_up_stmt(s.clone().into()).unwrap();
}
for s in &mut statements {
*s = *self.top_down_stmt(s.clone().into()).unwrap();
}
println!("-----TABLE------");
println!("{:#?}", self.table.table);
println!("-----FUNCS------");
println!("{:#?}", self.table.functions);
println!("-----STRUCTS----");
println!("{:#?}", self.table.structs);
statements
/// 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<Statement>) -> Result<Vec<Statement>> {
// 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)?;
}
}
// 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;
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<UID>,
},
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<bool>,
pub global: bool,
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::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: UID },
Block { returns: UID },
}
#[derive(Debug, Clone)]
pub struct SymbolTable {
pub structs: Vec<StructureDef>,
pub functions: HashMap<UID, FunctionDef>,
scope: Vec<Definition>,
pub table: HashMap<UID, Symbol>,
mangle_num: usize,
syms: HashMap<UID, Symbol>,
scope: Vec<Event>,
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<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 {
let uid = format!("${}${name}", self.mangle_num);
self.mangle_num += 1;
uid
}
pub fn get_field(&self, struct_id: SID, field_name: &str) -> Result<Type> {
let struct_def = &self.structs[struct_id].0;
for (name, sid) in struct_def {
if name == field_name {
return self.resolve_type(sid);
}
}
error().reason(format!("Cannot find field '{field_name}'"))
pub fn get(&self, uid: &UID) -> &Symbol {
self.syms.get(uid).unwrap()
}
pub fn create_struct(&mut self, params: Vec<Parameter>) -> SID {
let sid = self.structs.len();
let mut new_params = vec![];
for p in params {
let s = self.reference_ident(&p.type_str);
new_params.push((p.name, s.uid));
}
self.structs.push(StructureDef(new_params));
sid
pub fn get_mut(&mut self, uid: &UID) -> &mut Symbol {
self.syms.get_mut(uid).unwrap()
}
pub fn create_function(
&mut self,
params: Vec<Parameter>,
returns: Option<String>,
) -> Result<UID> {
let uid = self.generate_uid("func");
let mut symbols = vec![];
for p in &params {
let symbol = self.reference_ident(&p.type_str);
symbols.push(symbol);
// 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<()> {
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 {
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<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)
}
pub fn modify_ident(
&mut self,
uid: UID,
name: Option<String>,
type_: Option<Type>,
mutable: Option<bool>,
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<Parameters> {
for i in 0..params.arity {
params.types[i] = self
.find(&params.type_names[i])
.trace(format!(
"while resolving type of field '{}'",
params.type_names[i]
))?
.uid
.clone();
}
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;
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<UID> {
// 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,
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;
symbol.global |= global;
return Ok(());
},
Definition::FuncStart => nesting -= 1,
_ => {},
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<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
}
}