IR working, fixed function call ABI
This commit is contained in:
parent
b936901e17
commit
fd1c13dc04
15
demo.hal
15
demo.hal
|
@ -1,2 +1,13 @@
|
||||||
a : integer : 10;
|
S :: struct {
|
||||||
b := a + 10;
|
a: integer,
|
||||||
|
b: glyph,
|
||||||
|
c: real,
|
||||||
|
}
|
||||||
|
|
||||||
|
s := foo(S{ a: 1, b: 'a', c: 1.0}, 2);
|
||||||
|
|
||||||
|
foo :: (s: S, a: integer) -> S {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
Parser, Tokenizer,
|
|
||||||
err::*,
|
|
||||||
semantic::{self},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Module {
|
|
||||||
file_name: String,
|
|
||||||
source: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Module {
|
|
||||||
pub fn from_file(path: impl AsRef<Path>) -> Result<Self> {
|
|
||||||
let file = std::fs::read(&path).trace(format!(
|
|
||||||
"while attempting to open file '{}'",
|
|
||||||
&path.as_ref().display()
|
|
||||||
))?;
|
|
||||||
let source = String::from_utf8_lossy(&file);
|
|
||||||
Ok(Self::from_string(
|
|
||||||
format!("{}", path.as_ref().display()),
|
|
||||||
source.into(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_string(file_name: String, source: String) -> Self {
|
|
||||||
let tokens = Tokenizer::new(source.chars()).filter(|t| t.0.is_meaningful());
|
|
||||||
let statements = Parser::new(tokens);
|
|
||||||
let program = semantic::Analyzer::typecheck(statements.collect());
|
|
||||||
Self {
|
|
||||||
file_name,
|
|
||||||
source: source.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
pub fn write_to(&self, path: impl AsRef<Path>) {
|
|
||||||
let watpath = path.as_ref().to_owned().with_extension("wat");
|
|
||||||
let mut file = std::fs::File::create(watpath).unwrap();
|
|
||||||
file.write_all(&self.wat.as_bytes()).unwrap();
|
|
||||||
|
|
||||||
let wasmpath = path.as_ref().to_owned().with_extension("wasm");
|
|
||||||
let mut file = std::fs::File::create(wasmpath).unwrap();
|
|
||||||
file.write_all(&self.wasm).unwrap();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
|
@ -3,36 +3,100 @@ use crate::{Expression, ExpressionKind, Statement, StatementKind};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl Compiler {
|
impl Compiler {
|
||||||
fn statement(&mut self, stmt: Statement) {
|
pub fn generate(&mut self, statements: Vec<Statement>) {
|
||||||
|
for s in statements {
|
||||||
|
self.statement(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_temporary(&mut self, type_: Type) -> UID {
|
||||||
|
let uid = format!("$$tmp{}", self.tmp_num);
|
||||||
|
self.push(IR::New {
|
||||||
|
uid: uid.clone(),
|
||||||
|
type_,
|
||||||
|
mutable: true,
|
||||||
|
global: false,
|
||||||
|
});
|
||||||
|
self.tmp_num += 1;
|
||||||
|
uid
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn statement(&mut self, stmt: Statement) {
|
||||||
use StatementKind as s;
|
use StatementKind as s;
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
s::Declaration {
|
s::Declaration {
|
||||||
name,
|
|
||||||
type_str,
|
|
||||||
type_actual,
|
type_actual,
|
||||||
value,
|
value,
|
||||||
mutable,
|
mutable,
|
||||||
uid,
|
uid,
|
||||||
} => self.push(IR::New {
|
..
|
||||||
|
} => {
|
||||||
|
let global = self.table.table.get(&uid).unwrap().global;
|
||||||
|
match type_actual {
|
||||||
|
Type::Prim(_) | Type::Struct(_) => {
|
||||||
|
self.push(IR::New {
|
||||||
|
uid: uid.clone(),
|
||||||
|
type_: type_actual.clone(),
|
||||||
|
mutable,
|
||||||
|
global,
|
||||||
|
});
|
||||||
|
self.expression(value);
|
||||||
|
self.push(IR::Set {
|
||||||
uid,
|
uid,
|
||||||
type_: type_actual,
|
type_: type_actual,
|
||||||
}),
|
global,
|
||||||
s::Assignment { name, value, uid } => todo!(),
|
});
|
||||||
|
},
|
||||||
|
Type::Nothing | Type::Function(_) | Type::Alias(_) => {
|
||||||
|
self.expression(value);
|
||||||
|
},
|
||||||
|
Type::Ambiguous => unreachable!(),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
s::Assignment { name, value, uid } => {
|
||||||
|
let global = self.table.table.get(&uid).unwrap().global;
|
||||||
|
let type_ = value.type_.clone();
|
||||||
|
self.expression(value);
|
||||||
|
self.push(IR::Set { uid, type_, global });
|
||||||
|
},
|
||||||
s::If {
|
s::If {
|
||||||
predicate,
|
predicate,
|
||||||
block,
|
block,
|
||||||
else_,
|
else_,
|
||||||
} => todo!(),
|
} => todo!(),
|
||||||
s::While { predicate, block } => todo!(),
|
s::While { predicate, block } => todo!(),
|
||||||
s::Print(expression) => todo!(),
|
s::Print(expression) => {
|
||||||
s::Expression(expression) => todo!(),
|
let type_ = expression.type_.clone();
|
||||||
s::Block(vec) => todo!(),
|
self.expression(expression);
|
||||||
s::Return(expression) => todo!(),
|
self.push(IR::Print { type_ });
|
||||||
s::Error(diagnostic) => todo!(),
|
},
|
||||||
|
s::Expression(expression) => {
|
||||||
|
let type_ = expression.type_.clone();
|
||||||
|
self.expression(expression);
|
||||||
|
self.push(IR::Drop { type_ });
|
||||||
|
},
|
||||||
|
s::Block(block) => {
|
||||||
|
for s in block {
|
||||||
|
self.statement(s);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
s::Return(expression) => {
|
||||||
|
let type_ = if let Some(expression) = expression {
|
||||||
|
let type_ = expression.type_.clone();
|
||||||
|
self.expression(expression);
|
||||||
|
type_
|
||||||
|
} else {
|
||||||
|
Type::Nothing
|
||||||
|
};
|
||||||
|
self.push(IR::Return { type_ });
|
||||||
|
},
|
||||||
|
s::Error(diagnostic) => {
|
||||||
|
panic!("{diagnostic}")
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression(&mut self, expr: Expression) {
|
pub fn expression(&mut self, expr: Expression) {
|
||||||
use ExpressionKind as e;
|
use ExpressionKind as e;
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
e::Immediate(immediate) => {
|
e::Immediate(immediate) => {
|
||||||
|
@ -44,8 +108,14 @@ impl Compiler {
|
||||||
prim: p,
|
prim: p,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
e::Identifier(_, uid) => {
|
e::Identifier(_, uid) => match expr.type_ {
|
||||||
self.push(IR::Get { uid });
|
Type::Prim(_) | Type::Struct(_) => self.push(IR::Get {
|
||||||
|
global: self.table.table.get(&uid).unwrap().global,
|
||||||
|
uid,
|
||||||
|
type_: expr.type_,
|
||||||
|
}),
|
||||||
|
Type::Ambiguous => unreachable!(),
|
||||||
|
_ => {},
|
||||||
},
|
},
|
||||||
e::Binary { op, left, right } => {
|
e::Binary { op, left, right } => {
|
||||||
self.expression(*left);
|
self.expression(*left);
|
||||||
|
@ -65,14 +135,17 @@ impl Compiler {
|
||||||
e::Parenthesis(inner) => self.expression(*inner),
|
e::Parenthesis(inner) => self.expression(*inner),
|
||||||
e::FunctionDef {
|
e::FunctionDef {
|
||||||
params,
|
params,
|
||||||
returns_str,
|
|
||||||
returns_actual,
|
returns_actual,
|
||||||
body,
|
body,
|
||||||
id,
|
id,
|
||||||
|
..
|
||||||
} => {
|
} => {
|
||||||
self.push(IR::StartFunc {
|
self.push(IR::StartFunc {
|
||||||
fid: id,
|
uid: id,
|
||||||
params: params.into_iter().map(|p| p.type_actual).collect(),
|
params: params
|
||||||
|
.into_iter()
|
||||||
|
.map(|p| (p.name, p.type_actual))
|
||||||
|
.collect(),
|
||||||
returns: returns_actual,
|
returns: returns_actual,
|
||||||
});
|
});
|
||||||
for s in body {
|
for s in body {
|
||||||
|
@ -83,24 +156,93 @@ impl Compiler {
|
||||||
e::FunctionCall {
|
e::FunctionCall {
|
||||||
callee, args, id, ..
|
callee, args, id, ..
|
||||||
} => {
|
} => {
|
||||||
for arg in args {
|
self.expression(*callee);
|
||||||
|
for arg in args.into_iter().rev() {
|
||||||
self.expression(arg);
|
self.expression(arg);
|
||||||
}
|
}
|
||||||
let fid = if let Type::Function(fid) = expr.type_ {
|
self.push(IR::Call { uid: id })
|
||||||
fid
|
},
|
||||||
|
e::StructDef(..) => {},
|
||||||
|
e::StructLiteral { args, .. } => {
|
||||||
|
let struct_id = if let Type::Struct(s) = expr.type_ {
|
||||||
|
s
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
self.push(IR::Call { fid })
|
let length = args.len();
|
||||||
},
|
let mut temp_buffer = vec![None; length];
|
||||||
e::StructDef(..) => {},
|
let mut iter = args.into_iter();
|
||||||
e::StructLiteral { name, args, id } => {},
|
let mut index = length - 1;
|
||||||
e::Field {
|
loop {
|
||||||
namespace,
|
// If struct param has already been saved
|
||||||
field,
|
if let Some((uid, type_)) = temp_buffer[index].take() {
|
||||||
|
self.ir.push(IR::Get {
|
||||||
uid,
|
uid,
|
||||||
|
type_,
|
||||||
|
global: false,
|
||||||
|
});
|
||||||
|
if index == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
index -= 1;
|
||||||
|
}
|
||||||
|
// If struct parameter has not been saved
|
||||||
|
else {
|
||||||
|
let (name, arg) = iter.next().unwrap();
|
||||||
|
let type_ = arg.type_.clone();
|
||||||
|
self.expression(arg);
|
||||||
|
let argno = self.table.get_field_no(struct_id, &name);
|
||||||
|
if argno != index {
|
||||||
|
let temp = self.new_temporary(type_.clone());
|
||||||
|
temp_buffer[argno] = Some((temp.clone(), type_.clone()));
|
||||||
|
self.push(IR::Set {
|
||||||
|
uid: temp,
|
||||||
|
type_: type_.clone(),
|
||||||
|
global: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if index == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
index -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
e::Field {
|
||||||
|
namespace, field, ..
|
||||||
} => {
|
} => {
|
||||||
|
if let Type::Struct(sid) = namespace.type_ {
|
||||||
self.expression(*namespace);
|
self.expression(*namespace);
|
||||||
|
let name = if let e::Identifier(name, _) = field.kind {
|
||||||
|
name
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
// TODO extract field
|
||||||
|
let field_type = self.table.get_field(sid, &name).unwrap();
|
||||||
|
let temp = self.new_temporary(field_type.clone());
|
||||||
|
for (field_name, uid) in self.table.structs[sid].0.clone() {
|
||||||
|
let type_ =
|
||||||
|
self.table.resolve_type(&uid).unwrap().is_alias().unwrap();
|
||||||
|
if field_name != name {
|
||||||
|
self.push(IR::Drop { type_ });
|
||||||
|
} else {
|
||||||
|
self.push(IR::Set {
|
||||||
|
uid: temp.clone(),
|
||||||
|
type_: field_type.clone(),
|
||||||
|
global: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.push(IR::Get {
|
||||||
|
uid: temp,
|
||||||
|
type_: field_type.clone(),
|
||||||
|
global: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.expression(*namespace);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
372
src/ir/mod.rs
372
src/ir/mod.rs
|
@ -1,9 +1,11 @@
|
||||||
mod generate;
|
mod generate;
|
||||||
pub use generate::*;
|
mod wasm;
|
||||||
|
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BinaryOp, Immediate, UnaryOp,
|
BinaryOp, Immediate, Statement, UnaryOp,
|
||||||
semantic::{FID, Primitive, Type, UID},
|
semantic::{Primitive, SymbolTable, Type, UID},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -23,27 +25,34 @@ pub enum IR {
|
||||||
New {
|
New {
|
||||||
uid: UID,
|
uid: UID,
|
||||||
type_: Type,
|
type_: Type,
|
||||||
|
mutable: bool,
|
||||||
|
global: bool,
|
||||||
},
|
},
|
||||||
Set {
|
Set {
|
||||||
uid: UID,
|
uid: UID,
|
||||||
|
type_: Type,
|
||||||
|
global: bool,
|
||||||
},
|
},
|
||||||
Get {
|
Get {
|
||||||
uid: UID,
|
uid: UID,
|
||||||
|
type_: Type,
|
||||||
|
global: bool,
|
||||||
},
|
},
|
||||||
StartFunc {
|
StartFunc {
|
||||||
fid: FID,
|
uid: UID,
|
||||||
params: Vec<Type>,
|
params: Vec<(UID, Type)>,
|
||||||
returns: Type,
|
returns: Type,
|
||||||
},
|
},
|
||||||
EndFunc,
|
EndFunc,
|
||||||
ReturnType {
|
Return {
|
||||||
type_: Type,
|
type_: Type,
|
||||||
},
|
},
|
||||||
Return,
|
|
||||||
Call {
|
Call {
|
||||||
fid: FID,
|
uid: UID,
|
||||||
|
},
|
||||||
|
Drop {
|
||||||
|
type_: Type,
|
||||||
},
|
},
|
||||||
Drop,
|
|
||||||
Print {
|
Print {
|
||||||
type_: Type,
|
type_: Type,
|
||||||
},
|
},
|
||||||
|
@ -56,23 +65,28 @@ 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})"),
|
||||||
New { uid, type_ } => write!(f, "local ${uid} = {type_}"),
|
New {
|
||||||
Set { uid } => write!(f, "pop local ${uid}"),
|
uid,
|
||||||
Get { uid } => write!(f, "push local ${uid}"),
|
type_,
|
||||||
|
mutable,
|
||||||
|
..
|
||||||
|
} => write!(
|
||||||
|
f,
|
||||||
|
"let {}{uid} : {type_}",
|
||||||
|
if *mutable { "mut " } else { "" }
|
||||||
|
),
|
||||||
|
Set { uid, .. } => write!(f, "set local {uid}"),
|
||||||
|
Get { uid, .. } => write!(f, "get local {uid}"),
|
||||||
StartFunc {
|
StartFunc {
|
||||||
uid,
|
uid,
|
||||||
params,
|
params,
|
||||||
returns,
|
returns,
|
||||||
} => write!(
|
} => write!(f, "<function id={uid} params={params:?} returns={returns}>"),
|
||||||
f,
|
|
||||||
"<function id=${uid} params={params:?} returns={returns}>"
|
|
||||||
),
|
|
||||||
EndFunc => write!(f, "</function>"),
|
EndFunc => write!(f, "</function>"),
|
||||||
Return => write!(f, "return"),
|
Call { uid } => write!(f, "call {uid}"),
|
||||||
Call { uid } => write!(f, "call ${uid}"),
|
Return { type_ } => write!(f, "result {type_}"),
|
||||||
Drop => write!(f, "pop"),
|
|
||||||
ReturnType { type_ } => write!(f, "result {type_}"),
|
|
||||||
Print { type_ } => write!(f, "print {type_} [DEBUG]"),
|
Print { type_ } => write!(f, "print {type_} [DEBUG]"),
|
||||||
|
Drop { .. } => write!(f, "pop"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,276 +94,53 @@ impl std::fmt::Display for IR {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Compiler {
|
pub struct Compiler {
|
||||||
ir: Vec<IR>,
|
ir: Vec<IR>,
|
||||||
|
table: SymbolTable,
|
||||||
|
tmp_num: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Compiler {
|
impl Compiler {
|
||||||
pub fn new() -> Self {
|
pub fn new(table: SymbolTable) -> Self {
|
||||||
Self { ir: vec![] }
|
Self {
|
||||||
|
ir: vec![],
|
||||||
|
table,
|
||||||
|
tmp_num: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile(&mut self, statements: Vec<Statement>) {
|
||||||
|
self.generate(statements);
|
||||||
|
self.hoist();
|
||||||
|
for ir in &self.ir {
|
||||||
|
println!("{ir}");
|
||||||
|
}
|
||||||
|
let mut s = String::new();
|
||||||
|
for ir in &self.ir {
|
||||||
|
s.push_str(&self.ir_to_wat(ir.clone()).unwrap());
|
||||||
|
}
|
||||||
|
let assembly = format!("(module\n{s})");
|
||||||
|
println!("--------");
|
||||||
|
println!("{assembly}");
|
||||||
|
std::fs::File::create("test.wat")
|
||||||
|
.unwrap()
|
||||||
|
.write_all(assembly.as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
let binary = wat::parse_str(assembly).unwrap();
|
||||||
|
std::fs::File::create("test.wasm")
|
||||||
|
.unwrap()
|
||||||
|
.write_all(&binary)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, ir: IR) {
|
pub fn push(&mut self, ir: IR) {
|
||||||
self.ir.push(ir);
|
self.ir.push(ir);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
fn hoist(&mut self) {
|
||||||
impl IR {
|
// Declarations, instructions
|
||||||
pub fn to_wat(&self) -> String {
|
|
||||||
use BinaryOp as b;
|
|
||||||
use IR::*;
|
|
||||||
use Primitive as p;
|
|
||||||
use Type as t;
|
|
||||||
match self {
|
|
||||||
// Primitive
|
|
||||||
BinOp {
|
|
||||||
op,
|
|
||||||
type_: t::Prim(p),
|
|
||||||
} => match (op, p) {
|
|
||||||
// Addition
|
|
||||||
(b::Plus, p::i32 | p::w32 | p::integer | p::whole) => "i32.add",
|
|
||||||
(b::Plus, p::i64 | p::w64) => "i64.add",
|
|
||||||
(b::Plus, p::r32) => "f32.add",
|
|
||||||
(b::Plus, p::r64) => "f64.add",
|
|
||||||
// Subtraction
|
|
||||||
(b::Minus, p::i32 | p::w32 | p::integer | p::whole) => "i32.sub",
|
|
||||||
(b::Minus, p::i64 | p::w64) => "i64.sub",
|
|
||||||
(b::Minus, p::r32) => "f32.sub",
|
|
||||||
(b::Minus, p::r64) => "f64.sub",
|
|
||||||
// Multiplication
|
|
||||||
(b::Star, p::i32 | p::w32 | p::integer | p::whole) => "i32.mul",
|
|
||||||
(b::Star, p::i64 | p::w64) => "i64.mul",
|
|
||||||
(b::Star, p::r32) => "f32.mul",
|
|
||||||
(b::Star, p::r64) => "f64.mul",
|
|
||||||
// Division
|
|
||||||
(b::Slash, p::i32 | p::integer) => "i32.div_s",
|
|
||||||
(b::Slash, p::w32 | p::whole) => "i32.div_u",
|
|
||||||
(b::Slash, p::i64) => "i64.div_s",
|
|
||||||
(b::Slash, p::w64) => "i64.div_u",
|
|
||||||
(b::Slash, p::r32) => "f32.div",
|
|
||||||
(b::Slash, p::r64) => "f64.div",
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
UnOp {
|
|
||||||
op,
|
|
||||||
type_: t::Prim(p),
|
|
||||||
} => todo!(),
|
|
||||||
Push { prim, value } => todo!(),
|
|
||||||
NewLocal {
|
|
||||||
uid,
|
|
||||||
type_: t::Prim(p),
|
|
||||||
} => format!("(local ${uid} {})", p.as_wat()),
|
|
||||||
AssignLocal { uid } => format!("local.set ${uid}"),
|
|
||||||
GetLocal { uid } => format!("local.get ${uid}"),
|
|
||||||
NewGlobal {
|
|
||||||
uid,
|
|
||||||
type_: t::Prim(p),
|
|
||||||
} => format!(
|
|
||||||
"(global ${uid} (mut {}) ({}.const 0))",
|
|
||||||
p.as_wat(),
|
|
||||||
p.as_wat()
|
|
||||||
),
|
|
||||||
AssignGlobal { uid } => format!("global.set ${uid}"),
|
|
||||||
GetGlobal { uid } => format!("global.get ${uid}"),
|
|
||||||
StartFunc { uid } => format!("(func ${uid}"),
|
|
||||||
EndFunc => ")".into(),
|
|
||||||
ReturnType { type_: t::Prim(p) } => format!("(result {})", p.as_wat()),
|
|
||||||
NewParam {
|
|
||||||
uid,
|
|
||||||
type_: t::Prim(p),
|
|
||||||
} => format!("(param ${uid} {})", p.as_wat()),
|
|
||||||
Return => "return".into(),
|
|
||||||
Call { uid } => format!("call ${uid}"),
|
|
||||||
Drop => "drop".into(),
|
|
||||||
Print => "call $log".into(),
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Compiler {
|
|
||||||
pub ir: Vec<IR>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Compiler {
|
|
||||||
const IMPORTS: &'static str =
|
|
||||||
r#"(import "console" "log" (func $log (param i32)))"#;
|
|
||||||
|
|
||||||
pub fn compile(block: Vec<Statement>) -> (Vec<u8>, String) {
|
|
||||||
let mut this = Self { ir: vec![] };
|
|
||||||
for s in block {
|
|
||||||
this.statement(s);
|
|
||||||
}
|
|
||||||
this.ir = this.hoist();
|
|
||||||
let mut output = String::new();
|
|
||||||
for ir in &this.ir {
|
|
||||||
//println!("{ir}");
|
|
||||||
let s = ir.to_wat();
|
|
||||||
output.push_str(&format!("{s}\n"));
|
|
||||||
}
|
|
||||||
output = format!("(module\n{}\n{output}\n(start $0)\n)", Self::IMPORTS);
|
|
||||||
println!("{output}");
|
|
||||||
(wat::parse_str(&output).unwrap(), output)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn statement(&mut self, statement: Statement) {
|
|
||||||
use StatementKind::*;
|
|
||||||
match statement.kind {
|
|
||||||
Declaration {
|
|
||||||
type_actual,
|
|
||||||
value,
|
|
||||||
varkind,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
match varkind {
|
|
||||||
VarKind::Global(uid) => self.ir.push(IR::NewGlobal {
|
|
||||||
uid,
|
|
||||||
type_: type_actual,
|
|
||||||
}),
|
|
||||||
VarKind::Local(uid) => self.ir.push(IR::NewLocal {
|
|
||||||
uid,
|
|
||||||
type_: type_actual,
|
|
||||||
}),
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
self.expression(value);
|
|
||||||
match varkind {
|
|
||||||
VarKind::Global(uid) => self.ir.push(IR::AssignGlobal { uid }),
|
|
||||||
VarKind::Local(uid) => self.ir.push(IR::AssignLocal { uid }),
|
|
||||||
_ => {},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
Assignment {
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
varkind,
|
|
||||||
} => {
|
|
||||||
self.expression(value);
|
|
||||||
match varkind {
|
|
||||||
VarKind::Global(uid) => self.ir.push(IR::AssignGlobal { uid }),
|
|
||||||
VarKind::Local(uid) => self.ir.push(IR::AssignLocal { uid }),
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
If {
|
|
||||||
predicate,
|
|
||||||
block,
|
|
||||||
else_,
|
|
||||||
} => todo!(),
|
|
||||||
While { predicate, block } => todo!(),
|
|
||||||
Print(expression) => {
|
|
||||||
self.expression(expression);
|
|
||||||
self.ir.push(IR::Print);
|
|
||||||
},
|
|
||||||
Expression(expression) => {
|
|
||||||
if expression.type_ == Type::Nothing {
|
|
||||||
self.expression(expression);
|
|
||||||
} else {
|
|
||||||
self.expression(expression);
|
|
||||||
self.ir.push(IR::Drop);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Block(statements) => {
|
|
||||||
for s in statements {
|
|
||||||
self.statement(s);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Error(diagnostic) => {
|
|
||||||
panic!("{}", diagnostic);
|
|
||||||
},
|
|
||||||
Return(expression) => {
|
|
||||||
if let Some(e) = expression {
|
|
||||||
self.expression(e);
|
|
||||||
}
|
|
||||||
self.ir.push(IR::Return);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expression(&mut self, expression: Expression) {
|
|
||||||
use ExpressionKind::*;
|
|
||||||
match expression.kind {
|
|
||||||
Immediate(immediate) => {
|
|
||||||
let Type::Prim(p) = expression.type_ else {
|
|
||||||
panic!();
|
|
||||||
};
|
|
||||||
self.ir.push(IR::Push {
|
|
||||||
value: immediate,
|
|
||||||
prim: p,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
Identifier(_, var_kind) => match var_kind {
|
|
||||||
VarKind::Global(uid) => self.ir.push(IR::GetGlobal { uid }),
|
|
||||||
VarKind::Local(uid) => self.ir.push(IR::GetLocal { uid }),
|
|
||||||
VarKind::Function(_) => {},
|
|
||||||
VarKind::Undefined => panic!("Undefined var not caught by typecheck"),
|
|
||||||
},
|
|
||||||
Binary {
|
|
||||||
op,
|
|
||||||
mut left,
|
|
||||||
mut right,
|
|
||||||
} => {
|
|
||||||
assert!(&left.type_ == &right.type_);
|
|
||||||
self.expression(*left.clone());
|
|
||||||
self.expression(*right);
|
|
||||||
self.ir.push(IR::BinOp {
|
|
||||||
op,
|
|
||||||
type_: expression.type_,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
Unary { op, mut child } => {
|
|
||||||
self.expression(*child);
|
|
||||||
self.ir.push(IR::UnOp {
|
|
||||||
op,
|
|
||||||
type_: expression.type_,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
Parenthesis(mut e) => {
|
|
||||||
self.expression(*e);
|
|
||||||
},
|
|
||||||
FunctionDef {
|
|
||||||
params,
|
|
||||||
returns_actual,
|
|
||||||
body,
|
|
||||||
id,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
self.ir.push(IR::StartFunc { uid: id });
|
|
||||||
for (i, p) in params.iter().enumerate() {
|
|
||||||
self.ir.push(IR::NewParam {
|
|
||||||
uid: i as uid,
|
|
||||||
type_: p.type_actual.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
self.ir.push(IR::ReturnType {
|
|
||||||
type_: returns_actual,
|
|
||||||
});
|
|
||||||
for s in body {
|
|
||||||
self.statement(s);
|
|
||||||
}
|
|
||||||
self.ir.push(IR::EndFunc);
|
|
||||||
},
|
|
||||||
FunctionCall { callee, args } => {
|
|
||||||
let Type::FunctionDef { id, .. } = callee.type_ else {
|
|
||||||
panic!()
|
|
||||||
};
|
|
||||||
for arg in args {
|
|
||||||
self.expression(arg);
|
|
||||||
}
|
|
||||||
self.ir.push(IR::Call { uid: id });
|
|
||||||
},
|
|
||||||
StructDef(_) => {},
|
|
||||||
StructLiteral { name, args } => todo!(),
|
|
||||||
Field { namespace, field } => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hoist(&self) -> Vec<IR> {
|
|
||||||
let mut functions = vec![(vec![], vec![])];
|
let mut functions = vec![(vec![], vec![])];
|
||||||
|
// Final IR output
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
for index in 0..self.ir.len() {
|
for ir in &self.ir {
|
||||||
let ir = self.ir.get(index).unwrap();
|
|
||||||
match ir {
|
match ir {
|
||||||
IR::StartFunc { .. } => {
|
IR::StartFunc { .. } => {
|
||||||
functions.push((vec![], vec![]));
|
functions.push((vec![], vec![]));
|
||||||
|
@ -370,10 +161,7 @@ impl Compiler {
|
||||||
// Push instruction to correct stack
|
// Push instruction to correct stack
|
||||||
let (inits, instr) = functions.last_mut().unwrap();
|
let (inits, instr) = functions.last_mut().unwrap();
|
||||||
match ir {
|
match ir {
|
||||||
IR::NewLocal { .. }
|
IR::New { .. } | IR::StartFunc { .. } => {
|
||||||
| IR::NewGlobal { .. }
|
|
||||||
| IR::NewParam { .. }
|
|
||||||
| IR::StartFunc { .. } => {
|
|
||||||
inits.push(ir.clone());
|
inits.push(ir.clone());
|
||||||
},
|
},
|
||||||
_ => instr.push(ir.clone()),
|
_ => instr.push(ir.clone()),
|
||||||
|
@ -381,16 +169,28 @@ impl Compiler {
|
||||||
}
|
}
|
||||||
// Initialize globals
|
// Initialize globals
|
||||||
let (inits, instr) = functions.pop().unwrap();
|
let (inits, instr) = functions.pop().unwrap();
|
||||||
|
let mut main_locals = vec![];
|
||||||
for ir in inits {
|
for ir in inits {
|
||||||
|
match ir {
|
||||||
|
IR::New { global: true, .. } => {
|
||||||
result.push(ir);
|
result.push(ir);
|
||||||
|
},
|
||||||
|
_ => main_locals.push(ir),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// The main function (index 0)
|
// The main function (index 0)
|
||||||
result.push(IR::StartFunc { uid: 0 });
|
result.push(IR::StartFunc {
|
||||||
|
uid: "$$main".into(),
|
||||||
|
params: vec![],
|
||||||
|
returns: Type::Nothing,
|
||||||
|
});
|
||||||
|
for ir in main_locals {
|
||||||
|
result.push(ir);
|
||||||
|
}
|
||||||
for ir in instr {
|
for ir in instr {
|
||||||
result.push(ir);
|
result.push(ir);
|
||||||
}
|
}
|
||||||
result.push(IR::EndFunc);
|
result.push(IR::EndFunc);
|
||||||
result
|
self.ir = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
211
src/ir/wasm.rs
Normal file
211
src/ir/wasm.rs
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
use crate::{
|
||||||
|
Base, BinaryOp, Immediate,
|
||||||
|
err::*,
|
||||||
|
semantic::{Primitive, Type},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{Compiler, IR};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub enum RegisterType {
|
||||||
|
f32,
|
||||||
|
f64,
|
||||||
|
i32,
|
||||||
|
i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for RegisterType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", match self {
|
||||||
|
RegisterType::f32 => "f32",
|
||||||
|
RegisterType::f64 => "f64",
|
||||||
|
RegisterType::i32 => "i32",
|
||||||
|
RegisterType::i64 => "i64",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SYS_INT: RegisterType = RegisterType::i32;
|
||||||
|
const SYS_REAL: RegisterType = RegisterType::f32;
|
||||||
|
|
||||||
|
fn convert_sys_whole(input: &str, base: Base) -> Option<String> {
|
||||||
|
u32::from_str_radix(input, base as u32)
|
||||||
|
.ok()
|
||||||
|
.map(|i| format!("{i}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_sys_int(input: &str, base: Base) -> Option<String> {
|
||||||
|
i32::from_str_radix(input, base as u32)
|
||||||
|
.ok()
|
||||||
|
.map(|i| format!("{i}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_sys_real(input: &str) -> Option<String> {
|
||||||
|
input.parse::<f32>().ok().map(|f| format!("{f}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Compiler {
|
||||||
|
pub fn type_prim(&self, prim: Primitive) -> RegisterType {
|
||||||
|
use Primitive as p;
|
||||||
|
use RegisterType as r;
|
||||||
|
match prim {
|
||||||
|
p::i8 | p::i16 | p::i32 | p::w8 | p::w16 | p::w32 => r::i32,
|
||||||
|
p::i64 | p::w64 => r::i64,
|
||||||
|
p::integer | p::whole => SYS_INT,
|
||||||
|
p::r32 => r::f32,
|
||||||
|
p::r64 => r::f64,
|
||||||
|
p::real => SYS_REAL,
|
||||||
|
p::boolean => r::i32,
|
||||||
|
p::string => r::i64,
|
||||||
|
p::glyph => r::i32,
|
||||||
|
p::integer_ambiguous | p::real_ambiguous => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn splat(&self, type_: &Type) -> Vec<RegisterType> {
|
||||||
|
match type_ {
|
||||||
|
Type::Ambiguous => unreachable!(),
|
||||||
|
Type::Function(_) | Type::Nothing | Type::Alias(_) => vec![],
|
||||||
|
Type::Prim(prim) => vec![self.type_prim(*prim)],
|
||||||
|
Type::Struct(sid) => {
|
||||||
|
let struct_def = &self.table.structs[*sid].0;
|
||||||
|
let mut buf = vec![];
|
||||||
|
for (_, type_) in struct_def {
|
||||||
|
let type_ =
|
||||||
|
self.table.resolve_type(type_).unwrap().is_alias().unwrap();
|
||||||
|
buf.append(&mut self.splat(&type_));
|
||||||
|
}
|
||||||
|
buf
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ir_to_wat(&self, ir: IR) -> Result<String> {
|
||||||
|
use Immediate as i;
|
||||||
|
use Primitive as p;
|
||||||
|
Ok(match ir {
|
||||||
|
IR::Push { value, prim } => match value {
|
||||||
|
i::Integer(ref i, base) => {
|
||||||
|
let b = base as u32;
|
||||||
|
// Unfortunately this can't be simplified
|
||||||
|
let s = match prim {
|
||||||
|
p::w8 => u8::from_str_radix(i, b).ok().map(|s| format!("{s}")),
|
||||||
|
p::w16 => u16::from_str_radix(i, b).ok().map(|s| format!("{s}")),
|
||||||
|
p::w32 => u32::from_str_radix(i, b).ok().map(|s| format!("{s}")),
|
||||||
|
p::w64 => u64::from_str_radix(i, b).ok().map(|s| format!("{s}")),
|
||||||
|
p::i8 => i8::from_str_radix(i, b).ok().map(|s| format!("{s}")),
|
||||||
|
p::i16 => i16::from_str_radix(i, b).ok().map(|s| format!("{s}")),
|
||||||
|
p::i32 => i32::from_str_radix(i, b).ok().map(|s| format!("{s}")),
|
||||||
|
p::i64 => i64::from_str_radix(i, b).ok().map(|s| format!("{s}")),
|
||||||
|
p::whole => convert_sys_whole(i, base),
|
||||||
|
p::integer => convert_sys_int(i, base),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
.reason(format!("Cannot parse immediate value as '{}'", prim))?;
|
||||||
|
format!("{}.const {}\n", self.type_prim(prim), s)
|
||||||
|
},
|
||||||
|
i::Real(ref i) => {
|
||||||
|
let s = match prim {
|
||||||
|
p::r32 => i.parse::<f32>().ok().map(|f| format!("{f}")),
|
||||||
|
p::r64 => i.parse::<f64>().ok().map(|f| format!("{f}")),
|
||||||
|
p::real => convert_sys_real(i),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
.reason(format!("Cannot parse immediate value as '{}'", prim))?;
|
||||||
|
format!("{}.const {}\n", self.type_prim(prim), s)
|
||||||
|
},
|
||||||
|
i::String(_) => todo!(),
|
||||||
|
i::Glyph(c) => format!("i32.const {}\n", c as u32),
|
||||||
|
i::Boolean(b) => format!("i32.const {}\n", b as i8),
|
||||||
|
},
|
||||||
|
IR::Drop { type_ } => {
|
||||||
|
let mut buffer = String::new();
|
||||||
|
for _ in 0..self.splat(&type_).len() {
|
||||||
|
buffer.push_str("drop\n");
|
||||||
|
}
|
||||||
|
buffer
|
||||||
|
},
|
||||||
|
IR::New {
|
||||||
|
uid,
|
||||||
|
type_,
|
||||||
|
mutable,
|
||||||
|
global,
|
||||||
|
} => {
|
||||||
|
let mut buffer = String::new();
|
||||||
|
for (index, rt) in self.splat(&type_).iter().enumerate() {
|
||||||
|
buffer.push_str(&format!(
|
||||||
|
"({} {uid}${index} {})\n",
|
||||||
|
if global { "global" } else { "local" },
|
||||||
|
if global && mutable {
|
||||||
|
format!("(mut {rt})")
|
||||||
|
} else {
|
||||||
|
format!("{rt}")
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
buffer
|
||||||
|
},
|
||||||
|
IR::Set { uid, type_, global } => {
|
||||||
|
let mut buffer = String::new();
|
||||||
|
for index in 0..self.splat(&type_).len() {
|
||||||
|
buffer.push_str(&format!(
|
||||||
|
"{}.set {uid}${index}\n",
|
||||||
|
if global { "global" } else { "local" }
|
||||||
|
))
|
||||||
|
}
|
||||||
|
buffer
|
||||||
|
},
|
||||||
|
IR::Get { uid, type_, global } => {
|
||||||
|
let mut buffer = String::new();
|
||||||
|
for index in (0..self.splat(&type_).len()).rev() {
|
||||||
|
buffer.push_str(&format!(
|
||||||
|
"{}.get {uid}${index}\n",
|
||||||
|
if global { "global" } else { "local" }
|
||||||
|
))
|
||||||
|
}
|
||||||
|
buffer
|
||||||
|
},
|
||||||
|
IR::StartFunc {
|
||||||
|
uid,
|
||||||
|
params,
|
||||||
|
returns,
|
||||||
|
} => {
|
||||||
|
let mut buffer = format!("(func {uid}\n");
|
||||||
|
for (puid, type_) in params {
|
||||||
|
for (id, rt) in self.splat(&type_).iter().enumerate() {
|
||||||
|
buffer.push_str(&format!("(param {puid}${id} {rt})\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let returns = self.splat(&returns);
|
||||||
|
if returns.len() > 0 {
|
||||||
|
buffer.push_str("(result ");
|
||||||
|
for rt in returns {
|
||||||
|
buffer.push_str(&format!("{rt} "))
|
||||||
|
}
|
||||||
|
buffer.push_str(")\n");
|
||||||
|
}
|
||||||
|
buffer
|
||||||
|
},
|
||||||
|
IR::EndFunc => ")\n".into(),
|
||||||
|
IR::Return { type_ } => "return\n".into(),
|
||||||
|
IR::Call { uid } => format!("call {uid}\n"),
|
||||||
|
IR::BinOp { op, type_ } => {
|
||||||
|
use BinaryOp::*;
|
||||||
|
let p = if let Type::Prim(p) = type_ {
|
||||||
|
p
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
match (op, p) {
|
||||||
|
(Plus, _) => format!("{}.add\n", self.type_prim(p)),
|
||||||
|
(Minus, _) => format!("{}.sub\n", self.type_prim(p)),
|
||||||
|
(Star, _) => format!("{}.mul\n", self.type_prim(p)),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IR::UnOp { op, type_ } => todo!(),
|
||||||
|
IR::Print { type_ } => todo!(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
14
src/main.rs
14
src/main.rs
|
@ -1,5 +1,4 @@
|
||||||
mod err;
|
mod err;
|
||||||
mod frontend;
|
|
||||||
mod ir;
|
mod ir;
|
||||||
mod lookahead;
|
mod lookahead;
|
||||||
mod parse;
|
mod parse;
|
||||||
|
@ -9,6 +8,7 @@ mod treewalk;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
|
|
||||||
use err::*;
|
use err::*;
|
||||||
|
use ir::Compiler;
|
||||||
use lookahead::*;
|
use lookahead::*;
|
||||||
use parse::*;
|
use parse::*;
|
||||||
use semantic::Analyzer;
|
use semantic::Analyzer;
|
||||||
|
@ -95,14 +95,24 @@ fn parse(input: &'static str) -> impl Iterator<Item = Statement> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typecheck(input: &'static str) -> Vec<Statement> {
|
fn typecheck(input: &'static str) -> Vec<Statement> {
|
||||||
Analyzer::typecheck(parse(input).collect())
|
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 main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
/*
|
||||||
for s in typecheck(include_str!("../demo.hal")) {
|
for s in typecheck(include_str!("../demo.hal")) {
|
||||||
println!("------------------");
|
println!("------------------");
|
||||||
println!("{s:#?}");
|
println!("{s:#?}");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
compile(include_str!("../demo.hal"));
|
||||||
//let module = frontend::Module::from_file("./demo.hal")?;
|
//let module = frontend::Module::from_file("./demo.hal")?;
|
||||||
//module.write_to("test");
|
//module.write_to("test");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -36,7 +36,7 @@ impl std::fmt::Display for Immediate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ExpressionKind {
|
pub enum ExpressionKind {
|
||||||
Immediate(Immediate),
|
Immediate(Immediate),
|
||||||
Identifier(String, UID),
|
Identifier(String, UID),
|
||||||
|
@ -55,7 +55,7 @@ pub enum ExpressionKind {
|
||||||
returns_str: Option<String>,
|
returns_str: Option<String>,
|
||||||
returns_actual: Type,
|
returns_actual: Type,
|
||||||
body: Vec<Statement>,
|
body: Vec<Statement>,
|
||||||
id: usize,
|
id: UID,
|
||||||
},
|
},
|
||||||
FunctionCall {
|
FunctionCall {
|
||||||
callee: Box<Expression>,
|
callee: Box<Expression>,
|
||||||
|
@ -76,7 +76,7 @@ pub enum ExpressionKind {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Expression {
|
pub struct Expression {
|
||||||
pub kind: ExpressionKind,
|
pub kind: ExpressionKind,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
@ -89,7 +89,7 @@ impl Expression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for ExpressionKind {
|
impl std::fmt::Display for ExpressionKind {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
use ExpressionKind as e;
|
use ExpressionKind as e;
|
||||||
match self {
|
match self {
|
||||||
|
@ -99,27 +99,27 @@ impl std::fmt::Debug for ExpressionKind {
|
||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
} => {
|
} => {
|
||||||
write!(f, "({left:?} {token:?} {right:?})")
|
write!(f, "({left} {token} {right})")
|
||||||
},
|
},
|
||||||
e::Parenthesis(inner) => write!(f, "{inner:?}"),
|
e::Parenthesis(inner) => write!(f, "{inner}"),
|
||||||
e::Unary { op: token, child } => {
|
e::Unary { op: token, child } => {
|
||||||
write!(f, "({token:?} {child:?})")
|
write!(f, "({token} {child})")
|
||||||
},
|
},
|
||||||
e::Identifier(i, _) => write!(f, "{i}"),
|
e::Identifier(i, _) => write!(f, "{i}"),
|
||||||
e::FunctionCall { callee, args, .. } => {
|
e::FunctionCall { callee, args, .. } => {
|
||||||
write!(f, "({callee:?} call {args:?})")
|
write!(f, "({callee} call {args:?})")
|
||||||
},
|
},
|
||||||
e::Field {
|
e::Field {
|
||||||
namespace, field, ..
|
namespace, field, ..
|
||||||
} => {
|
} => {
|
||||||
write!(f, "({namespace:?} . {field:?})")
|
write!(f, "({namespace} . {field})")
|
||||||
},
|
},
|
||||||
e::FunctionDef {
|
e::FunctionDef {
|
||||||
params,
|
params,
|
||||||
returns_actual,
|
returns_actual,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
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:?} }}"),
|
||||||
|
@ -127,9 +127,9 @@ impl std::fmt::Debug for ExpressionKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Expression {
|
impl std::fmt::Display for Expression {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "({:?} {})", self.kind, self.type_)
|
write!(f, "({} {})", self.kind, self.type_)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +355,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
||||||
returns_str,
|
returns_str,
|
||||||
returns_actual: Type::Ambiguous,
|
returns_actual: Type::Ambiguous,
|
||||||
body,
|
body,
|
||||||
id: usize::MAX,
|
id: "".into(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Struct definition
|
// Struct definition
|
||||||
|
|
|
@ -5,25 +5,31 @@ pub struct Analyzer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Analyzer {
|
impl Analyzer {
|
||||||
pub fn typecheck(mut statements: Vec<Statement>) -> Vec<Statement> {
|
pub fn new() -> Self {
|
||||||
let mut this = Self {
|
Self {
|
||||||
table: SymbolTable::new(),
|
table: SymbolTable::new(),
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn typecheck(
|
||||||
|
&mut self,
|
||||||
|
mut statements: Vec<Statement>,
|
||||||
|
) -> Vec<Statement> {
|
||||||
for s in &mut statements {
|
for s in &mut statements {
|
||||||
*s = *this.naming_pass_stmt(s.clone().into()).unwrap();
|
*s = *self.naming_pass_stmt(s.clone().into()).unwrap();
|
||||||
}
|
}
|
||||||
for s in &mut statements {
|
for s in &mut statements {
|
||||||
*s = *this.bottom_up_stmt(s.clone().into()).unwrap();
|
*s = *self.bottom_up_stmt(s.clone().into()).unwrap();
|
||||||
}
|
}
|
||||||
for s in &mut statements {
|
for s in &mut statements {
|
||||||
*s = *this.top_down_stmt(s.clone().into()).unwrap();
|
*s = *self.top_down_stmt(s.clone().into()).unwrap();
|
||||||
}
|
}
|
||||||
println!("-----TABLE------");
|
println!("-----TABLE------");
|
||||||
println!("{:#?}", this.table.table);
|
println!("{:#?}", self.table.table);
|
||||||
println!("-----FUNCS------");
|
println!("-----FUNCS------");
|
||||||
println!("{:#?}", this.table.functions);
|
println!("{:#?}", self.table.functions);
|
||||||
println!("-----STRUCTS----");
|
println!("-----STRUCTS----");
|
||||||
println!("{:#?}", this.table.structs);
|
println!("{:#?}", self.table.structs);
|
||||||
statements
|
statements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ impl Analyzer {
|
||||||
Some(type_actual.clone()),
|
Some(type_actual.clone()),
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
self.table.in_global_scope(),
|
||||||
)?;
|
)?;
|
||||||
s::Declaration {
|
s::Declaration {
|
||||||
name,
|
name,
|
||||||
|
@ -62,6 +63,7 @@ impl Analyzer {
|
||||||
Some(value.type_.clone()),
|
Some(value.type_.clone()),
|
||||||
Some(true),
|
Some(true),
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
)?;
|
)?;
|
||||||
s::Assignment { name, value, uid }
|
s::Assignment { name, value, uid }
|
||||||
},
|
},
|
||||||
|
@ -170,18 +172,23 @@ impl Analyzer {
|
||||||
mut body,
|
mut body,
|
||||||
id,
|
id,
|
||||||
} => {
|
} => {
|
||||||
let funcdef = self.table.functions[id].clone();
|
let funcdef = self.table.functions.get(&id).unwrap().clone();
|
||||||
self.table.start_function();
|
self.table.start_function();
|
||||||
for (uid, param) in funcdef.params.iter().zip(params.iter_mut()) {
|
for (uid, param) in funcdef.params.iter().zip(params.iter_mut()) {
|
||||||
let type_ = self.table.resolve_type(uid).span(&expr.span)?;
|
let type_ = self.table.resolve_type(uid).span(&expr.span)?;
|
||||||
|
param.name = uid.clone();
|
||||||
param.type_actual = type_;
|
param.type_actual = type_;
|
||||||
}
|
}
|
||||||
for s in &mut body {
|
for s in &mut body {
|
||||||
*s = *self.bottom_up_stmt(s.clone().into())?;
|
*s = *self.bottom_up_stmt(s.clone().into())?;
|
||||||
}
|
}
|
||||||
self.table.end_function();
|
self.table.end_function();
|
||||||
returns_actual =
|
returns_actual = self
|
||||||
self.table.resolve_type(&funcdef.returns).span(&expr.span)?;
|
.table
|
||||||
|
.resolve_type(&funcdef.returns)
|
||||||
|
.span(&expr.span)?
|
||||||
|
.is_alias()
|
||||||
|
.span(&expr.span)?;
|
||||||
e::FunctionDef {
|
e::FunctionDef {
|
||||||
params,
|
params,
|
||||||
returns_str,
|
returns_str,
|
||||||
|
@ -194,14 +201,15 @@ impl Analyzer {
|
||||||
mut callee,
|
mut callee,
|
||||||
mut args,
|
mut args,
|
||||||
is_reference,
|
is_reference,
|
||||||
id,
|
mut id,
|
||||||
} => {
|
} => {
|
||||||
callee = self.bottom_up_expr(callee)?;
|
callee = self.bottom_up_expr(callee)?;
|
||||||
match callee.type_ {
|
match callee.type_ {
|
||||||
Type::Function(fid) => {
|
Type::Function(ref uid) => {
|
||||||
|
id = uid.clone();
|
||||||
expr.type_ = self
|
expr.type_ = self
|
||||||
.table
|
.table
|
||||||
.resolve_type(&self.table.functions[fid].returns)
|
.resolve_type(&self.table.functions.get(uid).unwrap().returns)
|
||||||
.span(&callee.span)?
|
.span(&callee.span)?
|
||||||
.is_alias()
|
.is_alias()
|
||||||
.span(&expr.span)?
|
.span(&expr.span)?
|
||||||
|
@ -247,10 +255,10 @@ impl Analyzer {
|
||||||
e::Field {
|
e::Field {
|
||||||
mut namespace,
|
mut namespace,
|
||||||
field,
|
field,
|
||||||
uid,
|
mut uid,
|
||||||
} => {
|
} => {
|
||||||
namespace = self.bottom_up_expr(namespace)?;
|
namespace = self.bottom_up_expr(namespace)?;
|
||||||
if let Type::Struct(s) = namespace.type_ {
|
let field_name = if let Type::Struct(s) = namespace.type_ {
|
||||||
if let e::Identifier(name, _) = &field.kind {
|
if let e::Identifier(name, _) = &field.kind {
|
||||||
expr.type_ = self
|
expr.type_ = self
|
||||||
.table
|
.table
|
||||||
|
@ -259,6 +267,7 @@ impl Analyzer {
|
||||||
.is_alias()
|
.is_alias()
|
||||||
.reason("Expected type, found value")
|
.reason("Expected type, found value")
|
||||||
.span(&expr.span)?;
|
.span(&expr.span)?;
|
||||||
|
name.clone()
|
||||||
} else {
|
} else {
|
||||||
return error().reason("Field must be identifier").span(&expr.span);
|
return error().reason("Field must be identifier").span(&expr.span);
|
||||||
}
|
}
|
||||||
|
@ -269,8 +278,13 @@ impl Analyzer {
|
||||||
namespace.type_
|
namespace.type_
|
||||||
))
|
))
|
||||||
.span(&expr.span);
|
.span(&expr.span);
|
||||||
|
};
|
||||||
|
// Name mangling
|
||||||
|
if let e::Identifier(_, mangle) = &namespace.kind {
|
||||||
|
uid = mangle.clone() + "$" + &field_name;
|
||||||
|
} else if uid != "" {
|
||||||
|
uid = uid + "$" + &field_name;
|
||||||
}
|
}
|
||||||
// TODO handle name mangle
|
|
||||||
e::Field {
|
e::Field {
|
||||||
namespace,
|
namespace,
|
||||||
field,
|
field,
|
||||||
|
|
|
@ -2,6 +2,7 @@ mod analyzer;
|
||||||
mod bottom_up;
|
mod bottom_up;
|
||||||
mod naming;
|
mod naming;
|
||||||
mod primitives;
|
mod primitives;
|
||||||
|
mod sizing;
|
||||||
mod top_down;
|
mod top_down;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
|
@ -23,11 +24,12 @@ pub type UID = String;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Symbol {
|
pub struct Symbol {
|
||||||
name: String,
|
pub name: String,
|
||||||
type_: Type,
|
pub type_: Type,
|
||||||
uid: UID,
|
pub uid: UID,
|
||||||
initialized: bool,
|
initialized: bool,
|
||||||
mutable: Option<bool>,
|
pub mutable: Option<bool>,
|
||||||
|
pub global: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -40,7 +42,7 @@ enum Definition {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SymbolTable {
|
pub struct SymbolTable {
|
||||||
pub structs: Vec<StructureDef>,
|
pub structs: Vec<StructureDef>,
|
||||||
pub functions: Vec<FunctionDef>,
|
pub functions: HashMap<UID, FunctionDef>,
|
||||||
scope: Vec<Definition>,
|
scope: Vec<Definition>,
|
||||||
pub table: HashMap<UID, Symbol>,
|
pub table: HashMap<UID, Symbol>,
|
||||||
mangle_num: usize,
|
mangle_num: usize,
|
||||||
|
@ -63,12 +65,18 @@ impl SymbolTable {
|
||||||
uid: nothing_mangle(),
|
uid: nothing_mangle(),
|
||||||
initialized: true,
|
initialized: true,
|
||||||
mutable: Some(false),
|
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()));
|
scope.push(Definition::Ident(nothing_symbol.clone()));
|
||||||
table.insert(nothing_symbol.uid.clone(), nothing_symbol);
|
table.insert(nothing_symbol.uid.clone(), nothing_symbol);
|
||||||
Self {
|
Self {
|
||||||
structs: vec![],
|
structs: vec![],
|
||||||
functions: vec![],
|
functions,
|
||||||
scope,
|
scope,
|
||||||
table,
|
table,
|
||||||
mangle_num: 0,
|
mangle_num: 0,
|
||||||
|
@ -96,6 +104,17 @@ impl SymbolTable {
|
||||||
unreachable!("Cannot end global scope")
|
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> {
|
pub fn resolve_type(&self, uid: &UID) -> Result<Type> {
|
||||||
let symbol = self.table.get(uid).unwrap();
|
let symbol = self.table.get(uid).unwrap();
|
||||||
if symbol.initialized == false {
|
if symbol.initialized == false {
|
||||||
|
@ -105,6 +124,16 @@ impl SymbolTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
pub fn start_function(&mut self) {
|
||||||
self.nesting += 1;
|
self.nesting += 1;
|
||||||
self.scope.push(Definition::FuncStart);
|
self.scope.push(Definition::FuncStart);
|
||||||
|
@ -158,8 +187,8 @@ impl SymbolTable {
|
||||||
&mut self,
|
&mut self,
|
||||||
params: Vec<Parameter>,
|
params: Vec<Parameter>,
|
||||||
returns: Option<String>,
|
returns: Option<String>,
|
||||||
) -> Result<FID> {
|
) -> Result<UID> {
|
||||||
let fid = self.functions.len();
|
let uid = self.generate_uid("func");
|
||||||
let mut symbols = vec![];
|
let mut symbols = vec![];
|
||||||
for p in ¶ms {
|
for p in ¶ms {
|
||||||
let symbol = self.reference_ident(&p.type_str);
|
let symbol = self.reference_ident(&p.type_str);
|
||||||
|
@ -174,15 +203,15 @@ impl SymbolTable {
|
||||||
let mut new_params = vec![];
|
let mut new_params = vec![];
|
||||||
for (p, s) in params.iter().zip(symbols.iter()) {
|
for (p, s) in params.iter().zip(symbols.iter()) {
|
||||||
let s = self
|
let s = self
|
||||||
.define_ident(&p.name, s.type_.clone(), false)
|
.define_ident(&p.name, s.type_.is_alias()?, false)
|
||||||
.trace("While initializing function parameters")?;
|
.trace("While initializing function parameters")?;
|
||||||
new_params.push(s.uid);
|
new_params.push(s.uid);
|
||||||
}
|
}
|
||||||
self.functions.push(FunctionDef {
|
self.functions.insert(uid.clone(), FunctionDef {
|
||||||
params: new_params,
|
params: new_params,
|
||||||
returns,
|
returns,
|
||||||
});
|
});
|
||||||
Ok(fid)
|
Ok(uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn modify_ident(
|
pub fn modify_ident(
|
||||||
|
@ -192,6 +221,7 @@ impl SymbolTable {
|
||||||
type_: Option<Type>,
|
type_: Option<Type>,
|
||||||
mutable: Option<bool>,
|
mutable: Option<bool>,
|
||||||
init: bool,
|
init: bool,
|
||||||
|
global: 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_ {
|
||||||
|
@ -204,6 +234,7 @@ impl SymbolTable {
|
||||||
_ => mutable,
|
_ => mutable,
|
||||||
};
|
};
|
||||||
symbol.initialized |= init;
|
symbol.initialized |= init;
|
||||||
|
symbol.global |= global;
|
||||||
|
|
||||||
let mut nesting = self.nesting;
|
let mut nesting = self.nesting;
|
||||||
for def in &mut self.scope {
|
for def in &mut self.scope {
|
||||||
|
@ -225,6 +256,7 @@ impl SymbolTable {
|
||||||
_ => mutable,
|
_ => mutable,
|
||||||
};
|
};
|
||||||
symbol.initialized |= init;
|
symbol.initialized |= init;
|
||||||
|
symbol.global |= global;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
},
|
||||||
Definition::FuncStart => nesting -= 1,
|
Definition::FuncStart => nesting -= 1,
|
||||||
|
@ -241,8 +273,6 @@ impl SymbolTable {
|
||||||
type_: Type,
|
type_: Type,
|
||||||
mutable: bool,
|
mutable: bool,
|
||||||
) -> Result<Symbol> {
|
) -> Result<Symbol> {
|
||||||
println!("---{name}---");
|
|
||||||
println!("{:#?}", self.lookup_block_scope(name));
|
|
||||||
if let Type::Alias(_) | Type::Function(_) = &type_ {
|
if let Type::Alias(_) | Type::Function(_) = &type_ {
|
||||||
if mutable {
|
if mutable {
|
||||||
return error()
|
return error()
|
||||||
|
@ -264,6 +294,7 @@ impl SymbolTable {
|
||||||
Some(type_),
|
Some(type_),
|
||||||
Some(mutable),
|
Some(mutable),
|
||||||
true,
|
true,
|
||||||
|
self.in_global_scope(),
|
||||||
)?;
|
)?;
|
||||||
return Ok(s);
|
return Ok(s);
|
||||||
}
|
}
|
||||||
|
@ -276,6 +307,7 @@ impl SymbolTable {
|
||||||
uid: uid.clone(),
|
uid: uid.clone(),
|
||||||
initialized: true,
|
initialized: true,
|
||||||
mutable: Some(mutable),
|
mutable: Some(mutable),
|
||||||
|
global: self.in_global_scope(),
|
||||||
};
|
};
|
||||||
self.scope.push(Definition::Ident(sym.clone()));
|
self.scope.push(Definition::Ident(sym.clone()));
|
||||||
self.table.insert(uid, sym.clone());
|
self.table.insert(uid, sym.clone());
|
||||||
|
@ -293,6 +325,7 @@ impl SymbolTable {
|
||||||
uid: uid.clone(),
|
uid: uid.clone(),
|
||||||
initialized: false,
|
initialized: false,
|
||||||
mutable: None,
|
mutable: None,
|
||||||
|
global: false,
|
||||||
};
|
};
|
||||||
self.scope.push(Definition::Ident(sym.clone()));
|
self.scope.push(Definition::Ident(sym.clone()));
|
||||||
self.table.insert(uid, sym.clone());
|
self.table.insert(uid, sym.clone());
|
||||||
|
@ -334,19 +367,3 @@ impl SymbolTable {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// I think this works? Box<T> pattern matching weirdness
|
|
||||||
// going on. If this is ever even used
|
|
||||||
fn unwrap_aliases(mut t: Type) -> Type {
|
|
||||||
loop {
|
|
||||||
if let Type::Alias(ref t1) = t {
|
|
||||||
if let Type::Alias(t2) = &**t1 {
|
|
||||||
t = *t2.clone();
|
|
||||||
} else {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ impl Analyzer {
|
||||||
} else {
|
} else {
|
||||||
value.type_.clone()
|
value.type_.clone()
|
||||||
};
|
};
|
||||||
println!("{type_:?}");
|
|
||||||
let symbol = self.table.define_ident(&name, type_, mutable)?;
|
let symbol = self.table.define_ident(&name, type_, mutable)?;
|
||||||
uid = symbol.uid;
|
uid = symbol.uid;
|
||||||
s::Declaration {
|
s::Declaration {
|
||||||
|
@ -55,6 +54,7 @@ impl Analyzer {
|
||||||
Some(value.type_.clone()),
|
Some(value.type_.clone()),
|
||||||
Some(true),
|
Some(true),
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
)?;
|
)?;
|
||||||
s::Assignment { name, value, uid }
|
s::Assignment { name, value, uid }
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,8 +34,8 @@ macro_rules! primitives {
|
||||||
impl std::fmt::Display for Primitive {
|
impl std::fmt::Display for Primitive {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Primitive::integer_ambiguous => write!(f, "<ambiguous integer>"),
|
Primitive::integer_ambiguous => write!(f, "ambiguous integer"),
|
||||||
Primitive::real_ambiguous => write!(f, "<ambiguous real>"),
|
Primitive::real_ambiguous => write!(f, "ambiguous real"),
|
||||||
$(Primitive::$i => write!(f, stringify!{$i}),)*
|
$(Primitive::$i => write!(f, stringify!{$i}),)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ macro_rules! primitives {
|
||||||
uid: format!("$${}", stringify!{$i}),
|
uid: format!("$${}", stringify!{$i}),
|
||||||
initialized: true,
|
initialized: true,
|
||||||
mutable: Some(false),
|
mutable: Some(false),
|
||||||
|
global: true,
|
||||||
},)*
|
},)*
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
6
src/semantic/sizing.rs
Normal file
6
src/semantic/sizing.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
pub enum DataType {
|
||||||
|
i32,
|
||||||
|
i64,
|
||||||
|
f32,
|
||||||
|
f64,
|
||||||
|
}
|
|
@ -89,6 +89,7 @@ impl Analyzer {
|
||||||
s::Return(expr) => {
|
s::Return(expr) => {
|
||||||
if let Some(mut expr) = expr {
|
if let Some(mut expr) = expr {
|
||||||
let expr_t = expr.type_.clone();
|
let expr_t = expr.type_.clone();
|
||||||
|
println!("{expr_t}");
|
||||||
expr = *self.top_down_expr(expr.into(), &expr_t)?;
|
expr = *self.top_down_expr(expr.into(), &expr_t)?;
|
||||||
s::Return(Some(expr))
|
s::Return(Some(expr))
|
||||||
} else {
|
} else {
|
||||||
|
@ -106,6 +107,7 @@ impl Analyzer {
|
||||||
expect: &Type,
|
expect: &Type,
|
||||||
) -> Result<Box<Expression>> {
|
) -> Result<Box<Expression>> {
|
||||||
use ExpressionKind as e;
|
use ExpressionKind as e;
|
||||||
|
println!("{} -> {expect}", expr.type_);
|
||||||
expr.type_ = expr.type_.coerce(expect).span(&expr.span)?;
|
expr.type_ = expr.type_.coerce(expect).span(&expr.span)?;
|
||||||
expr.kind = match expr.kind {
|
expr.kind = match expr.kind {
|
||||||
e::Immediate(i) => e::Immediate(i),
|
e::Immediate(i) => e::Immediate(i),
|
||||||
|
@ -151,8 +153,8 @@ impl Analyzer {
|
||||||
is_reference,
|
is_reference,
|
||||||
id,
|
id,
|
||||||
} => {
|
} => {
|
||||||
let func_def = if let Type::Function(fid) = callee.type_ {
|
let func_def = if let Type::Function(ref uid) = callee.type_ {
|
||||||
self.table.functions[fid].clone()
|
self.table.functions.get(uid).unwrap().clone()
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
@ -208,7 +210,9 @@ impl Analyzer {
|
||||||
.span(&arg.span)?
|
.span(&arg.span)?
|
||||||
.is_alias()
|
.is_alias()
|
||||||
.span(&arg.span)?;
|
.span(&arg.span)?;
|
||||||
|
println!("{param_t}");
|
||||||
*arg = *self.top_down_expr(arg.clone().into(), ¶m_t)?;
|
*arg = *self.top_down_expr(arg.clone().into(), ¶m_t)?;
|
||||||
|
println!("/{param_t}");
|
||||||
}
|
}
|
||||||
e::StructLiteral { name, args, id }
|
e::StructLiteral { name, args, id }
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,8 +9,6 @@ pub type SID = usize;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct StructureDef(pub Vec<(String, UID)>);
|
pub struct StructureDef(pub Vec<(String, UID)>);
|
||||||
|
|
||||||
pub type FID = usize;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FunctionDef {
|
pub struct FunctionDef {
|
||||||
pub params: Vec<UID>,
|
pub params: Vec<UID>,
|
||||||
|
@ -28,7 +26,7 @@ pub enum Type {
|
||||||
Alias(Box<Type>),
|
Alias(Box<Type>),
|
||||||
Prim(Primitive),
|
Prim(Primitive),
|
||||||
Struct(SID),
|
Struct(SID),
|
||||||
Function(FID),
|
Function(UID),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Type {
|
impl std::fmt::Display for Type {
|
||||||
|
|
14
src/token.rs
14
src/token.rs
|
@ -385,14 +385,14 @@ impl<I: Iterator<Item = char>> Tokenizer<I> {
|
||||||
}
|
}
|
||||||
buffer = buffer.to_lowercase();
|
buffer = buffer.to_lowercase();
|
||||||
// Determine base
|
// Determine base
|
||||||
let base = if buffer.starts_with("0b") {
|
let (buffer, base) = if let Some(buffer) = buffer.strip_prefix("0b") {
|
||||||
Base::Binary
|
(buffer.to_string(), Base::Binary)
|
||||||
} else if buffer.starts_with("0o") {
|
} else if let Some(buffer) = buffer.strip_prefix("0o") {
|
||||||
Base::Octal
|
(buffer.to_string(), Base::Octal)
|
||||||
} else if buffer.starts_with("0x") {
|
} else if let Some(buffer) = buffer.strip_prefix("0x") {
|
||||||
Base::Hex
|
(buffer.to_string(), Base::Hex)
|
||||||
} else {
|
} else {
|
||||||
Base::Decimal
|
(buffer, Base::Decimal)
|
||||||
};
|
};
|
||||||
// Determine integer or float
|
// Determine integer or float
|
||||||
if base == Base::Decimal && (encountered_dot || buffer.contains("e")) {
|
if base == Base::Decimal && (encountered_dot || buffer.contains("e")) {
|
||||||
|
|
40
test.wat
40
test.wat
|
@ -1,14 +1,32 @@
|
||||||
(module
|
(module
|
||||||
(import "console" "log" (func $log (param i32)))
|
(func $3$func
|
||||||
(global $a$0 (mut i32) (i32.const 0))
|
(param $4$s$0 i32)
|
||||||
(func $0
|
(param $4$s$1 i32)
|
||||||
i32.const 10
|
(param $4$s$2 f32)
|
||||||
i32.const 5
|
(param $5$a$0 i32)
|
||||||
i32.div_s
|
(result i32 i32 f32 )
|
||||||
global.set $a$0
|
local.get $4$s$2
|
||||||
global.get $a$0
|
local.get $4$s$1
|
||||||
call $log
|
local.get $4$s$0
|
||||||
|
return
|
||||||
|
)
|
||||||
|
(global $2$s$0 (mut i32))
|
||||||
|
(global $2$s$1 (mut i32))
|
||||||
|
(global $2$s$2 (mut f32))
|
||||||
|
(func $$main
|
||||||
|
(local $$tmp0$0 i32)
|
||||||
|
(local $$tmp1$0 i32)
|
||||||
|
i32.const 2
|
||||||
|
i32.const 1
|
||||||
|
local.set $$tmp0$0
|
||||||
|
i32.const 97
|
||||||
|
local.set $$tmp1$0
|
||||||
|
f32.const 1
|
||||||
|
local.get $$tmp1$0
|
||||||
|
local.get $$tmp0$0
|
||||||
|
call $3$func
|
||||||
|
global.set $2$s$0
|
||||||
|
global.set $2$s$1
|
||||||
|
global.set $2$s$2
|
||||||
)
|
)
|
||||||
|
|
||||||
(start $0)
|
|
||||||
)
|
)
|
Loading…
Reference in a new issue