reset semanalyzer
This commit is contained in:
parent
fabb66148d
commit
a783bcebb4
|
@ -1,251 +0,0 @@
|
|||
/*
|
||||
use crate::{Expression, ExpressionKind, Statement, StatementKind};
|
||||
|
||||
use super::*;
|
||||
|
||||
impl Compiler {
|
||||
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;
|
||||
match stmt.kind {
|
||||
s::Declaration {
|
||||
type_actual,
|
||||
value,
|
||||
mutable,
|
||||
uid,
|
||||
..
|
||||
} => {
|
||||
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,
|
||||
type_: type_actual,
|
||||
global,
|
||||
});
|
||||
},
|
||||
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 {
|
||||
predicate,
|
||||
block,
|
||||
else_,
|
||||
} => todo!(),
|
||||
s::While { predicate, block } => todo!(),
|
||||
s::Print(expression) => {
|
||||
let type_ = expression.type_.clone();
|
||||
self.expression(expression);
|
||||
self.push(IR::Print { type_ });
|
||||
},
|
||||
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}")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub 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) => match expr.type_ {
|
||||
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 } => {
|
||||
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_actual,
|
||||
body,
|
||||
id,
|
||||
..
|
||||
} => {
|
||||
self.push(IR::StartFunc {
|
||||
uid: id,
|
||||
params: params
|
||||
.into_iter()
|
||||
.map(|p| (p.name, p.type_actual))
|
||||
.collect(),
|
||||
returns: returns_actual,
|
||||
});
|
||||
for s in body {
|
||||
self.statement(s);
|
||||
}
|
||||
self.push(IR::EndFunc);
|
||||
},
|
||||
e::FunctionCall {
|
||||
callee, args, id, ..
|
||||
} => {
|
||||
self.expression(*callee);
|
||||
for arg in args.into_iter().rev() {
|
||||
self.expression(arg);
|
||||
}
|
||||
self.push(IR::Call { uid: id })
|
||||
},
|
||||
e::StructDef(..) => {},
|
||||
e::StructLiteral { args, .. } => {
|
||||
let struct_id = if let Type::Struct(s) = expr.type_ {
|
||||
s
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
let length = args.len();
|
||||
let mut temp_buffer = vec![None; length];
|
||||
let mut iter = args.into_iter();
|
||||
let mut index = length - 1;
|
||||
loop {
|
||||
// If struct param has already been saved
|
||||
if let Some((uid, type_)) = temp_buffer[index].take() {
|
||||
self.ir.push(IR::Get {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
198
src/ir/mod.rs
198
src/ir/mod.rs
|
@ -1,198 +0,0 @@
|
|||
/*
|
||||
mod generate;
|
||||
mod wasm;
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
use crate::{
|
||||
BinaryOp, Immediate, Statement, UnaryOp,
|
||||
semantic::{Primitive, SymbolTable, Type, UID},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum IR {
|
||||
BinOp {
|
||||
op: BinaryOp,
|
||||
type_: Type,
|
||||
},
|
||||
UnOp {
|
||||
op: UnaryOp,
|
||||
type_: Type,
|
||||
},
|
||||
Push {
|
||||
prim: Primitive,
|
||||
value: Immediate,
|
||||
},
|
||||
New {
|
||||
uid: UID,
|
||||
type_: Type,
|
||||
mutable: bool,
|
||||
global: bool,
|
||||
},
|
||||
Set {
|
||||
uid: UID,
|
||||
type_: Type,
|
||||
global: bool,
|
||||
},
|
||||
Get {
|
||||
uid: UID,
|
||||
type_: Type,
|
||||
global: bool,
|
||||
},
|
||||
StartFunc {
|
||||
uid: UID,
|
||||
params: Vec<(UID, Type)>,
|
||||
returns: Type,
|
||||
},
|
||||
EndFunc,
|
||||
Return {
|
||||
type_: Type,
|
||||
},
|
||||
Call {
|
||||
uid: UID,
|
||||
},
|
||||
Drop {
|
||||
type_: Type,
|
||||
},
|
||||
Print {
|
||||
type_: Type,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::fmt::Display for IR {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use IR::*;
|
||||
match self {
|
||||
BinOp { op, type_ } => write!(f, "{op} ({type_})"),
|
||||
UnOp { op, type_ } => write!(f, "{op}, {type_}"),
|
||||
Push { prim, value } => write!(f, "push {value} ({prim})"),
|
||||
New {
|
||||
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 {
|
||||
uid,
|
||||
params,
|
||||
returns,
|
||||
} => write!(f, "<function id={uid} params={params:?} returns={returns}>"),
|
||||
EndFunc => write!(f, "</function>"),
|
||||
Call { uid } => write!(f, "call {uid}"),
|
||||
Return { type_ } => write!(f, "result {type_}"),
|
||||
Print { type_ } => write!(f, "print {type_} [DEBUG]"),
|
||||
Drop { .. } => write!(f, "pop"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Compiler {
|
||||
ir: Vec<IR>,
|
||||
table: SymbolTable,
|
||||
tmp_num: usize,
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
pub fn new(table: SymbolTable) -> Self {
|
||||
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) {
|
||||
self.ir.push(ir);
|
||||
}
|
||||
|
||||
fn hoist(&mut self) {
|
||||
// Declarations, instructions
|
||||
let mut functions = vec![(vec![], vec![])];
|
||||
// Final IR output
|
||||
let mut result = vec![];
|
||||
for ir in &self.ir {
|
||||
match ir {
|
||||
IR::StartFunc { .. } => {
|
||||
functions.push((vec![], vec![]));
|
||||
},
|
||||
IR::EndFunc => {
|
||||
let (inits, instr) = functions.pop().unwrap();
|
||||
for ir in inits {
|
||||
result.push(ir);
|
||||
}
|
||||
for ir in instr {
|
||||
result.push(ir);
|
||||
}
|
||||
result.push(IR::EndFunc);
|
||||
continue;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
// Push instruction to correct stack
|
||||
let (inits, instr) = functions.last_mut().unwrap();
|
||||
match ir {
|
||||
IR::New { .. } | IR::StartFunc { .. } => {
|
||||
inits.push(ir.clone());
|
||||
},
|
||||
_ => instr.push(ir.clone()),
|
||||
}
|
||||
}
|
||||
// Initialize globals
|
||||
let (inits, instr) = functions.pop().unwrap();
|
||||
let mut main_locals = vec![];
|
||||
for ir in inits {
|
||||
match ir {
|
||||
IR::New { global: true, .. } => {
|
||||
result.push(ir);
|
||||
},
|
||||
_ => main_locals.push(ir),
|
||||
}
|
||||
}
|
||||
// The main function (index 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 {
|
||||
result.push(ir);
|
||||
}
|
||||
result.push(IR::EndFunc);
|
||||
self.ir = result;
|
||||
}
|
||||
}
|
||||
*/
|
213
src/ir/wasm.rs
213
src/ir/wasm.rs
|
@ -1,213 +0,0 @@
|
|||
/*
|
||||
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!(),
|
||||
})
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -1,6 +1,5 @@
|
|||
#![feature(let_chains)]
|
||||
mod err;
|
||||
mod ir;
|
||||
mod lookahead;
|
||||
mod parse;
|
||||
mod semantic;
|
||||
|
@ -79,6 +78,6 @@ fn main() -> Result<()> {
|
|||
*/
|
||||
//let module = frontend::Module::from_file("./demo.hal")?;
|
||||
//module.write_to("test");
|
||||
test_expression("asdf~+ + 3");
|
||||
test_expression("(a, b, c: d) {}");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
Expression, ExpressionKind, Span, Statement, StatementKind, err::*,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use ir::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Undo {
|
||||
FuncGuard,
|
||||
BlockGuard,
|
||||
Symbol { name: String, prev: Symbol },
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Symbol {
|
||||
mangle: SID,
|
||||
type_: TID,
|
||||
life: Lifetime,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct SymbolTable {
|
||||
type_table: Vec<Type>,
|
||||
sym_table: HashMap<String, Symbol>,
|
||||
undo_stack: Vec<Undo>,
|
||||
path: Vec<String>,
|
||||
salt: usize,
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl SymbolTable {
|
||||
fn define_symbol(&mut self, name: &str, type_: TID) {
|
||||
let mut path = self.path.clone();
|
||||
path.push(name.to_string());
|
||||
let undo = match self.sym_table.get(name) {
|
||||
Some(prev) => Undo::Symbol {
|
||||
name: name.to_string(),
|
||||
prev: prev.clone(),
|
||||
},
|
||||
None => Undo::None,
|
||||
};
|
||||
self.undo_stack.push(undo);
|
||||
let mangle = names::mangle(path, &self.salt.to_string());
|
||||
let symbol = Symbol {
|
||||
mangle,
|
||||
type_,
|
||||
life: if self.depth == 0 {
|
||||
Lifetime::Static
|
||||
} else {
|
||||
Lifetime::Dynamic
|
||||
},
|
||||
};
|
||||
self.sym_table.insert(name.to_string(), symbol);
|
||||
}
|
||||
|
||||
fn query_symbol(&mut self, name: &str) -> Result<&Symbol> {
|
||||
self.sym_table.get(name).ok_or(Diagnostic::new(
|
||||
format!("The name {name} is not declared in this scope",),
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
||||
fn define_type(&mut self, type_: Type) -> TID {
|
||||
self.type_table.push(type_);
|
||||
self.type_table.len()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn analyze_block(stmts: Vec<Statement>) -> Result<Vec<IrNode>> {
|
||||
todo!()
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
use super::{primitives::Primitive, SID};
|
||||
|
||||
pub fn mangle(input: &str) -> SID {
|
||||
format!("$B${input}")
|
||||
}
|
||||
|
||||
// Nothing ever happens
|
||||
pub fn nothing() -> SID {
|
||||
mangle("nothing")
|
||||
}
|
||||
|
||||
pub fn integer() -> SID {
|
||||
Primitive::integer_ambiguous.mangle()
|
||||
}
|
||||
|
||||
pub fn real() -> SID {
|
||||
Primitive::real_ambiguous.mangle()
|
||||
}
|
||||
|
||||
pub fn all() -> Vec<SID> {
|
||||
let mut uids = Primitive::ALL.map(|p| p.mangle()).to_vec();
|
||||
uids.push(nothing());
|
||||
uids
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
use crate::{BinaryOp, UnaryOp};
|
||||
|
||||
use super::{Type, SID, TID};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IrBlock {
|
||||
nodes: Vec<IrNode>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum IrNode {
|
||||
Declaration {
|
||||
uid: SID,
|
||||
mutable: bool,
|
||||
size: usize,
|
||||
value: IrExpr,
|
||||
},
|
||||
Function {
|
||||
uid: SID,
|
||||
parameters: Vec<Type>,
|
||||
block: IrBlock,
|
||||
},
|
||||
Conditional {
|
||||
branches: Vec<(IrExpr, IrBlock)>,
|
||||
default: IrBlock,
|
||||
},
|
||||
Expr(IrExpr),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IrExpr {
|
||||
kind: IrExprKind,
|
||||
type_: TID,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum IrExprKind {
|
||||
Ident(SID),
|
||||
UnOp {
|
||||
op: UnaryOp,
|
||||
child: Box<IrExpr>,
|
||||
},
|
||||
BinOp {
|
||||
op: BinaryOp,
|
||||
left: Box<IrExpr>,
|
||||
right: Box<IrExpr>,
|
||||
},
|
||||
Block(IrBlock),
|
||||
Call {
|
||||
function: SID,
|
||||
args: Vec<IrExpr>,
|
||||
},
|
||||
}
|
|
@ -1,56 +1,46 @@
|
|||
pub mod analyzer;
|
||||
pub mod builtin;
|
||||
pub mod ir;
|
||||
pub mod names;
|
||||
pub mod primitives;
|
||||
pub type Mangle = String;
|
||||
|
||||
pub use primitives::*;
|
||||
|
||||
use crate::semantic::Primitive;
|
||||
|
||||
/// Type ID
|
||||
pub type TID = usize;
|
||||
/// Name mangle
|
||||
pub type SID = String;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Lifetime {
|
||||
/// Exists for lifetime of program
|
||||
Static,
|
||||
/// Exists for lifetime of contained scope
|
||||
Dynamic,
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Primitive {
|
||||
i8,
|
||||
i16,
|
||||
i32,
|
||||
i64,
|
||||
integer,
|
||||
integer_literal,
|
||||
w8,
|
||||
w16,
|
||||
w32,
|
||||
w64,
|
||||
whole,
|
||||
f32,
|
||||
f64,
|
||||
float,
|
||||
float_literal,
|
||||
glyph,
|
||||
string,
|
||||
boolean,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Type {
|
||||
/// Type is unknown at this stage
|
||||
Ambiguous,
|
||||
/// Zero size void type
|
||||
None,
|
||||
/// A primitive type
|
||||
Prim(Primitive),
|
||||
Nothing,
|
||||
Never,
|
||||
/// Constructed type
|
||||
Struct {
|
||||
size: usize,
|
||||
name: String,
|
||||
member_names: Vec<String>,
|
||||
member_types: Vec<TID>,
|
||||
field_names: Vec<String>,
|
||||
field_types: Vec<Type>,
|
||||
},
|
||||
Alias(TID),
|
||||
/// Non-capturing function type
|
||||
Function {
|
||||
name: String,
|
||||
arg_names: Vec<String>,
|
||||
arg_types: Vec<TID>,
|
||||
field_types: Vec<Type>,
|
||||
returns: Box<Type>,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Type {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Type::Ambiguous => write!(f, "ambiguous"),
|
||||
Type::Prim(primitive) => write!(f, "{primitive}"),
|
||||
Type::Nothing => write!(f, "nothing"),
|
||||
Type::Never => write!(f, "never"),
|
||||
Type::Struct { name, .. } => write!(f, "struct {name}"),
|
||||
Type::Alias(tid) => write!(f, "alias ({tid})"),
|
||||
Type::Function { name, .. } => write!(f, "func ({name})"),
|
||||
}
|
||||
}
|
||||
/// The name of a type
|
||||
Type(Box<Type>),
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
// <mangle> ::= "$" <path> <salt>
|
||||
// <path> ::= {<path-element>}*
|
||||
// <path-element> ::= <length> <ident>
|
||||
// <ident> ::= <_a-zA-Z> {<_a-zA-Z0-9>}*
|
||||
// <length> ::= {<0-9>}+
|
||||
// <salt> ::= {<a-zA-Z>}*
|
||||
|
||||
pub fn mangle(path: Vec<String>, salt: &str) -> String {
|
||||
let mut buf: Vec<u8> = vec![];
|
||||
for p in path {
|
||||
let bytes = format!("{}{}", p.len(), punycode::encode(&p).unwrap());
|
||||
buf.extend_from_slice(bytes.as_bytes());
|
||||
}
|
||||
buf.extend_from_slice(salt.as_bytes());
|
||||
String::from_utf8(buf).unwrap()
|
||||
}
|
|
@ -1,197 +0,0 @@
|
|||
use crate::{BinaryOp, UnaryOp};
|
||||
|
||||
use crate::err::*;
|
||||
use crate::semantic::{builtin, SID};
|
||||
|
||||
macro_rules! count {
|
||||
() => (0usize);
|
||||
( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
|
||||
}
|
||||
|
||||
macro_rules! primitives {
|
||||
( $($i:ident),* ) => {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
pub enum Primitive {
|
||||
integer_ambiguous,
|
||||
real_ambiguous,
|
||||
$($i,)*
|
||||
}
|
||||
|
||||
impl Primitive {
|
||||
pub const ALL: [Primitive; count!($($i)*,) - 1] = [$(Primitive::$i),*];
|
||||
|
||||
pub fn from_string(string: &str) -> Option<Self> {
|
||||
match string {
|
||||
$(stringify!{$i} => Some(Self::$i),)*
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mangle(&self) -> SID {
|
||||
match self {
|
||||
Primitive::integer_ambiguous => builtin::mangle("integer_ambiguous"),
|
||||
Primitive::real_ambiguous => builtin::mangle("real_ambiguous"),
|
||||
$(
|
||||
Primitive::$i => builtin::mangle(stringify!{$i}),
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for Primitive {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Primitive::integer_ambiguous => write!(f, "ambiguous integer"),
|
||||
Primitive::real_ambiguous => write!(f, "ambiguous real"),
|
||||
$(Primitive::$i => write!(f, stringify!{$i}),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
primitives! {
|
||||
w8, w16, w32, w64, whole,
|
||||
i8, i16, i32, i64, integer,
|
||||
r32, r64, real,
|
||||
boolean,
|
||||
string, glyph
|
||||
}
|
||||
|
||||
impl Primitive {
|
||||
pub fn as_wat(&self) -> &'static str {
|
||||
use Primitive::*;
|
||||
match self {
|
||||
boolean | glyph | w8 | w16 | w32 | whole | i8 | i16 | i32 | integer => "i32",
|
||||
w64 | i64 => "i64",
|
||||
r32 | real => "f32",
|
||||
r64 => "f64",
|
||||
string => todo!(),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! selfsame_basic {
|
||||
( $lhs:ident, $op:ident, $rhs:ident, $binop:ident, $i:ident ) => {
|
||||
if ($i == $rhs && $rhs == $lhs) && $op == BinaryOp::$binop {
|
||||
return Ok($i);
|
||||
}
|
||||
};
|
||||
|
||||
( $lhs:ident, $op:ident, $rhs:ident; $($i:ident),* ) => {
|
||||
$(
|
||||
selfsame_basic!($lhs, $op, $rhs, Plus, $i);
|
||||
selfsame_basic!($lhs, $op, $rhs, Minus, $i);
|
||||
selfsame_basic!($lhs, $op, $rhs, Star, $i);
|
||||
selfsame_basic!($lhs, $op, $rhs, Slash, $i);
|
||||
)*
|
||||
logical!($lhs, $op, $rhs; $($i),*);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! logical {
|
||||
( $lhs:ident, $op:ident, $rhs:ident; $($i:ident),* ) => {
|
||||
$(
|
||||
selfsame_basic!($lhs, $op, $rhs, And, $i);
|
||||
selfsame_basic!($lhs, $op, $rhs, Nand, $i);
|
||||
selfsame_basic!($lhs, $op, $rhs, Xor, $i);
|
||||
selfsame_basic!($lhs, $op, $rhs, Xnor, $i);
|
||||
selfsame_basic!($lhs, $op, $rhs, Or, $i);
|
||||
selfsame_basic!($lhs, $op, $rhs, Nor, $i);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! comparison {
|
||||
( $lhs:ident, $op:ident, $rhs:ident, $binop:ident, $i:ident ) => {
|
||||
if ($i == $rhs && $rhs == $lhs) && $op == BinaryOp::$binop {
|
||||
return Ok(boolean);
|
||||
}
|
||||
};
|
||||
|
||||
( $lhs:ident, $op:ident, $rhs:ident; $($i:ident),* ) => {
|
||||
$(
|
||||
comparison!($lhs, $op, $rhs, DoubleEqual, $i);
|
||||
comparison!($lhs, $op, $rhs, BangEqual, $i);
|
||||
comparison!($lhs, $op, $rhs, Less, $i);
|
||||
comparison!($lhs, $op, $rhs, LessEqual, $i);
|
||||
comparison!($lhs, $op, $rhs, Greater, $i);
|
||||
comparison!($lhs, $op, $rhs, GreaterEqual, $i);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl Primitive {
|
||||
pub fn coerce(self, expect: Primitive) -> Result<Self> {
|
||||
use Primitive::*;
|
||||
match (self, expect) {
|
||||
(integer_ambiguous, a @ (i8 | i16 | i32 | i64 | integer | w8 | w16 | w32 | w64 | whole))
|
||||
| (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 {
|
||||
match self {
|
||||
Primitive::integer_ambiguous | Primitive::real_ambiguous => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn promote(&mut self) {
|
||||
*self = match *self {
|
||||
Primitive::integer_ambiguous => Primitive::integer,
|
||||
Primitive::real_ambiguous => Primitive::real,
|
||||
_ => *self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn binary_op(mut lhs: Primitive, op: BinaryOp, mut rhs: Primitive) -> Result<Primitive> {
|
||||
use Primitive::*;
|
||||
if lhs.is_ambiguous() && !rhs.is_ambiguous() {
|
||||
lhs = lhs.coerce(rhs)?;
|
||||
} else if rhs.is_ambiguous() && !lhs.is_ambiguous() {
|
||||
rhs = rhs.coerce(lhs)?;
|
||||
}
|
||||
selfsame_basic! {
|
||||
lhs, op, rhs; w8, w16, w32, w64, i8, i16, i32, i64,
|
||||
integer, integer_ambiguous, real, real_ambiguous
|
||||
}
|
||||
logical! { lhs, op, rhs; boolean }
|
||||
comparison! {
|
||||
lhs, op, rhs; w8, w16, w32, w64, i8, i16, i32, i64,
|
||||
integer, integer_ambiguous, real, real_ambiguous,
|
||||
boolean, string
|
||||
}
|
||||
error().reason(format!(
|
||||
"Binary {} is not defined for {} and {}",
|
||||
op, lhs, rhs
|
||||
))
|
||||
}
|
||||
|
||||
pub fn unary_op(op: UnaryOp, child: Primitive) -> Result<Primitive> {
|
||||
use Primitive::*;
|
||||
use UnaryOp::*;
|
||||
let e = error().reason(format!("Unary {} is not defined for {}", op, child));
|
||||
match op {
|
||||
Minus => match child {
|
||||
boolean | string | glyph | whole | w8 | w16 | w32 | w64 => e,
|
||||
_ => Ok(child),
|
||||
},
|
||||
Plus => match child {
|
||||
boolean | string | glyph => e,
|
||||
_ => Ok(child),
|
||||
},
|
||||
Not => match child {
|
||||
string | glyph => e,
|
||||
_ => Ok(child),
|
||||
},
|
||||
_ => error().reason(format!("Unary {} is not implemented (yet)", op)),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue