Started IR again

This commit is contained in:
Logan 2024-11-01 12:34:58 -05:00
parent 552496c0f9
commit b936901e17
15 changed files with 1070 additions and 358 deletions

View file

@ -1,13 +1,2 @@
c :: C{r: 10.0}; a : integer : 10;
b := a + 10;
A :: struct {
b: B,
}
B :: struct {
c: C,
}
C :: struct {
r: real,
}

View file

@ -9,5 +9,6 @@ WebAssembly.instantiateStreaming(fetch(url), { console });
</script> </script>
<body> <body>
</body> </body>
</html> </html>

View file

@ -1,4 +1,4 @@
use std::{io::Write, path::Path}; use std::path::Path;
use crate::{ use crate::{
Parser, Tokenizer, Parser, Tokenizer,

107
src/ir/generate.rs Normal file
View file

@ -0,0 +1,107 @@
use crate::{Expression, ExpressionKind, Statement, StatementKind};
use super::*;
impl Compiler {
fn statement(&mut self, stmt: Statement) {
use StatementKind as s;
match stmt.kind {
s::Declaration {
name,
type_str,
type_actual,
value,
mutable,
uid,
} => self.push(IR::New {
uid,
type_: type_actual,
}),
s::Assignment { name, value, uid } => todo!(),
s::If {
predicate,
block,
else_,
} => todo!(),
s::While { predicate, block } => todo!(),
s::Print(expression) => todo!(),
s::Expression(expression) => todo!(),
s::Block(vec) => todo!(),
s::Return(expression) => todo!(),
s::Error(diagnostic) => todo!(),
}
}
fn expression(&mut self, expr: Expression) {
use ExpressionKind as e;
match expr.kind {
e::Immediate(immediate) => {
let Type::Prim(p) = expr.type_ else {
unreachable!();
};
self.push(IR::Push {
value: immediate,
prim: p,
})
},
e::Identifier(_, uid) => {
self.push(IR::Get { uid });
},
e::Binary { op, left, right } => {
self.expression(*left);
self.expression(*right);
self.push(IR::BinOp {
op,
type_: expr.type_,
})
},
e::Unary { op, child } => {
self.expression(*child);
self.push(IR::UnOp {
op,
type_: expr.type_,
})
},
e::Parenthesis(inner) => self.expression(*inner),
e::FunctionDef {
params,
returns_str,
returns_actual,
body,
id,
} => {
self.push(IR::StartFunc {
fid: id,
params: params.into_iter().map(|p| p.type_actual).collect(),
returns: returns_actual,
});
for s in body {
self.statement(s);
}
self.push(IR::EndFunc);
},
e::FunctionCall {
callee, args, id, ..
} => {
for arg in args {
self.expression(arg);
}
let fid = if let Type::Function(fid) = expr.type_ {
fid
} else {
unreachable!()
};
self.push(IR::Call { fid })
},
e::StructDef(..) => {},
e::StructLiteral { name, args, id } => {},
e::Field {
namespace,
field,
uid,
} => {
self.expression(*namespace);
},
}
}
}

View file

@ -1,28 +1,52 @@
mod generate;
pub use generate::*;
use crate::{ use crate::{
BinaryOp, Expression, ExpressionKind, Immediate, Statement, StatementKind, BinaryOp, Immediate, UnaryOp,
UnaryOp, semantic::{FID, Primitive, Type, UID},
semantic::{Primitive, Type, UID},
}; };
/*
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum IR { pub enum IR {
BinOp { op: BinaryOp, type_: Type }, BinOp {
UnOp { op: UnaryOp, type_: Type }, op: BinaryOp,
Push { prim: Primitive, value: Immediate }, type_: Type,
NewLocal { uid: UID, type_: Type }, },
AssignLocal { uid: UID }, UnOp {
GetLocal { uid: UID }, op: UnaryOp,
NewGlobal { uid: UID, type_: Type }, type_: Type,
AssignGlobal { uid: UID }, },
GetGlobal { uid: UID }, Push {
StartFunc { uid: UID }, prim: Primitive,
value: Immediate,
},
New {
uid: UID,
type_: Type,
},
Set {
uid: UID,
},
Get {
uid: UID,
},
StartFunc {
fid: FID,
params: Vec<Type>,
returns: Type,
},
EndFunc, EndFunc,
ReturnType { type_: Type }, ReturnType {
NewParam { uid: UID, type_: Type }, type_: Type,
},
Return, Return,
Call { uid: UID }, Call {
fid: FID,
},
Drop, Drop,
Print, Print {
type_: Type,
},
} }
impl std::fmt::Display for IR { impl std::fmt::Display for IR {
@ -32,24 +56,43 @@ impl std::fmt::Display for IR {
BinOp { op, type_ } => write!(f, "{op} ({type_})"), BinOp { op, type_ } => write!(f, "{op} ({type_})"),
UnOp { op, type_ } => write!(f, "{op}, {type_}"), UnOp { op, type_ } => write!(f, "{op}, {type_}"),
Push { prim, value } => write!(f, "push {value} ({prim})"), Push { prim, value } => write!(f, "push {value} ({prim})"),
NewLocal { uid, type_ } => write!(f, "local ${uid} = {type_}"), New { uid, type_ } => write!(f, "local ${uid} = {type_}"),
AssignLocal { uid } => write!(f, "pop local ${uid}"), Set { uid } => write!(f, "pop local ${uid}"),
GetLocal { uid } => write!(f, "push local ${uid}"), Get { uid } => write!(f, "push local ${uid}"),
NewGlobal { uid, type_ } => write!(f, "global ${uid} = {type_}"), StartFunc {
AssignGlobal { uid } => write!(f, "pop global ${uid}"), uid,
GetGlobal { uid } => write!(f, "push global ${uid}"), params,
StartFunc { uid } => write!(f, "<function id=${uid}>"), returns,
} => write!(
f,
"<function id=${uid} params={params:?} returns={returns}>"
),
EndFunc => write!(f, "</function>"), EndFunc => write!(f, "</function>"),
NewParam { uid, type_ } => write!(f, "param ${uid} = {type_}"),
Return => write!(f, "return"), Return => write!(f, "return"),
Call { uid } => write!(f, "call ${uid}"), Call { uid } => write!(f, "call ${uid}"),
Drop => write!(f, "pop"), Drop => write!(f, "pop"),
ReturnType { type_ } => write!(f, "result {type_}"), ReturnType { type_ } => write!(f, "result {type_}"),
Print => write!(f, "print [DEBUG]"), Print { type_ } => write!(f, "print {type_} [DEBUG]"),
} }
} }
} }
#[derive(Debug, Clone)]
pub struct Compiler {
ir: Vec<IR>,
}
impl Compiler {
pub fn new() -> Self {
Self { ir: vec![] }
}
pub fn push(&mut self, ir: IR) {
self.ir.push(ir);
}
}
/*
impl IR { impl IR {
pub fn to_wat(&self) -> String { pub fn to_wat(&self) -> String {
use BinaryOp as b; use BinaryOp as b;

View file

@ -99,13 +99,10 @@ fn typecheck(input: &'static str) -> Vec<Statement> {
} }
fn main() -> Result<()> { fn main() -> Result<()> {
/*
for s in typecheck(include_str!("../demo.hal")) { for s in typecheck(include_str!("../demo.hal")) {
println!("{s:#?}");
println!("------------------"); println!("------------------");
println!("{s:#?}");
} }
*/
typecheck(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

@ -67,6 +67,7 @@ pub enum ExpressionKind {
StructLiteral { StructLiteral {
name: String, name: String,
args: Vec<(String, Expression)>, args: Vec<(String, Expression)>,
id: UID,
}, },
Field { Field {
namespace: Box<Expression>, namespace: Box<Expression>,
@ -121,7 +122,7 @@ impl std::fmt::Debug for ExpressionKind {
write!(f, "(fn({params:?}) -> {returns_actual:?})") write!(f, "(fn({params:?}) -> {returns_actual:?})")
}, },
e::StructDef(params, _) => write!(f, "struct {{ {params:?} }}"), e::StructDef(params, _) => write!(f, "struct {{ {params:?} }}"),
e::StructLiteral { name, args } => write!(f, "{name} {{ {args:?} }}"), e::StructLiteral { name, args, .. } => write!(f, "{name} {{ {args:?} }}"),
} }
} }
} }
@ -410,7 +411,11 @@ impl<I: Iterator<Item = Token>> Parser<I> {
} }
} }
self.eat(t::RightBrace)?; self.eat(t::RightBrace)?;
e::StructLiteral { name, args } e::StructLiteral {
name,
args,
id: "".into(),
}
}, },
t::Identifier(i) => { t::Identifier(i) => {
self.skip(1); self.skip(1);

View file

@ -1,10 +1,4 @@
use crate::{ use crate::{Statement, semantic::SymbolTable};
Expression, ExpressionKind, Immediate, Statement, StatementKind,
err::*,
semantic::{Primitive, SymbolTable},
};
use super::Type;
pub struct Analyzer { pub struct Analyzer {
pub table: SymbolTable, pub table: SymbolTable,
@ -18,6 +12,12 @@ impl Analyzer {
for s in &mut statements { for s in &mut statements {
*s = *this.naming_pass_stmt(s.clone().into()).unwrap(); *s = *this.naming_pass_stmt(s.clone().into()).unwrap();
} }
for s in &mut statements {
*s = *this.bottom_up_stmt(s.clone().into()).unwrap();
}
for s in &mut statements {
*s = *this.top_down_stmt(s.clone().into()).unwrap();
}
println!("-----TABLE------"); println!("-----TABLE------");
println!("{:#?}", this.table.table); println!("{:#?}", this.table.table);
println!("-----FUNCS------"); println!("-----FUNCS------");
@ -26,224 +26,4 @@ impl Analyzer {
println!("{:#?}", this.table.structs); println!("{:#?}", this.table.structs);
statements statements
} }
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,
type_str,
mut type_actual,
mut value,
mutable,
mut uid,
} => {
value = *self.naming_pass_expr(value.into())?;
if let Some(ref type_str) = type_str {
type_actual = self.table.reference_ident(type_str).type_;
} else {
type_actual = value.type_.clone();
}
let symbol =
self
.table
.define_ident(&name, type_actual.clone(), mutable)?;
uid = symbol.uid;
s::Declaration {
name,
type_str,
type_actual,
value,
mutable,
uid,
}
},
s::Assignment {
name,
mut value,
mut uid,
} => {
uid = self.table.reference_ident(&name).uid;
value = *self.naming_pass_expr(value.into())?;
// Hint ident is rhs type and mutable
self.table.modify_ident(
uid.clone(),
None,
Some(value.type_.clone()),
Some(true),
false,
)?;
s::Assignment { name, value, uid }
},
s::If {
mut predicate,
mut block,
mut else_,
} => {
predicate = *self.naming_pass_expr(predicate.into())?;
self.table.start_block();
for s in &mut block {
*s = *self.naming_pass_stmt(s.clone().into())?;
}
self.table.end_block();
else_ = if let Some(else_) = else_ {
Some(self.naming_pass_stmt(else_)?)
} else {
None
};
s::If {
predicate,
block,
else_,
}
},
s::While {
mut predicate,
mut block,
} => {
predicate = *self.naming_pass_expr(predicate.into())?;
self.table.start_block();
for s in &mut block {
*s = *self.naming_pass_stmt(s.clone().into())?;
}
self.table.end_block();
s::While { predicate, block }
},
s::Print(mut expression) => {
expression = *self.naming_pass_expr(expression.into())?;
s::Print(expression)
},
s::Expression(mut expression) => {
expression = *self.naming_pass_expr(expression.into())?;
s::Expression(expression)
},
s::Block(mut block) => {
self.table.start_block();
for s in &mut block {
*s = *self.naming_pass_stmt(s.clone().into())?;
}
self.table.end_block();
s::Block(block)
},
s::Return(mut expression) => {
if let Some(e) = expression {
expression = Some(*self.naming_pass_expr(e.into())?);
}
s::Return(expression)
},
s::Error(diagnostic) => s::Error(diagnostic),
};
Ok(stmt)
}
pub fn naming_pass_expr(
&mut self,
mut expr: Box<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,
} => {
id = self
.table
.create_function(params.clone(), returns_str.clone());
expr.type_ = Type::Function(id.clone());
self.table.start_function();
for s in &mut body {
*s = *self.naming_pass_stmt(s.clone().into())?;
}
self.table.end_function();
e::FunctionDef {
params,
returns_str,
returns_actual,
body,
id,
}
},
e::FunctionCall {
mut callee,
mut args,
is_reference,
id,
} => {
callee = self.naming_pass_expr(callee)?;
for a in &mut args {
*a = *self.naming_pass_expr(a.clone().into())?;
}
e::FunctionCall {
callee,
args,
is_reference,
id,
}
},
e::StructDef(params, mut sid) => {
sid = self.table.create_struct(params.clone());
expr.type_ = Type::Alias(Box::new(Type::Struct(sid)));
e::StructDef(params, sid)
},
e::StructLiteral { name, mut args } => {
self.table.reference_ident(&name);
for (_, a) in &mut args {
*a = *self.naming_pass_expr(a.clone().into())?;
}
e::StructLiteral { name, args }
},
e::Field {
mut namespace,
field,
uid,
} => {
namespace = self.naming_pass_expr(namespace)?;
e::Field {
namespace,
field,
uid,
}
},
};
Ok(expr)
}
} }

View file

@ -1,25 +1,283 @@
use super::Analyzer; use super::Analyzer;
use crate::{ use crate::{Expression, ExpressionKind, Statement, StatementKind, err::*};
Expression, ExpressionKind, Immediate, Statement, StatementKind,
err::*,
semantic::{Primitive, SymbolTable},
};
use super::Type; use super::Type;
impl Analyzer { impl Analyzer {
pub fn stmt_bottom_up( pub fn bottom_up_stmt(
&mut self, &mut self,
mut stmt: Box<Statement>, mut stmt: Box<Statement>,
) -> Result<Box<Statement>> { ) -> Result<Box<Statement>> {
todo!() use StatementKind as s;
stmt.kind = match stmt.kind {
s::Declaration {
name,
type_str,
mut type_actual,
mut value,
mutable,
uid,
} => {
value = *self.bottom_up_expr(value.into())?;
if let Some(ref uid) = type_str {
type_actual =
self.table.resolve_type(uid)?.is_alias().span(&stmt.span)?;
}
value.type_ = value
.type_
.deduce(&type_actual)
.span(&value.span)?
.promote();
type_actual = value.type_.clone();
if let Type::Ambiguous = type_actual {
return error()
.reason(format!("Cannot deduce type of {name}"))
.span(&stmt.span);
}
self.table.modify_ident(
uid.clone(),
None,
Some(type_actual.clone()),
None,
true,
)?;
s::Declaration {
name,
type_str,
type_actual,
value,
mutable,
uid,
}
},
s::Assignment {
name,
mut value,
uid,
} => {
value = *self.bottom_up_expr(value.into())?;
self.table.modify_ident(
uid.clone(),
None,
Some(value.type_.clone()),
Some(true),
true,
)?;
s::Assignment { name, value, uid }
},
s::If {
mut predicate,
mut block,
mut else_,
} => {
predicate = *self.bottom_up_expr(predicate.into())?;
self.table.start_block();
for s in &mut block {
*s = *self.bottom_up_stmt(s.clone().into())?;
}
self.table.end_block();
else_ = if let Some(else_) = else_ {
Some(self.bottom_up_stmt(else_)?)
} else {
None
};
s::If {
predicate,
block,
else_,
}
},
s::While {
mut predicate,
mut block,
} => {
predicate = *self.bottom_up_expr(predicate.into())?;
self.table.start_block();
for s in &mut block {
*s = *self.bottom_up_stmt(s.clone().into())?;
}
self.table.end_block();
s::While { predicate, block }
},
s::Print(mut expression) => {
expression = *self.bottom_up_expr(expression.into())?;
s::Print(expression)
},
s::Expression(mut expression) => {
expression = *self.bottom_up_expr(expression.into())?;
s::Expression(expression)
},
s::Block(mut block) => {
for s in &mut block {
*s = *self.bottom_up_stmt(s.clone().into())?;
}
s::Block(block)
},
s::Return(mut expression) => {
expression = if let Some(e) = expression {
Some(*self.bottom_up_expr(e.into())?)
} else {
None
};
s::Return(expression)
},
s::Error(diagnostic) => s::Error(diagnostic),
};
Ok(stmt)
} }
// Bottom up type inference // Bottom up type inference
pub fn expr_bottom_up( pub fn bottom_up_expr(
&mut self, &mut self,
mut expr: Box<Expression>, mut expr: Box<Expression>,
) -> Result<Box<Expression>> { ) -> Result<Box<Expression>> {
todo!() use ExpressionKind as e;
expr.kind = match expr.kind {
// Type assigned in naming step
e::Immediate(immediate) => e::Immediate(immediate),
e::Identifier(name, mangle) => {
expr.type_ = self
.table
.resolve_type(&mangle)
.trace_span(expr.span, format!("While resolving type of '{name}'"))?;
e::Identifier(name, mangle)
},
e::Binary {
op,
mut left,
mut right,
} => {
left = self.bottom_up_expr(left)?;
right = self.bottom_up_expr(right)?;
expr.type_ =
Type::binary_op(&left.type_, op, &right.type_).span(&expr.span)?;
e::Binary { op, left, right }
},
e::Unary { op, mut child } => {
child = self.bottom_up_expr(child)?;
expr.type_ = Type::unary_op(op, &child.type_)?;
e::Unary { op, child }
},
e::Parenthesis(mut expression) => {
expression = self.bottom_up_expr(expression)?;
expr.type_ = expression.type_.clone();
e::Parenthesis(expression)
},
e::FunctionDef {
mut params,
returns_str,
mut returns_actual,
mut body,
id,
} => {
let funcdef = self.table.functions[id].clone();
self.table.start_function();
for (uid, param) in funcdef.params.iter().zip(params.iter_mut()) {
let type_ = self.table.resolve_type(uid).span(&expr.span)?;
param.type_actual = type_;
}
for s in &mut body {
*s = *self.bottom_up_stmt(s.clone().into())?;
}
self.table.end_function();
returns_actual =
self.table.resolve_type(&funcdef.returns).span(&expr.span)?;
e::FunctionDef {
params,
returns_str,
returns_actual,
body,
id,
}
},
e::FunctionCall {
mut callee,
mut args,
is_reference,
id,
} => {
callee = self.bottom_up_expr(callee)?;
match callee.type_ {
Type::Function(fid) => {
expr.type_ = self
.table
.resolve_type(&self.table.functions[fid].returns)
.span(&callee.span)?
.is_alias()
.span(&expr.span)?
},
_ => {
return error()
.reason(format!("Cannot call type {}", callee.type_))
.span(&expr.span);
},
}
for a in &mut args {
*a = *self.bottom_up_expr(a.clone().into())?;
}
e::FunctionCall {
callee,
args,
is_reference,
id,
}
},
e::StructDef(mut params, sid) => {
let struct_ = &self.table.structs[sid].0;
for ((_, uid), p) in struct_.iter().zip(params.iter_mut()) {
p.type_actual = self
.table
.resolve_type(uid)
.trace_span(expr.span, "For struct field")?;
}
e::StructDef(params, sid)
},
e::StructLiteral { name, mut args, id } => {
expr.type_ = self
.table
.resolve_type(&id)
.span(&expr.span)?
.is_alias()
.span(&expr.span)?;
for (_name, arg) in &mut args {
*arg = *self.bottom_up_expr(arg.clone().into())?;
}
e::StructLiteral { name, args, id }
},
e::Field {
mut namespace,
field,
uid,
} => {
namespace = self.bottom_up_expr(namespace)?;
if let Type::Struct(s) = namespace.type_ {
if let e::Identifier(name, _) = &field.kind {
expr.type_ = self
.table
.get_field(s, name)
.span(&expr.span)?
.is_alias()
.reason("Expected type, found value")
.span(&expr.span)?;
} else {
return error().reason("Field must be identifier").span(&expr.span);
}
} else {
return error()
.reason(format!(
"Type '{}' does not contain fields",
namespace.type_
))
.span(&expr.span);
}
// TODO handle name mangle
e::Field {
namespace,
field,
uid,
}
},
};
Ok(expr)
} }
} }

