diff --git a/src/ir/generate.rs b/src/ir/generate.rs deleted file mode 100644 index 1229933..0000000 --- a/src/ir/generate.rs +++ /dev/null @@ -1,251 +0,0 @@ -/* -use crate::{Expression, ExpressionKind, Statement, StatementKind}; - -use super::*; - -impl Compiler { - pub fn generate(&mut self, statements: Vec) { - 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); - } - }, - } - } -} -*/ diff --git a/src/ir/mod.rs b/src/ir/mod.rs deleted file mode 100644 index 9effe5b..0000000 --- a/src/ir/mod.rs +++ /dev/null @@ -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, ""), - EndFunc => write!(f, ""), - 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, - 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) { - 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; - } -} -*/ diff --git a/src/ir/wasm.rs b/src/ir/wasm.rs deleted file mode 100644 index 75aa94a..0000000 --- a/src/ir/wasm.rs +++ /dev/null @@ -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 { - u32::from_str_radix(input, base as u32) - .ok() - .map(|i| format!("{i}")) -} - -fn convert_sys_int(input: &str, base: Base) -> Option { - i32::from_str_radix(input, base as u32) - .ok() - .map(|i| format!("{i}")) -} - -fn convert_sys_real(input: &str) -> Option { - input.parse::().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 { - 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 { - 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::().ok().map(|f| format!("{f}")), - p::r64 => i.parse::().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!(), - }) - } -} -*/ diff --git a/src/main.rs b/src/main.rs index 7b0746a..72676c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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(()) } diff --git a/src/semantic/analyzer.rs b/src/semantic/analyzer.rs deleted file mode 100644 index 34e2609..0000000 --- a/src/semantic/analyzer.rs +++ /dev/null @@ -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, - sym_table: HashMap, - undo_stack: Vec, - path: Vec, - 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) -> Result> { - todo!() -} diff --git a/src/semantic/builtin.rs b/src/semantic/builtin.rs deleted file mode 100644 index 4d5a054..0000000 --- a/src/semantic/builtin.rs +++ /dev/null @@ -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 { - let mut uids = Primitive::ALL.map(|p| p.mangle()).to_vec(); - uids.push(nothing()); - uids -} diff --git a/src/semantic/ir.rs b/src/semantic/ir.rs deleted file mode 100644 index c1cae87..0000000 --- a/src/semantic/ir.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::{BinaryOp, UnaryOp}; - -use super::{Type, SID, TID}; - -#[derive(Clone, Debug)] -pub struct IrBlock { - nodes: Vec, -} - -#[derive(Clone, Debug)] -pub enum IrNode { - Declaration { - uid: SID, - mutable: bool, - size: usize, - value: IrExpr, - }, - Function { - uid: SID, - parameters: Vec, - 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, - }, - BinOp { - op: BinaryOp, - left: Box, - right: Box, - }, - Block(IrBlock), - Call { - function: SID, - args: Vec, - }, -} diff --git a/src/semantic/mod.rs b/src/semantic/mod.rs index 0b84b7b..582ce87 100644 --- a/src/semantic/mod.rs +++ b/src/semantic/mod.rs @@ -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, - member_types: Vec, + field_names: Vec, + field_types: Vec, }, - Alias(TID), + /// Non-capturing function type Function { - name: String, - arg_names: Vec, - arg_types: Vec, + field_types: Vec, + returns: Box, }, -} - -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), } diff --git a/src/semantic/names.rs b/src/semantic/names.rs deleted file mode 100644 index 92d8f5d..0000000 --- a/src/semantic/names.rs +++ /dev/null @@ -1,16 +0,0 @@ -// ::= "$" -// ::= {}* -// ::= -// ::= <_a-zA-Z> {<_a-zA-Z0-9>}* -// ::= {<0-9>}+ -// ::= {}* - -pub fn mangle(path: Vec, salt: &str) -> String { - let mut buf: Vec = 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() -} diff --git a/src/semantic/primitives.rs b/src/semantic/primitives.rs deleted file mode 100644 index 419a85f..0000000 --- a/src/semantic/primitives.rs +++ /dev/null @@ -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 { - 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 { - 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 { - 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 { - 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)), - } - } -}