diff --git a/crates/wx-compiler/Cargo.toml b/crates/wx-compiler/Cargo.toml index ead6314..bf5ef2b 100644 --- a/crates/wx-compiler/Cargo.toml +++ b/crates/wx-compiler/Cargo.toml @@ -12,7 +12,7 @@ codespan-reporting = { version = "0.12.0", features = ["serialization"] } indoc = "2.0.6" leb128fmt = "0.1.0" string-interner = "0.19.0" -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0", features = ["derive", "rc"] } [dev-dependencies] indoc = "2" diff --git a/crates/wx-compiler/src/hir/builder.rs b/crates/wx-compiler/src/hir/builder.rs index 919a4d1..e9ab685 100644 --- a/crates/wx-compiler/src/hir/builder.rs +++ b/crates/wx-compiler/src/hir/builder.rs @@ -1061,7 +1061,6 @@ impl<'ast, 'interner> Builder<'ast, 'interner> { } fn report_unused_locals(&mut self, block: &BlockScope) { - println!("reporting unused locals for block: {:?}", block.label); for local in block.locals.iter() { if local.accesses.is_empty() { self.diagnostics.push( diff --git a/crates/wx-compiler/src/mir/builder.rs b/crates/wx-compiler/src/mir/builder.rs index 6f3d18b..627b477 100644 --- a/crates/wx-compiler/src/mir/builder.rs +++ b/crates/wx-compiler/src/mir/builder.rs @@ -1,7 +1,8 @@ use core::panic; +use std::cell::RefCell; +use std::rc::Rc; -use crate::hir::{self, ScopeIndex}; -use crate::{ast, mir}; +use crate::{ast, hir, mir}; pub struct Builder<'a> { hir: &'a hir::HIR, @@ -20,6 +21,12 @@ impl From for mir::Type { } } +#[derive(Debug)] +struct ScopeWithLocals { + scope: Rc>, + locals: Vec>>, +} + impl<'a> Builder<'a> { pub fn build(hir: &hir::HIR) -> mir::MIR { let builder = Builder { hir }; @@ -29,19 +36,20 @@ impl<'a> Builder<'a> { .iter() .map(|func| builder.build_function(func)) .collect(), - globals: hir - .globals - .iter() - .map(|global| mir::Global { - name: global.name.symbol, - ty: builder.to_mir_type(global.ty.clone()), - mutability: match global.mutability { - Some(_) => mir::Mutability::Mutable, - None => mir::Mutability::Const, - }, - value: builder.build_expression(&global.value), - }) - .collect(), + globals: Vec::new(), + // globals: hir + // .globals + // .iter() + // .map(|global| mir::Global { + // name: global.name.symbol, + // ty: builder.to_mir_type(global.ty.clone()), + // mutability: match global.mutability { + // Some(_) => mir::Mutability::Mutable, + // None => mir::Mutability::Const, + // }, + // value: builder.build_expression(&global.value), + // }) + // .collect(), exports: hir.exports.clone(), } } @@ -73,90 +81,54 @@ impl<'a> Builder<'a> { } } - fn build_function(&self, function: &hir::Function) -> mir::Function { - let block = match &function.block.kind { - hir::ExprKind::Block { - expressions, - result, - .. - } => self.build_block_expression( - ScopeIndex(0), - expressions, - match result { - Some(result) => Some(result), - None => None, - }, - self.to_mir_type(function.ty.result), - ), - _ => unreachable!(), - }; + fn build_function(&self, func: &hir::Function) -> mir::Function { + let scopes = self.create_linked_scopes(&func.stack); + let block = self.build_block_expression(&scopes, &func.block); mir::Function { - name: function.name.symbol, - frame: function - .stack - .scopes - .iter() - .map(|scope| mir::BlockScope { - kind: match scope.kind { - hir::BlockKind::Block => mir::BlockKind::Block, - hir::BlockKind::Loop => mir::BlockKind::Loop, - }, - parent: match scope.parent { - Some(index) => Some(mir::ScopeIndex(index.0)), - None => None, - }, - locals: scope - .locals - .iter() - .map(|local| mir::Local { - name: local.name.symbol, - ty: self.to_mir_type(local.ty), - mutability: match local.mutability { - Some(_) => mir::Mutability::Mutable, - None => mir::Mutability::Const, - }, - }) - .collect(), - result: self.to_mir_type(scope.inferred_type.expect("must be typed")), - }) - .collect(), - ty: self.to_mir_function_type(function.ty.clone()), + symbol: func.name.symbol, + ty: self.to_mir_function_type(func.ty.clone()), block, } } - fn build_expression(&self, expr: &hir::Expression) -> mir::Expression { - let ty = self.to_mir_type(match expr.ty { - Some(ty) => ty, - None => panic!("expression type must be defined {expr:?}"), - }); + fn build_expression( + &self, + scopes: &Vec, + expr: &hir::Expression, + ) -> mir::Expression { + let ty = self.to_mir_type(expr.ty.unwrap()); match &expr.kind { - hir::ExprKind::Binary { - operator, - left, - right, - } => self.build_binary_expression(operator.kind, &left, &right, ty), - hir::ExprKind::Unary { operator, operand } => { - self.build_unary_expression(operator.kind, &operand, ty) - } - hir::ExprKind::Bool(value) => mir::Expression { - kind: mir::ExprKind::Bool { value: *value }, + hir::ExprKind::Int(value) => mir::Expression { + kind: mir::ExprKind::Int { value: *value }, ty, }, - hir::ExprKind::Global { global_index } => mir::Expression { - kind: mir::ExprKind::Global { - global_index: global_index.0, - }, + hir::ExprKind::Float(value) => mir::Expression { + kind: mir::ExprKind::Float { value: *value }, ty, }, + hir::ExprKind::Bool(value) => mir::Expression { + kind: mir::ExprKind::Bool { value: *value }, + ty, + }, + hir::ExprKind::Binary { .. } => self.build_binary_expression(scopes, expr), + hir::ExprKind::Unary { .. } => self.build_unary_expression(scopes, expr), hir::ExprKind::Local { local_index, scope_index, - } => mir::Expression { - kind: mir::ExprKind::Local { - local_index: local_index.0, - scope_index: mir::ScopeIndex(scope_index.0), + } => { + let scope = &scopes[scope_index.0 as usize]; + mir::Expression { + kind: mir::ExprKind::Local { + local: Rc::downgrade(&scope.locals[local_index.0 as usize]), + scope: Rc::downgrade(&scope.scope), + }, + ty, + } + } + hir::ExprKind::Global { global_index } => mir::Expression { + kind: mir::ExprKind::Global { + global_index: global_index.0, }, ty, }, @@ -166,14 +138,40 @@ impl<'a> Builder<'a> { }, hir::ExprKind::Call { callee, arguments } => mir::Expression { kind: mir::ExprKind::Call { - callee: Box::new(self.build_expression(callee)), + callee: Box::new(self.build_expression(scopes, callee)), arguments: arguments .into_iter() - .map(|arg| self.build_expression(&arg)) + .map(|arg| self.build_expression(scopes, &arg)) .collect(), }, ty, }, + hir::ExprKind::LocalDeclaration { + local_index, + scope_index, + expr, + .. + } => { + let scope = &scopes[scope_index.0 as usize]; + + mir::Expression { + kind: mir::ExprKind::LocalSet { + local: Rc::downgrade(&scope.locals[local_index.0 as usize]), + scope: Rc::downgrade(&scope.scope), + value: Box::new(self.build_expression(scopes, expr)), + }, + ty, + } + } + hir::ExprKind::Return { value } => mir::Expression { + kind: mir::ExprKind::Return { + value: match value { + Some(value) => Some(Box::new(self.build_expression(scopes, value))), + None => None, + }, + }, + ty: mir::Type::Never, + }, hir::ExprKind::EnumVariant { enum_index, variant_index, @@ -190,77 +188,18 @@ impl<'a> Builder<'a> { ty, } } - hir::ExprKind::LocalDeclaration { - local_index, - scope_index, - expr, - .. - } => match expr.kind { - hir::ExprKind::Int(value) if value == 0 => { - return mir::Expression { - kind: mir::ExprKind::Noop, - ty: mir::Type::Unit, - }; - } - hir::ExprKind::Bool(value) if value == false => { - return mir::Expression { - kind: mir::ExprKind::Noop, - ty: mir::Type::Unit, - }; - } - _ => { - return mir::Expression { - kind: mir::ExprKind::LocalSet { - local_index: local_index.0, - scope_index: mir::ScopeIndex(scope_index.0), - value: Box::new(self.build_expression(expr)), - }, - ty, - }; - } - }, - hir::ExprKind::Return { value } => mir::Expression { - kind: mir::ExprKind::Return { - value: match value { - Some(value) => Some(Box::new(self.build_expression(value))), - None => None, - }, - }, - ty: mir::Type::Never, - }, - hir::ExprKind::Int(value) => mir::Expression { - kind: mir::ExprKind::Int { value: *value }, - ty, - }, - hir::ExprKind::Float(value) => mir::Expression { - kind: mir::ExprKind::Float { value: *value }, - ty, - }, hir::ExprKind::Placeholder => unreachable!(), - hir::ExprKind::Block { - scope_index, - expressions, - result, - } => self.build_block_expression( - *scope_index, - expressions, - match result { - Some(result) => Some(&result), - None => None, - }, - ty, - ), + hir::ExprKind::Block { .. } => self.build_block_expression(scopes, expr), hir::ExprKind::IfElse { condition, else_block, then_block, } => { - let condition = self.build_expression(condition); - let then_block = self.build_expression(then_block); - let else_block = match else_block { - Some(else_block) => Some(self.build_expression(else_block)), - None => None, - }; + let condition = self.build_expression(scopes, condition); + let then_block = self.build_expression(scopes, then_block); + let else_block = else_block + .as_ref() + .map(|expr| self.build_expression(scopes, expr)); mir::Expression { kind: mir::ExprKind::IfElse { @@ -273,9 +212,9 @@ impl<'a> Builder<'a> { } hir::ExprKind::Break { scope_index, value } => mir::Expression { kind: mir::ExprKind::Break { - scope_index: mir::ScopeIndex(scope_index.0), + scope: Rc::downgrade(&scopes[scope_index.0 as usize].scope), value: match value { - Some(value) => Some(Box::new(self.build_expression(value))), + Some(value) => Some(Box::new(self.build_expression(scopes, value))), None => None, }, }, @@ -283,7 +222,7 @@ impl<'a> Builder<'a> { }, hir::ExprKind::Continue { scope_index } => mir::Expression { kind: mir::ExprKind::Continue { - scope_index: mir::ScopeIndex(scope_index.0), + scope: Rc::downgrade(&scopes[scope_index.0 as usize].scope), }, ty: mir::Type::Never, }, @@ -291,165 +230,177 @@ impl<'a> Builder<'a> { kind: mir::ExprKind::Unreachable, ty: mir::Type::Never, }, - hir::ExprKind::Loop { block, scope_index } => { - let block = match &block.kind { - hir::ExprKind::Block { - expressions, - result, - .. - } => self.build_block_expression( - *scope_index, - expressions, - match result { - Some(result) => Some(result), - None => None, - }, - mir::Type::Never, - ), - _ => unreachable!(), - }; + hir::ExprKind::Loop { block, .. } => { + let block = self.build_block_expression(scopes, block); mir::Expression { kind: mir::ExprKind::Loop { - scope_index: mir::ScopeIndex(scope_index.0), block: Box::new(block), }, - ty: mir::Type::Never, + ty, } } hir::ExprKind::Error => panic!("invalid HIR"), } } + fn create_linked_locals( + &self, + start_index: u32, + hir_locals: &[hir::Local], + ) -> Vec>> { + let mut mir_locals = Vec::with_capacity(hir_locals.len()); + let mut prev: Option>> = None; + for (index, hir_local) in hir_locals.iter().enumerate() { + let mir_local = Rc::new(RefCell::new(mir::Local { + index: start_index + index as u32, + symbol: hir_local.name.symbol, + ty: self.to_mir_type(hir_local.ty), + mutability: match hir_local.mutability { + Some(_) => mir::Mutability::Mutable, + None => mir::Mutability::Const, + }, + prev: prev.as_ref().map(Rc::downgrade), + next: None, + })); + if let Some(prev) = &prev { + prev.borrow_mut().next = Some(mir_local.clone()); + } + prev = Some(mir_local.clone()); + mir_locals.push(mir_local); + } + + mir_locals + } + + fn create_linked_scopes(&self, frame: &hir::StackFrame) -> Vec { + let mut scopes: Vec = Vec::with_capacity(frame.scopes.len()); + let mut start_index = 0; + + for (index, scope) in frame.scopes.iter().enumerate() { + let mir_scope = Rc::new(RefCell::new(mir::BlockScope { + index: index as u32, + kind: match scope.kind { + hir::BlockKind::Block => mir::BlockKind::Block, + hir::BlockKind::Loop => mir::BlockKind::Loop, + }, + parent: match scope.parent { + Some(index) => scopes + .get(index.0 as usize) + .map(|scope| Rc::downgrade(&scope.scope)), + None => None, + }, + children: Vec::new(), + locals: None, + result: self.to_mir_type(scope.inferred_type.unwrap()), + })); + + if let Some(index) = scope.parent { + let parent = &scopes.get(index.0 as usize).unwrap().scope; + parent.borrow_mut().children.push(Rc::downgrade(&mir_scope)); + } + + let locals = self.create_linked_locals(start_index, &scope.locals); + start_index += locals.len() as u32; + mir_scope.borrow_mut().locals = locals.first().map(Rc::clone); + + scopes.push(ScopeWithLocals { + scope: mir_scope, + locals, + }); + } + scopes + } + fn build_block_expression( &self, - scope_index: hir::ScopeIndex, - expressions: &[hir::Expression], - result: Option<&hir::Expression>, - ty: mir::Type, + scopes: &Vec, + expr: &hir::Expression, ) -> mir::Expression { - let expressions: Box<_> = expressions - .iter() - .map(|expr| self.build_expression(expr)) - .chain(result.map(|result| self.build_expression(result))) - .collect(); - - mir::Expression { - kind: mir::ExprKind::Block { - scope_index: mir::ScopeIndex(scope_index.0), + match &expr.kind { + hir::ExprKind::Block { + scope_index, expressions, - }, - ty, + result, + } => { + let expressions: Box<_> = expressions + .iter() + .map(|expr| self.build_expression(scopes, expr)) + .chain( + result + .as_ref() + .map(|result| self.build_expression(scopes, result)), + ) + .collect(); + + mir::Expression { + kind: mir::ExprKind::Block { + scope: scopes[scope_index.0 as usize].scope.clone(), + expressions, + }, + ty: self.to_mir_type(expr.ty.unwrap()), + } + } + _ => unreachable!(), } } fn build_unary_expression( &self, - operator: ast::UnOpKind, - operand: &hir::Expression, - ty: mir::Type, + scopes: &Vec, + expr: &hir::Expression, ) -> mir::Expression { - let kind = match operator { - ast::UnOpKind::InvertSign => mir::ExprKind::Neg { - value: Box::new(self.build_expression(operand)), - }, - ast::UnOpKind::Not => mir::ExprKind::Eqz { - value: Box::new(self.build_expression(operand)), - }, - ast::UnOpKind::BitNot => mir::ExprKind::BitNot { - value: Box::new(self.build_expression(operand)), - }, + let (operator, operand) = match &expr.kind { + hir::ExprKind::Unary { operator, operand } => (operator.clone(), operand), + _ => unreachable!(), }; + let ty = self.to_mir_type(expr.ty.unwrap()); + let value = Box::new(self.build_expression(scopes, operand)); - mir::Expression { kind, ty } + mir::Expression { + kind: match operator.kind { + ast::UnOpKind::InvertSign => mir::ExprKind::Neg { value }, + ast::UnOpKind::Not => mir::ExprKind::Eqz { value }, + ast::UnOpKind::BitNot => mir::ExprKind::BitNot { value }, + }, + ty, + } } fn build_binary_expression( &self, - operator: ast::BinOpKind, - lhs: &hir::Expression, - rhs: &hir::Expression, - ty: mir::Type, + scopes: &Vec, + expr: &hir::Expression, ) -> mir::Expression { + let (operator, left, right) = match &expr.kind { + hir::ExprKind::Binary { + operator, + left, + right, + } => (operator, left, right), + _ => unreachable!(), + }; + let ty = self.to_mir_type(expr.ty.unwrap()); + use crate::ast::BinOpKind; - match operator { - BinOpKind::Add => mir::Expression { - kind: mir::ExprKind::Add { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::Sub => mir::Expression { - kind: mir::ExprKind::Sub { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::Mul => mir::Expression { - kind: mir::ExprKind::Mul { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::Div => mir::Expression { - kind: mir::ExprKind::Div { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::Rem => mir::Expression { - kind: mir::ExprKind::Rem { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::Less => mir::Expression { - kind: mir::ExprKind::Less { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::LessEq => mir::Expression { - kind: mir::ExprKind::LessEq { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::Greater => mir::Expression { - kind: mir::ExprKind::Greater { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::GreaterEq => mir::Expression { - kind: mir::ExprKind::GreaterEq { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, + match operator.kind { BinOpKind::Assign => { - let value = self.build_expression(rhs); - match lhs.kind { + let value = self.build_expression(scopes, &right); + match left.kind { hir::ExprKind::Local { local_index, scope_index, - } => mir::Expression { - kind: mir::ExprKind::LocalSet { - local_index: local_index.0, - scope_index: mir::ScopeIndex(scope_index.0), - value: Box::new(value), - }, - ty, - }, + } => { + let scope = &scopes[scope_index.0 as usize]; + mir::Expression { + kind: mir::ExprKind::LocalSet { + local: Rc::downgrade(&scope.locals[local_index.0 as usize]), + scope: Rc::downgrade(&scope.scope), + value: Box::new(value), + }, + ty, + } + } hir::ExprKind::Placeholder => mir::Expression { kind: mir::ExprKind::Drop { value: Box::new(value), @@ -466,199 +417,109 @@ impl<'a> Builder<'a> { _ => unreachable!(), } } - BinOpKind::AddAssign => match lhs.kind { - hir::ExprKind::Local { - local_index, - scope_index, - } => { - let left = self.build_expression(lhs); - let sum_type = left.ty.clone(); - let sum = mir::Expression { - kind: mir::ExprKind::Add { - left: Box::new(left), - right: Box::new(self.build_expression(rhs)), - }, - ty: sum_type, - }; - - mir::Expression { - kind: mir::ExprKind::LocalSet { - local_index: local_index.0, - scope_index: mir::ScopeIndex(scope_index.0), - value: Box::new(sum), - }, - ty, - } - } - _ => unreachable!("add assignment only allowed on local mutable variables"), - }, - BinOpKind::SubAssign => match lhs.kind { - hir::ExprKind::Local { - local_index, - scope_index, - } => { - let left = self.build_expression(lhs); - let value_ty = left.ty.clone(); - let value = mir::Expression { - kind: mir::ExprKind::Sub { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty: value_ty, - }; - - mir::Expression { - kind: mir::ExprKind::LocalSet { - local_index: local_index.0, - scope_index: mir::ScopeIndex(scope_index.0), - value: Box::new(value), - }, - ty, - } - } - _ => unreachable!("sub assignment only allowed on local mutable variables"), - }, - BinOpKind::MulAssign => match lhs.kind { - hir::ExprKind::Local { - local_index, - scope_index, - } => { - let left = self.build_expression(lhs); - let value_type = left.ty.clone(); - let value = mir::Expression { - kind: mir::ExprKind::Mul { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, + BinOpKind::AddAssign + | BinOpKind::SubAssign + | BinOpKind::DivAssign + | BinOpKind::MulAssign + | BinOpKind::RemAssign => { + let hir_left = &left; + let left = Box::new(self.build_expression(scopes, &left)); + let right = Box::new(self.build_expression(scopes, &right)); + let value_type = left.ty; + let value = match operator.kind { + BinOpKind::AddAssign => mir::Expression { + kind: mir::ExprKind::Add { left, right }, ty: value_type, - }; - - mir::Expression { - kind: mir::ExprKind::LocalSet { - local_index: local_index.0, - scope_index: mir::ScopeIndex(scope_index.0), - value: Box::new(value), - }, - ty, - } - } - _ => unreachable!("mul assignment only allowed on local mutable variables"), - }, - BinOpKind::DivAssign => match lhs.kind { - hir::ExprKind::Local { - local_index, - scope_index, - } => { - let left = self.build_expression(lhs); - let value_type = left.ty.clone(); - let value = mir::Expression { - kind: mir::ExprKind::Div { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, + }, + BinOpKind::SubAssign => mir::Expression { + kind: mir::ExprKind::Sub { left, right }, ty: value_type, - }; - - mir::Expression { - kind: mir::ExprKind::LocalSet { - local_index: local_index.0, - scope_index: mir::ScopeIndex(scope_index.0), - value: Box::new(value), - }, - ty, - } - } - _ => unreachable!("div assignment only allowed on local mutable variables"), - }, - BinOpKind::RemAssign => match lhs.kind { - hir::ExprKind::Local { - local_index, - scope_index, - } => { - let left = self.build_expression(lhs); - let value_type = left.ty.clone(); - let value = mir::Expression { - kind: mir::ExprKind::Rem { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, + }, + BinOpKind::MulAssign => mir::Expression { + kind: mir::ExprKind::Mul { left, right }, ty: value_type, - }; + }, + BinOpKind::DivAssign => mir::Expression { + kind: mir::ExprKind::Div { left, right }, + ty: value_type, + }, + BinOpKind::RemAssign => mir::Expression { + kind: mir::ExprKind::Rem { left, right }, + ty: value_type, + }, + _ => unreachable!(), + }; - mir::Expression { - kind: mir::ExprKind::LocalSet { - local_index: local_index.0, - scope_index: mir::ScopeIndex(scope_index.0), + match &hir_left.kind { + hir::ExprKind::Local { + local_index, + scope_index, + } => { + let scope = &scopes[scope_index.0 as usize]; + mir::Expression { + kind: mir::ExprKind::LocalSet { + local: Rc::downgrade(&scope.locals[local_index.0 as usize]), + scope: Rc::downgrade(&scope.scope), + value: Box::new(value), + }, + ty, + } + } + hir::ExprKind::Global { global_index } => mir::Expression { + kind: mir::ExprKind::GlobalSet { + global_index: global_index.0, value: Box::new(value), }, ty, - } + }, + _ => unreachable!(), } - _ => unreachable!("rem assignment only allowed on local mutable variables"), - }, - BinOpKind::BitAnd => mir::Expression { - kind: mir::ExprKind::BitAnd { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::BitOr => mir::Expression { - kind: mir::ExprKind::BitOr { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::BitXor => mir::Expression { - kind: mir::ExprKind::BitXor { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::LeftShift => mir::Expression { - kind: mir::ExprKind::LeftShift { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::RightShift => mir::Expression { - kind: mir::ExprKind::RightShift { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::Eq => mir::Expression { - kind: mir::ExprKind::Eq { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::NotEq => mir::Expression { - kind: mir::ExprKind::NotEq { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::And => mir::Expression { - kind: mir::ExprKind::And { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, - BinOpKind::Or => mir::Expression { - kind: mir::ExprKind::Or { - left: Box::new(self.build_expression(lhs)), - right: Box::new(self.build_expression(rhs)), - }, - ty, - }, + } + BinOpKind::BitAnd + | BinOpKind::BitOr + | BinOpKind::BitXor + | BinOpKind::LeftShift + | BinOpKind::RightShift + | BinOpKind::Eq + | BinOpKind::NotEq + | BinOpKind::And + | BinOpKind::Or + | BinOpKind::Add + | BinOpKind::Sub + | BinOpKind::Mul + | BinOpKind::Div + | BinOpKind::Rem + | BinOpKind::Greater + | BinOpKind::GreaterEq + | BinOpKind::Less + | BinOpKind::LessEq => { + let left = Box::new(self.build_expression(scopes, &left)); + let right = Box::new(self.build_expression(scopes, &right)); + + let kind = match operator.kind { + BinOpKind::BitAnd => mir::ExprKind::BitAnd { left, right }, + BinOpKind::BitOr => mir::ExprKind::BitOr { left, right }, + BinOpKind::BitXor => mir::ExprKind::BitXor { left, right }, + BinOpKind::LeftShift => mir::ExprKind::LeftShift { left, right }, + BinOpKind::RightShift => mir::ExprKind::RightShift { left, right }, + BinOpKind::Eq => mir::ExprKind::Eq { left, right }, + BinOpKind::NotEq => mir::ExprKind::NotEq { left, right }, + BinOpKind::And => mir::ExprKind::And { left, right }, + BinOpKind::Or => mir::ExprKind::Or { left, right }, + BinOpKind::Add => mir::ExprKind::Add { left, right }, + BinOpKind::Sub => mir::ExprKind::Sub { left, right }, + BinOpKind::Mul => mir::ExprKind::Mul { left, right }, + BinOpKind::Div => mir::ExprKind::Div { left, right }, + BinOpKind::Rem => mir::ExprKind::Rem { left, right }, + BinOpKind::Greater => mir::ExprKind::Greater { left, right }, + BinOpKind::GreaterEq => mir::ExprKind::GreaterEq { left, right }, + BinOpKind::Less => mir::ExprKind::Less { left, right }, + BinOpKind::LessEq => mir::ExprKind::LessEq { left, right }, + _ => unreachable!(), + }; + + mir::Expression { kind, ty } + } } } } diff --git a/crates/wx-compiler/src/mir/mod.rs b/crates/wx-compiler/src/mir/mod.rs index 0f015f0..b483f55 100644 --- a/crates/wx-compiler/src/mir/mod.rs +++ b/crates/wx-compiler/src/mir/mod.rs @@ -1,4 +1,7 @@ -use serde::Serialize; +use std::cell::RefCell; +use std::rc::{Rc, Weak}; + +use serde::{Serialize, Serializer}; use string_interner::symbol::SymbolU32; pub mod builder; @@ -14,7 +17,6 @@ pub struct MIR { } pub type FunctionIndex = u32; -pub type LocalIndex = u32; pub type GlobalIndex = u32; #[derive(Debug, Clone, Serialize)] @@ -55,8 +57,9 @@ pub enum Type { pub enum ExprKind { Noop, Local { - scope_index: ScopeIndex, - local_index: LocalIndex, + local: Weak>, + #[serde(serialize_with = "serialize_scope_index")] + scope: Weak>, }, Global { global_index: GlobalIndex, @@ -74,8 +77,9 @@ pub enum ExprKind { value: f64, }, LocalSet { - scope_index: ScopeIndex, - local_index: LocalIndex, + local: Weak>, + #[serde(serialize_with = "serialize_scope_index")] + scope: Weak>, value: Box, }, GlobalSet { @@ -132,15 +136,15 @@ pub enum ExprKind { right: Box, }, Block { - scope_index: ScopeIndex, + scope: Rc>, expressions: Box<[Expression]>, }, Break { - scope_index: ScopeIndex, + scope: Weak>, value: Option>, }, Continue { - scope_index: ScopeIndex, + scope: Weak>, }, Unreachable, IfElse { @@ -188,7 +192,6 @@ pub enum ExprKind { right: Box, }, Loop { - scope_index: ScopeIndex, block: Box, }, Neg { @@ -210,22 +213,23 @@ pub enum Mutability { #[derive(Debug, Serialize)] pub struct Local { - pub name: SymbolU32, + pub index: u32, + pub symbol: SymbolU32, pub ty: Type, pub mutability: Mutability, + #[serde(skip)] + pub next: Option>>, + #[serde(skip)] + pub prev: Option>>, } #[derive(Debug, Serialize)] pub struct Function { - pub name: SymbolU32, + pub symbol: SymbolU32, pub ty: FunctionType, - pub frame: Vec, pub block: Expression, } -#[derive(Debug, Clone, Copy, Serialize)] -pub struct ScopeIndex(pub u32); - #[derive(Debug, Clone, Copy, PartialEq, Serialize)] pub enum BlockKind { Block, @@ -234,12 +238,57 @@ pub enum BlockKind { #[derive(Debug, Serialize)] pub struct BlockScope { + pub index: u32, pub kind: BlockKind, - pub parent: Option, - pub locals: Vec, + #[serde(serialize_with = "serialize_block_scope_parent")] + pub parent: Option>>, + #[serde(serialize_with = "serialize_block_scope_children")] + pub children: Vec>>, + #[serde(skip)] + pub locals: Option>>, pub result: Type, } +fn serialize_block_scope_parent( + parent: &Option>>, + serializer: S, +) -> Result +where + S: Serializer, +{ + parent + .as_ref() + .map(|parent| parent.upgrade().map(|p| p.borrow().index)) + .serialize(serializer) +} + +fn serialize_block_scope_children( + children: &Vec>>, + serializer: S, +) -> Result +where + S: Serializer, +{ + let indicies: Vec<_> = children + .iter() + .map(|child| child.upgrade().map(|child| child.borrow().index)) + .collect(); + indicies.serialize(serializer) +} + +fn serialize_scope_index( + scope: &Weak>, + serializer: S, +) -> Result +where + S: Serializer, +{ + match scope.upgrade() { + Some(scope_ref) => scope_ref.borrow().index.serialize(serializer), + None => serializer.serialize_none(), + } +} + #[derive(Debug, Serialize)] pub struct Global { pub name: SymbolU32, diff --git a/crates/wx-compiler/src/snapshots/wx_compiler__tests__factorial_mir.snap b/crates/wx-compiler/src/snapshots/wx_compiler__tests__factorial_mir.snap index b742cc4..f6ef9d7 100644 --- a/crates/wx-compiler/src/snapshots/wx_compiler__tests__factorial_mir.snap +++ b/crates/wx-compiler/src/snapshots/wx_compiler__tests__factorial_mir.snap @@ -3,28 +3,22 @@ source: crates/wx-compiler/src/tests.rs expression: mir --- functions: - - name: 1 + - symbol: 1 ty: param_count: 1 params_results: - I32 - I32 - frame: - - kind: Block - parent: ~ - locals: - - name: 2 - ty: I32 - mutability: Const - result: I32 - - kind: Block - parent: 0 - locals: [] - result: Never block: kind: Block: - scope_index: 0 + scope: + index: 0 + kind: Block + parent: ~ + children: + - 1 + result: I32 expressions: - kind: IfElse: @@ -34,8 +28,12 @@ functions: left: kind: Local: - scope_index: 0 - local_index: 0 + local: + index: 0 + symbol: 2 + ty: I32 + mutability: Const + scope: 0 ty: I32 right: kind: @@ -46,7 +44,12 @@ functions: then_block: kind: Block: - scope_index: 1 + scope: + index: 1 + kind: Block + parent: 0 + children: [] + result: Never expressions: - kind: Return: @@ -64,8 +67,12 @@ functions: left: kind: Local: - scope_index: 0 - local_index: 0 + local: + index: 0 + symbol: 2 + ty: I32 + mutability: Const + scope: 0 ty: I32 right: kind: @@ -82,8 +89,12 @@ functions: left: kind: Local: - scope_index: 0 - local_index: 0 + local: + index: 0 + symbol: 2 + ty: I32 + mutability: Const + scope: 0 ty: I32 right: kind: diff --git a/crates/wx-compiler/src/snapshots/wx_compiler__tests__factorial_wasm.snap b/crates/wx-compiler/src/snapshots/wx_compiler__tests__factorial_wasm.snap index 75d1dfa..c40be47 100644 --- a/crates/wx-compiler/src/snapshots/wx_compiler__tests__factorial_wasm.snap +++ b/crates/wx-compiler/src/snapshots/wx_compiler__tests__factorial_wasm.snap @@ -23,7 +23,6 @@ exports: name: 1 func_index: 0 code: - expressions: [] functions: - name: 1 locals: diff --git a/crates/wx-compiler/src/snapshots/wx_compiler__tests__func_pointers_mir.snap b/crates/wx-compiler/src/snapshots/wx_compiler__tests__func_pointers_mir.snap index 6a79091..3a644bb 100644 --- a/crates/wx-compiler/src/snapshots/wx_compiler__tests__func_pointers_mir.snap +++ b/crates/wx-compiler/src/snapshots/wx_compiler__tests__func_pointers_mir.snap @@ -3,85 +3,89 @@ source: crates/wx-compiler/src/tests.rs expression: mir --- functions: - - name: 1 + - symbol: 1 ty: param_count: 2 params_results: - I32 - I32 - I32 - frame: - - kind: Block - parent: ~ - locals: - - name: 2 - ty: I32 - mutability: Const - - name: 4 - ty: I32 - mutability: Const - result: I32 block: kind: Block: - scope_index: 0 + scope: + index: 0 + kind: Block + parent: ~ + children: [] + result: I32 expressions: - kind: Add: left: kind: Local: - scope_index: 0 - local_index: 0 + local: + index: 0 + symbol: 2 + ty: I32 + mutability: Const + scope: 0 ty: I32 right: kind: Local: - scope_index: 0 - local_index: 1 + local: + index: 1 + symbol: 4 + ty: I32 + mutability: Const + scope: 0 ty: I32 ty: I32 ty: I32 - - name: 5 + - symbol: 5 ty: param_count: 2 params_results: - I32 - I32 - I32 - frame: - - kind: Block - parent: ~ - locals: - - name: 2 - ty: I32 - mutability: Const - - name: 4 - ty: I32 - mutability: Const - result: I32 block: kind: Block: - scope_index: 0 + scope: + index: 0 + kind: Block + parent: ~ + children: [] + result: I32 expressions: - kind: Sub: left: kind: Local: - scope_index: 0 - local_index: 0 + local: + index: 0 + symbol: 2 + ty: I32 + mutability: Const + scope: 0 ty: I32 right: kind: Local: - scope_index: 0 - local_index: 1 + local: + index: 1 + symbol: 4 + ty: I32 + mutability: Const + scope: 0 ty: I32 ty: I32 ty: I32 - - name: 6 + - symbol: 6 ty: param_count: 3 params_results: @@ -89,76 +93,74 @@ functions: - I32 - I32 - I32 - frame: - - kind: Block - parent: ~ - locals: - - name: 7 - ty: - Function: 0 - mutability: Const - - name: 2 - ty: I32 - mutability: Const - - name: 4 - ty: I32 - mutability: Const - result: I32 block: kind: Block: - scope_index: 0 + scope: + index: 0 + kind: Block + parent: ~ + children: [] + result: I32 expressions: - kind: Call: callee: kind: Local: - scope_index: 0 - local_index: 0 + local: + index: 0 + symbol: 7 + ty: + Function: 0 + mutability: Const + scope: 0 ty: Function: 0 arguments: - kind: Local: - scope_index: 0 - local_index: 1 + local: + index: 1 + symbol: 2 + ty: I32 + mutability: Const + scope: 0 ty: I32 - kind: Local: - scope_index: 0 - local_index: 2 + local: + index: 2 + symbol: 4 + ty: I32 + mutability: Const + scope: 0 ty: I32 ty: I32 ty: I32 - - name: 8 + - symbol: 8 ty: param_count: 0 params_results: - I32 - frame: - - kind: Block - parent: ~ - locals: - - name: 2 - ty: I32 - mutability: Const - - name: 4 - ty: I32 - mutability: Const - - name: 9 - ty: I32 - mutability: Const - result: I32 block: kind: Block: - scope_index: 0 + scope: + index: 0 + kind: Block + parent: ~ + children: [] + result: I32 expressions: - kind: LocalSet: - scope_index: 0 - local_index: 0 + local: + index: 0 + symbol: 2 + ty: I32 + mutability: Const + scope: 0 value: kind: Call: @@ -186,8 +188,12 @@ functions: ty: Unit - kind: LocalSet: - scope_index: 0 - local_index: 1 + local: + index: 1 + symbol: 4 + ty: I32 + mutability: Const + scope: 0 value: kind: Call: @@ -215,8 +221,12 @@ functions: ty: Unit - kind: LocalSet: - scope_index: 0 - local_index: 2 + local: + index: 2 + symbol: 9 + ty: I32 + mutability: Const + scope: 0 value: kind: Int: @@ -228,14 +238,22 @@ functions: left: kind: Local: - scope_index: 0 - local_index: 0 + local: + index: 0 + symbol: 2 + ty: I32 + mutability: Const + scope: 0 ty: I32 right: kind: Local: - scope_index: 0 - local_index: 1 + local: + index: 1 + symbol: 4 + ty: I32 + mutability: Const + scope: 0 ty: I32 ty: I32 ty: I32 diff --git a/crates/wx-compiler/src/snapshots/wx_compiler__tests__func_pointers_wasm.snap b/crates/wx-compiler/src/snapshots/wx_compiler__tests__func_pointers_wasm.snap index dbdb0df..ca84297 100644 --- a/crates/wx-compiler/src/snapshots/wx_compiler__tests__func_pointers_wasm.snap +++ b/crates/wx-compiler/src/snapshots/wx_compiler__tests__func_pointers_wasm.snap @@ -44,7 +44,6 @@ exports: name: 8 func_index: 3 code: - expressions: [] functions: - name: 1 locals: diff --git a/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_ast.snap b/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_ast.snap index 8d2d1f3..15ce086 100644 --- a/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_ast.snap +++ b/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_ast.snap @@ -264,33 +264,33 @@ ast: Identifier: symbol: 5 span: - start: 174 - end: 180 + start: 178 + end: 184 span: - start: 168 - end: 180 + start: 172 + end: 184 span: - start: 168 - end: 180 + start: 172 + end: 184 separator: - start: 180 - end: 181 + start: 184 + end: 185 close: - start: 191 - end: 192 + start: 195 + end: 196 span: start: 158 - end: 192 + end: 196 else_block: ~ span: start: 146 - end: 192 + end: 196 span: start: 146 - end: 192 + end: 196 separator: - start: 192 - end: 193 + start: 196 + end: 197 - inner: Expression: expr: @@ -301,29 +301,29 @@ ast: Identifier: symbol: 5 span: - start: 211 - end: 217 + start: 215 + end: 221 operator: kind: MulAssign span: - start: 218 - end: 220 + start: 222 + end: 224 right: kind: Identifier: symbol: 2 span: - start: 221 - end: 225 + start: 225 + end: 229 span: - start: 211 - end: 225 + start: 215 + end: 229 span: - start: 211 - end: 225 + start: 215 + end: 229 separator: - start: 225 - end: 226 + start: 229 + end: 230 - inner: Expression: expr: @@ -334,52 +334,52 @@ ast: Identifier: symbol: 4 span: - start: 235 - end: 238 + start: 239 + end: 242 operator: kind: SubAssign span: - start: 239 - end: 241 + start: 243 + end: 245 right: kind: Int: value: 1 span: - start: 242 - end: 243 + start: 246 + end: 247 span: - start: 235 - end: 243 + start: 239 + end: 247 span: - start: 235 - end: 243 + start: 239 + end: 247 separator: - start: 243 - end: 244 + start: 247 + end: 248 close: - start: 249 - end: 250 + start: 253 + end: 254 span: start: 136 - end: 250 + end: 254 span: start: 131 - end: 250 + end: 254 span: start: 131 - end: 250 + end: 254 separator: ~ close: - start: 251 - end: 252 + start: 255 + end: 256 span: start: 46 - end: 252 + end: 256 span: start: 7 - end: 252 + end: 256 span: start: 0 - end: 252 + end: 256 diagnostics: [] diff --git a/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_hir.snap b/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_hir.snap index 84a4040..ed952da 100644 --- a/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_hir.snap +++ b/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_hir.snap @@ -32,8 +32,8 @@ hir: mutability: ~ accesses: - span: - start: 221 - end: 225 + start: 225 + end: 229 kind: Read - name: symbol: 4 @@ -55,8 +55,8 @@ hir: end: 152 kind: Read - span: - start: 235 - end: 238 + start: 239 + end: 242 kind: ReadWrite - name: symbol: 5 @@ -70,12 +70,12 @@ hir: end: 109 accesses: - span: - start: 174 - end: 180 + start: 178 + end: 184 kind: Read - span: - start: 211 - end: 217 + start: 215 + end: 221 kind: ReadWrite inferred_type: Primitive: I32 @@ -243,39 +243,39 @@ hir: scope_index: 0 local_index: 2 span: - start: 174 - end: 180 + start: 178 + end: 184 ty: Primitive: I32 span: - start: 168 - end: 180 + start: 172 + end: 184 ty: Never result: ~ span: start: 158 - end: 192 + end: 196 ty: Never else_block: ~ span: start: 146 - end: 192 + end: 196 ty: Unit - kind: Binary: operator: kind: MulAssign span: - start: 218 - end: 220 + start: 222 + end: 224 left: kind: Local: scope_index: 0 local_index: 2 span: - start: 211 - end: 217 + start: 215 + end: 221 ty: Primitive: I32 right: @@ -284,57 +284,57 @@ hir: scope_index: 0 local_index: 0 span: - start: 221 - end: 225 + start: 225 + end: 229 ty: Primitive: I32 span: - start: 211 - end: 225 + start: 215 + end: 229 ty: Unit - kind: Binary: operator: kind: SubAssign span: - start: 239 - end: 241 + start: 243 + end: 245 left: kind: Local: scope_index: 0 local_index: 1 span: - start: 235 - end: 238 + start: 239 + end: 242 ty: Primitive: I32 right: kind: Int: 1 span: - start: 242 - end: 243 + start: 246 + end: 247 ty: Primitive: I32 span: - start: 235 - end: 243 + start: 239 + end: 247 ty: Unit result: ~ span: start: 136 - end: 250 + end: 254 ty: Primitive: I32 span: start: 131 - end: 250 + end: 254 ty: Primitive: I32 span: start: 46 - end: 252 + end: 256 ty: Primitive: I32 enums: [] diff --git a/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_mir.snap b/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_mir.snap index 723853c..d3ebe7d 100644 --- a/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_mir.snap +++ b/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_mir.snap @@ -3,43 +3,24 @@ source: crates/wx-compiler/src/tests.rs expression: mir --- functions: - - name: 1 + - symbol: 1 ty: param_count: 2 params_results: - I32 - I32 - I32 - frame: - - kind: Block - parent: ~ - locals: - - name: 2 - ty: I32 - mutability: Const - - name: 4 - ty: I32 - mutability: Mutable - - name: 5 - ty: I32 - mutability: Mutable - result: I32 - - kind: Block - parent: 0 - locals: [] - result: Never - - kind: Loop - parent: 0 - locals: [] - result: I32 - - kind: Block - parent: 2 - locals: [] - result: Never block: kind: Block: - scope_index: 0 + scope: + index: 0 + kind: Block + parent: ~ + children: + - 1 + - 2 + result: I32 expressions: - kind: IfElse: @@ -49,8 +30,12 @@ functions: left: kind: Local: - scope_index: 0 - local_index: 1 + local: + index: 1 + symbol: 4 + ty: I32 + mutability: Mutable + scope: 0 ty: I32 right: kind: @@ -61,7 +46,12 @@ functions: then_block: kind: Block: - scope_index: 1 + scope: + index: 1 + kind: Block + parent: 0 + children: [] + result: Never expressions: - kind: Return: @@ -76,8 +66,12 @@ functions: ty: Unit - kind: LocalSet: - scope_index: 0 - local_index: 2 + local: + index: 2 + symbol: 5 + ty: I32 + mutability: Mutable + scope: 0 value: kind: Int: @@ -86,11 +80,16 @@ functions: ty: Unit - kind: Loop: - scope_index: 2 block: kind: Block: - scope_index: 2 + scope: + index: 2 + kind: Loop + parent: 0 + children: + - 3 + result: I32 expressions: - kind: IfElse: @@ -100,8 +99,12 @@ functions: left: kind: Local: - scope_index: 0 - local_index: 1 + local: + index: 1 + symbol: 4 + ty: I32 + mutability: Mutable + scope: 0 ty: I32 right: kind: @@ -112,16 +115,31 @@ functions: then_block: kind: Block: - scope_index: 3 + scope: + index: 3 + kind: Block + parent: 2 + children: [] + result: Never expressions: - kind: Break: - scope_index: 2 + scope: + index: 2 + kind: Loop + parent: 0 + children: + - 3 + result: I32 value: kind: Local: - scope_index: 0 - local_index: 2 + local: + index: 2 + symbol: 5 + ty: I32 + mutability: Mutable + scope: 0 ty: I32 ty: Never ty: Never @@ -129,37 +147,57 @@ functions: ty: Unit - kind: LocalSet: - scope_index: 0 - local_index: 2 + local: + index: 2 + symbol: 5 + ty: I32 + mutability: Mutable + scope: 0 value: kind: Mul: left: kind: Local: - scope_index: 0 - local_index: 2 + local: + index: 2 + symbol: 5 + ty: I32 + mutability: Mutable + scope: 0 ty: I32 right: kind: Local: - scope_index: 0 - local_index: 0 + local: + index: 0 + symbol: 2 + ty: I32 + mutability: Const + scope: 0 ty: I32 ty: I32 ty: Unit - kind: LocalSet: - scope_index: 0 - local_index: 1 + local: + index: 1 + symbol: 4 + ty: I32 + mutability: Mutable + scope: 0 value: kind: Sub: left: kind: Local: - scope_index: 0 - local_index: 1 + local: + index: 1 + symbol: 4 + ty: I32 + mutability: Mutable + scope: 0 ty: I32 right: kind: @@ -168,8 +206,8 @@ functions: ty: I32 ty: I32 ty: Unit - ty: Never - ty: Never + ty: I32 + ty: I32 ty: I32 globals: [] exports: diff --git a/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_wasm.snap b/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_wasm.snap index 4c54767..2fd50e4 100644 --- a/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_wasm.snap +++ b/crates/wx-compiler/src/snapshots/wx_compiler__tests__pow_wasm.snap @@ -24,7 +24,6 @@ exports: name: 1 func_index: 0 code: - expressions: [] functions: - name: 1 locals: diff --git a/crates/wx-compiler/src/tests.rs b/crates/wx-compiler/src/tests.rs index 74c7d86..3e1b641 100644 --- a/crates/wx-compiler/src/tests.rs +++ b/crates/wx-compiler/src/tests.rs @@ -1,7 +1,9 @@ -use super::*; use indoc::indoc; use insta::{assert_binary_snapshot, assert_yaml_snapshot}; -use string_interner::{StringInterner, backend::StringBackend}; +use string_interner::StringInterner; +use string_interner::backend::StringBackend; + +use super::*; #[allow(unused)] struct TestCase { @@ -70,7 +72,7 @@ fn pow() { local mut result: i32 = 1; loop { if exp == 0 { - break result; + break result; }; result *= base; diff --git a/crates/wx-compiler/src/wasm/builder.rs b/crates/wx-compiler/src/wasm/builder.rs index 27cc873..8291cad 100644 --- a/crates/wx-compiler/src/wasm/builder.rs +++ b/crates/wx-compiler/src/wasm/builder.rs @@ -1,4 +1,6 @@ +use std::cell::RefCell; use std::collections::HashMap; +use std::rc::Rc; use crate::wasm::{self, TableIndex}; use crate::{hir, mir}; @@ -35,67 +37,82 @@ impl From for wasm::BlockResult { } #[derive(Debug)] -struct FunctionContext<'mir> { - locals: Box<[wasm::Local]>, - scope_offsets: Box<[usize]>, - scopes: &'mir Vec, - scope_index: mir::ScopeIndex, +struct FunctionContext { + pub locals: Vec, + pub local_indices: HashMap, + pub scope: Rc>, } -impl FunctionContext<'_> { - fn get_flat_index( - &self, - scope_index: mir::ScopeIndex, - local_index: mir::LocalIndex, - ) -> wasm::LocalIndex { - let scope_offset = self.scope_offsets[scope_index.0 as usize]; - wasm::LocalIndex(scope_offset as u32 + local_index) +impl FunctionContext { + fn new(root_scope: Rc>) -> Self { + let mut ctx = Self { + locals: Vec::new(), + local_indices: HashMap::new(), + scope: root_scope.clone(), + }; + + ctx.populate_locals(root_scope); + + ctx + } + + fn populate_locals(&mut self, scope: Rc>) { + let mut current_local = scope.borrow().locals.clone(); + loop { + let local = match current_local { + Some(local) => local, + None => break, + }; + + let local_index = wasm::LocalIndex(self.locals.len() as u32); + self.locals.push(wasm::Local { + name: local.borrow().symbol, + ty: wasm::ValueType::try_from(local.borrow().ty).unwrap(), + }); + self.local_indices.insert(local.borrow().index, local_index); + + current_local = local.borrow().next.clone(); + } + + for child_scope in scope.borrow().children.iter() { + self.populate_locals(child_scope.upgrade().unwrap()); + } } - pub fn get_break_depth(&self, target_scope: mir::ScopeIndex) -> Option { - let mut index = self.scope_index; + pub fn get_break_depth(&self, target_scope: Rc>) -> Option { + let mut scope = self.scope.clone(); let mut depth = 0; loop { - let scope = &self.scopes[index.0 as usize]; - depth += match scope.kind { + depth += match scope.borrow().kind { mir::BlockKind::Loop => depth + 2, mir::BlockKind::Block => depth + 1, }; - if index.0 == target_scope.0 { + if scope.borrow().index == target_scope.borrow().index { return Some(depth - 1); } - match scope.parent { - Some(scope_index) => { - index = scope_index; - } - None => return None, - } + let parent = scope.borrow().parent.clone()?; + scope = parent.upgrade().unwrap(); } } - pub fn get_continue_depth(&self, target_scope: mir::ScopeIndex) -> Option { - let mut index = self.scope_index; + pub fn get_continue_depth(&self, target_scope: Rc>) -> Option { + let mut scope = self.scope.clone(); let mut depth = 0; loop { - if index.0 == target_scope.0 { + if scope.borrow().index == target_scope.borrow().index { return Some(depth); } - let scope = self.scopes.get(index.0 as usize).unwrap(); - match scope.parent { - Some(scope_index) => { - index = scope_index; - depth += match scope.kind { - mir::BlockKind::Loop => 2, // 1 for the loop, 1 for the block - mir::BlockKind::Block => 1, - }; - } - None => return None, - } + let parent = scope.borrow().parent.clone()?; + scope = parent.upgrade().unwrap(); + depth += match scope.borrow().kind { + mir::BlockKind::Loop => 2, // 1 for the loop, 1 for the block + mir::BlockKind::Block => 1, + }; } } } @@ -139,7 +156,7 @@ impl Builder { wasm::ExportItem::Function { func_index: wasm::FuncIndex(func_index.0), - name: func.name, + name: func.symbol, } } }) @@ -152,47 +169,20 @@ impl Builder { let type_index = types.entry(ty.clone()).or_insert(next_type_index).clone(); function_signatures.push(type_index); - let expressions = match &func.block.kind { - mir::ExprKind::Block { expressions, .. } => expressions, + let (expressions, scope) = match &func.block.kind { + mir::ExprKind::Block { expressions, scope } => (expressions, scope), _ => unreachable!(), }; - let scope_offsets: Box<_> = func - .frame - .iter() - .scan(0, |offset, scope| { - let current = *offset; - *offset += scope.locals.len(); - Some(current) - }) - .collect(); - - let flat_locals: Box<_> = func - .frame - .iter() - .flat_map(|scope| { - scope.locals.iter().map(|local| wasm::Local { - name: local.name, - ty: wasm::ValueType::try_from(local.ty.clone()).unwrap(), - }) - }) - .collect(); - - let mut ctx = FunctionContext { - locals: flat_locals, - scope_offsets, - scope_index: mir::ScopeIndex(0), - scopes: &func.frame, - }; - + let mut ctx = FunctionContext::new(scope.clone()); let expressions = expressions .iter() .map(|expr| builder.build_expression(&mut ctx, expr)) .collect::, ()>>()?; functions.push(wasm::FunctionBody { - name: func.name, - locals: ctx.locals, + name: func.symbol, + locals: ctx.locals.into_boxed_slice(), expressions, }); } @@ -244,7 +234,6 @@ impl Builder { }, exports: wasm::ExportSection { items: exports }, code: wasm::CodeSection { - expressions: builder.expressions.into_boxed_slice(), functions: functions.into_boxed_slice(), }, }) @@ -270,9 +259,9 @@ impl Builder { } } - fn build_expression<'mir, 'wasm>( + fn build_expression( &mut self, - ctx: &mut FunctionContext<'mir>, + ctx: &mut FunctionContext, expr: &mir::Expression, ) -> Result { match &expr.kind { @@ -475,20 +464,27 @@ impl Builder { Ok(expr) } - mir::ExprKind::Local { - local_index, - scope_index, - } => Ok(wasm::Expression::LocalGet { - local_index: ctx.get_flat_index(*scope_index, *local_index), - }), - mir::ExprKind::LocalSet { - local_index, - scope_index, - value, - } => Ok(wasm::Expression::LocalSet { - local_index: ctx.get_flat_index(*scope_index, *local_index), - value: Box::new(self.build_expression(ctx, &value)?), - }), + mir::ExprKind::Local { local, .. } => { + let local_index = ctx + .local_indices + .get(&local.upgrade().unwrap().borrow().index) + .copied() + .unwrap(); + + Ok(wasm::Expression::LocalGet { local_index }) + } + mir::ExprKind::LocalSet { local, value, .. } => { + let local_index = ctx + .local_indices + .get(&local.upgrade().unwrap().borrow().index) + .copied() + .unwrap(); + + Ok(wasm::Expression::LocalSet { + local_index, + value: Box::new(self.build_expression(ctx, &value)?), + }) + } mir::ExprKind::Global { global_index } => Ok(wasm::Expression::GlobalGet { global_index: wasm::GlobalIndex(*global_index), }), @@ -564,15 +560,12 @@ impl Builder { Ok(expr) } - mir::ExprKind::Block { - expressions, - scope_index, - } => { + mir::ExprKind::Block { expressions, scope } => { let expr = wasm::Expression::Block { expressions: expressions .iter() .map(|expr| { - ctx.scope_index = mir::ScopeIndex(scope_index.0); + ctx.scope = scope.clone(); self.build_expression(ctx, expr) }) .collect::>()?, @@ -583,9 +576,9 @@ impl Builder { }; Ok(expr) } - mir::ExprKind::Loop { scope_index, block } => { - let expressions = match &block.kind { - mir::ExprKind::Block { expressions, .. } => expressions, + mir::ExprKind::Loop { block } => { + let (expressions, scope) = match &block.kind { + mir::ExprKind::Block { expressions, scope } => (expressions, scope), _ => unreachable!(), }; @@ -593,7 +586,7 @@ impl Builder { expressions: expressions .iter() .map(|expr| { - ctx.scope_index = mir::ScopeIndex(scope_index.0); + ctx.scope = scope.clone(); self.build_expression(ctx, expr) }) .chain(std::iter::once(Ok(wasm::Expression::Break { @@ -604,10 +597,9 @@ impl Builder { result: wasm::BlockResult::Empty, }; - let scope = &ctx.scopes[scope_index.0 as usize]; let block_expr = wasm::Expression::Block { expressions: Box::new([loop_expr, wasm::Expression::Unreachable]), - result: match wasm::ValueType::try_from(scope.result) { + result: match wasm::ValueType::try_from(scope.borrow().result) { Ok(ty) => wasm::BlockResult::SingleValue(ty), _ => wasm::BlockResult::Empty, }, @@ -615,16 +607,16 @@ impl Builder { Ok(block_expr) } - mir::ExprKind::Continue { scope_index } => { + mir::ExprKind::Continue { scope } => { let expr = wasm::Expression::Break { - depth: ctx.get_continue_depth(*scope_index).unwrap(), + depth: ctx.get_continue_depth(scope.upgrade().unwrap()).unwrap(), value: None, }; Ok(expr) } - mir::ExprKind::Break { value, scope_index } => { + mir::ExprKind::Break { value, scope } => { let expr = wasm::Expression::Break { - depth: ctx.get_break_depth(*scope_index).unwrap(), + depth: ctx.get_break_depth(scope.upgrade().unwrap()).unwrap(), value: match value { Some(value) => Some(Box::new(self.build_expression(ctx, value)?)), None => None, diff --git a/crates/wx-compiler/src/wasm/mod.rs b/crates/wx-compiler/src/wasm/mod.rs index bf38661..220daf6 100644 --- a/crates/wx-compiler/src/wasm/mod.rs +++ b/crates/wx-compiler/src/wasm/mod.rs @@ -445,7 +445,6 @@ pub struct FunctionBody { #[derive(Debug, Clone, Serialize)] pub struct CodeSection { - expressions: Box<[Expression]>, functions: Box<[FunctionBody]>, }