View file

@ -1,5 +1,6 @@
mod analyzer; mod analyzer;
mod bottom_up; mod bottom_up;
mod naming;
mod primitives; mod primitives;
mod top_down; mod top_down;
mod types; mod types;
@ -11,6 +12,12 @@ pub use analyzer::*;
pub use primitives::*; pub use primitives::*;
pub use types::*; pub use types::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Scope {
Block,
Function,
}
// Mangled name // Mangled name
pub type UID = String; pub type UID = String;
@ -23,18 +30,6 @@ pub struct Symbol {
mutable: Option<bool>, mutable: Option<bool>,
} }
impl Symbol {
pub fn assert_is_type(&self) -> Result<Type> {
if let Type::Alias(ref t) = self.type_ {
return Ok(*t.clone());
}
error().reason(format!(
"The name '{}' refers to a value, not a type",
self.name
))
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum Definition { enum Definition {
Ident(Symbol), Ident(Symbol),
@ -86,23 +81,47 @@ impl SymbolTable {
} }
pub fn end_block(&mut self) { pub fn end_block(&mut self) {
let mut escaped = vec![];
while !self.scope.is_empty() { while !self.scope.is_empty() {
if let Some(Definition::BlockStart) = self.scope.pop() { let top = self.scope.pop();
if let Some(Definition::BlockStart) = top {
self.scope.append(&mut escaped);
return; return;
} else if let Some(Definition::Ident(s)) = top {
if !s.initialized {
escaped.push(Definition::Ident(s));
}
} }
} }
unreachable!("Cannot end global scope") unreachable!("Cannot end global scope")
} }
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 start_function(&mut self) { pub fn start_function(&mut self) {
self.nesting += 1; self.nesting += 1;
self.scope.push(Definition::FuncStart); self.scope.push(Definition::FuncStart);
} }
pub fn end_function(&mut self) { pub fn end_function(&mut self) {
self.nesting -= 1;
let mut escaped = vec![];
while !self.scope.is_empty() { while !self.scope.is_empty() {
if let Some(Definition::FuncStart) = self.scope.pop() { let top = self.scope.pop();
if let Some(Definition::FuncStart) = top {
self.scope.append(&mut escaped);
return; return;
} else if let Some(Definition::Ident(s)) = top {
if !s.initialized {
escaped.push(Definition::Ident(s));
}
} }
} }
unreachable!("Cannot end global scope") unreachable!("Cannot end global scope")
@ -114,6 +133,16 @@ impl SymbolTable {
uid 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 create_struct(&mut self, params: Vec<Parameter>) -> SID { pub fn create_struct(&mut self, params: Vec<Parameter>) -> SID {
let sid = self.structs.len(); let sid = self.structs.len();
let mut new_params = vec![]; let mut new_params = vec![];
@ -129,23 +158,31 @@ impl SymbolTable {
&mut self, &mut self,
params: Vec<Parameter>, params: Vec<Parameter>,
returns: Option<String>, returns: Option<String>,
) -> FID { ) -> Result<FID> {
let fid = self.functions.len(); let fid = self.functions.len();
let mut new_params = vec![]; let mut symbols = vec![];
for p in params { for p in &params {
let s = self.reference_ident(&p.type_str); let symbol = self.reference_ident(&p.type_str);
new_params.push(s.uid); symbols.push(symbol);
} }
let returns = if let Some(s) = returns { let returns = if let Some(s) = returns {
Some(self.reference_ident(&s).uid) self.reference_ident(&s).uid
} else { } else {
Some(nothing_mangle()) nothing_mangle()
}; };
self.start_function();
let mut new_params = vec![];
for (p, s) in params.iter().zip(symbols.iter()) {
let s = self
.define_ident(&p.name, s.type_.clone(), false)
.trace("While initializing function parameters")?;
new_params.push(s.uid);
}
self.functions.push(FunctionDef { self.functions.push(FunctionDef {
params: new_params, params: new_params,
returns, returns,
}); });
fid Ok(fid)
} }
pub fn modify_ident( pub fn modify_ident(
@ -156,15 +193,17 @@ impl SymbolTable {
mutable: Option<bool>, mutable: Option<bool>,
init: bool, init: bool,
) -> Result<()> { ) -> Result<()> {
{
let symbol = self.table.get_mut(&uid).unwrap(); let symbol = self.table.get_mut(&uid).unwrap();
if let Some(ref type_) = type_ { if let Some(ref type_) = type_ {
symbol.type_ = symbol.type_.clone().deduce(type_)?; symbol.type_ = symbol.type_.clone().deduce(type_)?;
} }
if let Some(m) = mutable { symbol.mutable = match (symbol.mutable, mutable) {
symbol.mutable = Some(m); (Some(true), Some(false)) | (Some(false), Some(true)) => {
} return error().reason("Cannot mutate immutable symbol");
} },
_ => mutable,
};
symbol.initialized |= init;
let mut nesting = self.nesting; let mut nesting = self.nesting;
for def in &mut self.scope { for def in &mut self.scope {
@ -179,17 +218,21 @@ impl SymbolTable {
if let Some(ref type_) = type_ { if let Some(ref type_) = type_ {
symbol.type_ = symbol.type_.clone().deduce(type_)?; symbol.type_ = symbol.type_.clone().deduce(type_)?;
} }
if let Some(m) = mutable { symbol.mutable = match (symbol.mutable, mutable) {
symbol.mutable = Some(m); (Some(true), Some(false)) | (Some(false), Some(true)) => {
} return error().reason("Cannot mutate immutable symbol");
symbol.initialized &= init; },
_ => mutable,
};
symbol.initialized |= init;
return Ok(()); return Ok(());
}, },
Definition::FuncStart => nesting -= 1, Definition::FuncStart => nesting -= 1,
_ => {}, _ => {},
} }
} }
panic!("Symbol {uid} does not exist") Ok(())
//unreachable!("Symbol {uid} does not exist")
} }
pub fn define_ident( pub fn define_ident(
@ -198,7 +241,15 @@ impl SymbolTable {
type_: Type, type_: Type,
mutable: bool, mutable: bool,
) -> Result<Symbol> { ) -> Result<Symbol> {
if let Ok(s) = self.lookup_this_scope(name) { println!("---{name}---");
println!("{:#?}", self.lookup_block_scope(name));
if let Type::Alias(_) | Type::Function(_) = &type_ {
if mutable {
return error()
.reason("Struct and function definitions cannot be mutable");
}
}
if let Ok(s) = self.lookup_block_scope(name) {
// Re-definition error // Re-definition error
// TODO support name shadowing // TODO support name shadowing
if s.initialized { if s.initialized {
@ -232,7 +283,7 @@ impl SymbolTable {
} }
pub fn reference_ident(&mut self, name: &str) -> Symbol { pub fn reference_ident(&mut self, name: &str) -> Symbol {
match self.lookup_available_scope(name) { match self.lookup_function_scope(name) {
Ok(s) => s, Ok(s) => s,
Err(_) => { Err(_) => {
let uid = self.generate_uid(name); let uid = self.generate_uid(name);
@ -250,24 +301,29 @@ impl SymbolTable {
} }
} }
pub fn lookup_this_scope(&self, name: &str) -> Result<Symbol> { pub fn lookup_block_scope(&self, name: &str) -> Result<Symbol> {
self.lookup_scope(name, false) self.lookup_scope(name, Scope::Block)
} }
pub fn lookup_available_scope(&self, name: &str) -> Result<Symbol> { pub fn lookup_function_scope(&self, name: &str) -> Result<Symbol> {
self.lookup_scope(name, true) self.lookup_scope(name, Scope::Function)
} }
fn lookup_scope(&self, name: &str, with_global: bool) -> Result<Symbol> { fn lookup_scope(&self, name: &str, scope: Scope) -> Result<Symbol> {
let mut nesting = self.nesting; let mut nesting = self.nesting;
for def in &self.scope { for def in self.scope.iter().rev() {
match def { match def {
Definition::Ident(symbol) Definition::Ident(symbol)
if (symbol.name == name) if (symbol.name == name)
&& ((nesting == 0 && with_global) || nesting == self.nesting) => && ((nesting == 0) || nesting == self.nesting) =>
{ {
return Ok(symbol.clone()); return Ok(symbol.clone());
}, },
Definition::FuncStart | Definition::BlockStart
if scope == Scope::Block =>
{
break;
},
Definition::FuncStart => nesting -= 1, Definition::FuncStart => nesting -= 1,
_ => {}, _ => {},
} }

234
src/semantic/naming.rs Normal file
View file

@ -0,0 +1,234 @@
use super::Analyzer;
use crate::{
Expression, ExpressionKind, Immediate, Statement, StatementKind, err::*,
semantic::Primitive,
};
use super::Type;
impl Analyzer {
pub fn naming_pass_stmt(
&mut self,
mut stmt: Box<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()
};
println!("{type_:?}");
let symbol = self.table.define_ident(&name, type_, mutable)?;
uid = symbol.uid;
s::Declaration {
name,
type_str,
type_actual,
value,
mutable,
uid,
}
},
s::Assignment {
name,
mut value,
mut uid,
} => {
uid = self.table.reference_ident(&name).uid;
value = *self.naming_pass_expr(value.into())?;
// Hint ident is rhs type and mutable
self.table.modify_ident(
uid.clone(),
None,
Some(value.type_.clone()),
Some(true),
false,
)?;
s::Assignment { name, value, uid }
},
s::If {
mut predicate,
mut block,
mut else_,
} => {
predicate = *self.naming_pass_expr(predicate.into())?;
self.table.start_block();
for s in &mut block {
*s = *self.naming_pass_stmt(s.clone().into())?;
}
self.table.end_block();
else_ = if let Some(else_) = else_ {
Some(self.naming_pass_stmt(else_)?)
} else {
None
};
s::If {
predicate,
block,
else_,
}
},
s::While {
mut predicate,
mut block,
} => {
predicate = *self.naming_pass_expr(predicate.into())?;
self.table.start_block();
for s in &mut block {
*s = *self.naming_pass_stmt(s.clone().into())?;
}
self.table.end_block();
s::While { predicate, block }
},
s::Print(mut expression) => {
expression = *self.naming_pass_expr(expression.into())?;
s::Print(expression)
},
s::Expression(mut expression) => {
expression = *self.naming_pass_expr(expression.into())?;
s::Expression(expression)
},
s::Block(mut block) => {
self.table.start_block();
for s in &mut block {
*s = *self.naming_pass_stmt(s.clone().into())?;
}
self.table.end_block();
s::Block(block)
},
s::Return(mut expression) => {
if let Some(e) = expression {
expression = Some(*self.naming_pass_expr(e.into())?);
}
s::Return(expression)
},
s::Error(diagnostic) => s::Error(diagnostic),
};
Ok(stmt)
}
pub fn naming_pass_expr(
&mut self,
mut expr: Box<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

@ -129,16 +129,22 @@ macro_rules! comparison {
} }
impl Primitive { impl Primitive {
pub fn coerce(&mut self, into: Primitive) { pub fn coerce(self, expect: Primitive) -> Result<Self> {
use Primitive::*; use Primitive::*;
*self = match (*self, into) { match (self, expect) {
( (
integer_ambiguous, integer_ambiguous,
i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole, a @ (i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole),
) => into, )
(real_ambiguous, r32 | r64 | real) => into, | (
_ => *self, a @ (i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole),
}; integer_ambiguous,
) => Ok(a),
(real_ambiguous, a @ (r32 | r64 | real))
| (a @ (r32 | r64 | real), real_ambiguous) => Ok(a),
(t1, t2) if t1 == t2 => Ok(t1),
_ => error().reason(format!("Cannot coerce '{self}' into '{expect}'")),
}
} }
pub fn is_ambiguous(&self) -> bool { pub fn is_ambiguous(&self) -> bool {
@ -163,9 +169,9 @@ impl Primitive {
) -> Result<Primitive> { ) -> Result<Primitive> {
use Primitive::*; use Primitive::*;
if lhs.is_ambiguous() && !rhs.is_ambiguous() { if lhs.is_ambiguous() && !rhs.is_ambiguous() {
lhs.coerce(rhs); lhs = lhs.coerce(rhs)?;
} else if rhs.is_ambiguous() && !lhs.is_ambiguous() { } else if rhs.is_ambiguous() && !lhs.is_ambiguous() {
rhs.coerce(lhs); rhs = rhs.coerce(lhs)?;
} }
selfsame_basic! { selfsame_basic! {
lhs, op, rhs; w8, w16, w32, w64, i8, i16, i32, i64, lhs, op, rhs; w8, w16, w32, w64, i8, i16, i32, i64,

View file

@ -1,24 +1,227 @@
use super::{Analyzer, Type}; use super::{Analyzer, Type};
use crate::{ use crate::{
Expression, ExpressionKind, Immediate, Statement, StatementKind, Expression, ExpressionKind, Statement, StatementKind, err::*,
err::*, semantic::Primitive,
semantic::{Primitive, SymbolTable},
}; };
impl Analyzer { impl Analyzer {
pub fn stmt_top_down( pub fn top_down_stmt(
&mut self, &mut self,
mut stmt: Box<Statement>, mut stmt: Box<Statement>,
expect: &Type,
) -> Result<Box<Statement>> { ) -> Result<Box<Statement>> {
todo!() use StatementKind as s;
stmt.kind = match stmt.kind {
s::Declaration {
name,
type_str,
type_actual,
mut value,
mutable,
uid,
} => {
value = *self.top_down_expr(value.into(), &type_actual)?;
s::Declaration {
name,
type_str,
type_actual,
value,
mutable,
uid,
}
},
s::Assignment {
name,
mut value,
uid,
} => {
let type_ = self.table.resolve_type(&uid).span(&stmt.span)?;
value = *self.top_down_expr(value.into(), &type_)?;
s::Assignment { name, value, uid }
},
s::If {
mut predicate,
mut block,
mut else_,
} => {
predicate = *self
.top_down_expr(predicate.into(), &Type::Prim(Primitive::boolean))?;
for s in &mut block {
*s = *self.top_down_stmt(s.clone().into())?;
}
else_ = if let Some(else_) = else_ {
Some(self.top_down_stmt(else_)?)
} else {
None
};
s::If {
predicate,
block,
else_,
}
},
s::While {
mut predicate,
mut block,
} => {
predicate = *self
.top_down_expr(predicate.into(), &Type::Prim(Primitive::boolean))?;
for s in &mut block {
*s = *self.top_down_stmt(s.clone().into())?;
}
s::While { predicate, block }
},
s::Print(mut expr) => {
let expr_t = expr.type_.clone();
expr = *self.top_down_expr(expr.into(), &expr_t)?;
s::Print(expr)
},
s::Expression(mut expr) => {
let expr_t = expr.type_.clone();
expr = *self.top_down_expr(expr.into(), &expr_t)?;
s::Expression(expr)
},
s::Block(mut block) => {
for s in &mut block {
*s = *self.top_down_stmt(s.clone().into())?;
}
s::Block(block)
},
s::Return(expr) => {
if let Some(mut expr) = expr {
let expr_t = expr.type_.clone();
expr = *self.top_down_expr(expr.into(), &expr_t)?;
s::Return(Some(expr))
} else {
s::Return(None)
}
},
s::Error(diagnostic) => s::Error(diagnostic),
};
Ok(stmt)
} }
pub fn expr_top_down( pub fn top_down_expr(
&mut self, &mut self,
mut expr: Box<Expression>, mut expr: Box<Expression>,
expect: &Type, expect: &Type,
) -> Result<Box<Expression>> { ) -> Result<Box<Expression>> {
todo!() use ExpressionKind as e;
expr.type_ = expr.type_.coerce(expect).span(&expr.span)?;
expr.kind = match expr.kind {
e::Immediate(i) => e::Immediate(i),
e::Identifier(i, m) => e::Identifier(i, m),
e::Binary {
op,
mut left,
mut right,
} => {
left = self.top_down_expr(left, expect)?;
right = self.top_down_expr(right, expect)?;
e::Binary { op, left, right }
},
e::Unary { op, mut child } => {
child = self.top_down_expr(child, expect)?;
e::Unary { op, child }
},
e::Parenthesis(mut expression) => {
expression = self.top_down_expr(expression, expect)?;
e::Parenthesis(expression)
},
e::FunctionDef {
params,
returns_str,
returns_actual,
mut body,
id,
} => {
for s in &mut body {
*s = *self.top_down_stmt(s.clone().into())?;
}
e::FunctionDef {
params,
returns_str,
returns_actual,
body,
id,
}
},
e::FunctionCall {
callee,
mut args,
is_reference,
id,
} => {
let func_def = if let Type::Function(fid) = callee.type_ {
self.table.functions[fid].clone()
} else {
unreachable!()
};
if func_def.params.len() != args.len() {
return error()
.reason(format!(
"Wrong number of arguments; found {}, expected {}",
args.len(),
func_def.params.len()
))
.span(&expr.span);
}
for (param, arg) in func_def.params.iter().zip(args.iter_mut()) {
let type_ = self.table.resolve_type(param).span(&arg.span)?;
*arg = *self.top_down_expr(arg.clone().into(), &type_)?;
}
e::FunctionCall {
callee,
args,
is_reference,
id,
}
},
e::StructDef(params, sid) => e::StructDef(params, sid),
e::StructLiteral { name, mut args, id } => {
let sid = if let Type::Struct(sid) = expr.type_ {
sid
} else {
return error()
.reason(format!("Cannot create struct from type {}", expr.type_))
.span(&expr.span);
};
if self.table.structs[sid].0.len() != args.len() {
return error()
.reason(format!(
"Wrong number of parameters; found {}, expected {}",
args.len(),
self.table.structs[sid].0.len()
))
.span(&expr.span);
}
let mut declared_params: Vec<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)?;
*arg = *self.top_down_expr(arg.clone().into(), &param_t)?;
}
e::StructLiteral { name, args, id }
},
e::Field {
namespace,
field,
uid,
} => e::Field {
namespace,
field,
uid,
},
};
Ok(expr)
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{BinaryOp, UnaryOp}; use crate::{BinaryOp, UnaryOp};
use super::{Symbol, UID, primitives::*}; use super::{UID, primitives::*};
use crate::err::*; use crate::err::*;
/// Struct ID /// Struct ID
@ -14,7 +14,7 @@ pub type FID = usize;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FunctionDef { pub struct FunctionDef {
pub params: Vec<UID>, pub params: Vec<UID>,
pub returns: Option<UID>, pub returns: UID,
} }
pub fn nothing_mangle() -> UID { pub fn nothing_mangle() -> UID {
@ -60,6 +60,14 @@ impl PartialEq for Type {
} }
impl Type { 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> { pub fn binary_op(lhs: &Type, op: BinaryOp, rhs: &Type) -> Result<Type> {
use Type as t; use Type as t;
let e = error().reason(format!( let e = error().reason(format!(
@ -86,17 +94,42 @@ impl Type {
pub fn deduce(self, hint: &Type) -> Result<Self> { pub fn deduce(self, hint: &Type) -> Result<Self> {
use Type::*; use Type::*;
match (hint, self) { match (self, hint) {
(Ambiguous, t) => Ok(t), (Ambiguous, t) => Ok(t.clone()),
(t, Ambiguous) => Ok(t.clone()), (t, Ambiguous) => Ok(t),
(Prim(mut p1), Prim(p2)) => { (Prim(mut p1), Prim(p2)) => {
p1.coerce(p2); p1 = p1.coerce(*p2)?;
Ok(Prim(p1)) Ok(Prim(p1))
}, },
(t1, t2) if t1 == &t2 => Ok(t1.clone()), (t1, t2) if &t1 == t2 => Ok(t1.clone()),
(t1, t2) => { (t1, t2) => {
error().reason(format!("Cannot coerce type '{t2}' into '{t1}'")) 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

@ -9,6 +9,7 @@ pub enum Base {
Hex = 16, Hex = 16,
} }
#[allow(dead_code)]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum TokenKind { pub enum TokenKind {
LeftParen, LeftParen,
@ -382,20 +383,19 @@ impl<I: Iterator<Item = char>> Tokenizer<I> {
buffer.push(c); buffer.push(c);
let _ = self.next_char(); let _ = self.next_char();
} }
buffer = buffer.to_lowercase();
// Determine base // Determine base
let base = if buffer.starts_with("0b") { let base = if buffer.starts_with("0b") {
Base::Binary Base::Binary
} else if buffer.starts_with("0o") || buffer.starts_with("0O") { } else if buffer.starts_with("0o") {
Base::Octal Base::Octal
} else if buffer.starts_with("0x") || buffer.starts_with("0X") { } else if buffer.starts_with("0x") {
Base::Hex Base::Hex
} else { } else {
Base::Decimal Base::Decimal
}; };
// Determine integer or float // Determine integer or float
if base == Base::Decimal if base == Base::Decimal && (encountered_dot || buffer.contains("e")) {
&& (encountered_dot || buffer.contains("e") || buffer.contains("E"))
{
return t(FloatLiteral(buffer), position); return t(FloatLiteral(buffer), position);
} else { } else {
return t(IntegerLiteral(buffer, base), position); return t(IntegerLiteral(buffer, base), position);