From cc6e77210dd28e7f6b7716ab890a9d2c04f186e2 Mon Sep 17 00:00:00 2001 From: Artem Melnyk Date: Sun, 20 Jul 2025 16:10:14 +0200 Subject: [PATCH 1/3] wip --- crates/wx-compiler/Cargo.toml | 2 +- crates/wx-compiler/src/mir/builder.rs | 754 ++++++++++--------------- crates/wx-compiler/src/mir/mod.rs | 31 +- crates/wx-compiler/src/wasm/builder.rs | 181 +++--- plot.md | 16 + 5 files changed, 417 insertions(+), 567 deletions(-) create mode 100644 plot.md 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/mir/builder.rs b/crates/wx-compiler/src/mir/builder.rs index 6f3d18b..aab2d5b 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,11 @@ impl From for mir::Type { } } +struct Context { + scopes: Vec>>, + locals: Vec>>, +} + impl<'a> Builder<'a> { pub fn build(hir: &hir::HIR) -> mir::MIR { let builder = Builder { hir }; @@ -29,19 +35,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 +80,55 @@ 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 block = + self.build_block_expression(func, &self.create_linked_scopes(&func.stack), &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()), + name: 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, + func: &hir::Function, + scopes: &Vec>>, + locals: &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(func, scopes, locals, expr) + } + hir::ExprKind::Unary { .. } => self.build_unary_expression(func, scopes, locals, 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), + local: Rc::downgrade(&locals[local_index.0 as usize]), + scope: Rc::downgrade(&scopes[scope_index.0 as usize]), + }, + ty, + }, + hir::ExprKind::Global { global_index } => mir::Expression { + kind: mir::ExprKind::Global { + global_index: global_index.0, }, ty, }, @@ -166,14 +138,38 @@ 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(func, scopes, locals, callee)), arguments: arguments .into_iter() - .map(|arg| self.build_expression(&arg)) + .map(|arg| self.build_expression(func, scopes, locals, &arg)) .collect(), }, ty, }, + hir::ExprKind::LocalDeclaration { + local_index, + scope_index, + expr, + .. + } => mir::Expression { + kind: mir::ExprKind::LocalSet { + local: Rc::downgrade(&locals[local_index.0 as usize]), + scope: Rc::downgrade(&scopes[scope_index.0 as usize]), + value: Box::new(self.build_expression(func, scopes, locals, expr)), + }, + ty, + }, + hir::ExprKind::Return { value } => mir::Expression { + kind: mir::ExprKind::Return { + value: match value { + Some(value) => { + Some(Box::new(self.build_expression(func, scopes, locals, value))) + } + None => None, + }, + }, + ty: mir::Type::Never, + }, hir::ExprKind::EnumVariant { enum_index, variant_index, @@ -190,77 +186,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(func, 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(func, scopes, locals, condition); + let then_block = self.build_expression(func, scopes, locals, then_block); + let else_block = else_block + .as_ref() + .map(|expr| self.build_expression(func, scopes, locals, expr)); mir::Expression { kind: mir::ExprKind::IfElse { @@ -273,9 +210,11 @@ 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]), value: match value { - Some(value) => Some(Box::new(self.build_expression(value))), + Some(value) => { + Some(Box::new(self.build_expression(func, scopes, locals, 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]), }, ty: mir::Type::Never, }, @@ -292,26 +231,11 @@ impl<'a> Builder<'a> { 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!(), - }; + let block = self.build_block_expression(func, scopes, block); mir::Expression { kind: mir::ExprKind::Loop { - scope_index: mir::ScopeIndex(scope_index.0), + scope: scopes[scope_index.0 as usize].clone(), block: Box::new(block), }, ty: mir::Type::Never, @@ -321,131 +245,148 @@ impl<'a> Builder<'a> { } } + fn create_linked_locals(&self, hir_locals: &[hir::Local]) -> Vec>> { + let mut mir_locals = Vec::with_capacity(hir_locals.len()); + let mut prev: Option>> = None; + for hir_local in hir_locals { + let mir_local = Rc::new(RefCell::new(mir::Local { + name: 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()); + for scope in &frame.scopes { + let mir_scope = Rc::new(RefCell::new(mir::BlockScope { + 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(Rc::downgrade), + 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(); + parent.borrow_mut().children.push(Rc::downgrade(&mir_scope)); + } + scopes.push(mir_scope); + } + scopes + } + fn build_block_expression( &self, - scope_index: hir::ScopeIndex, - expressions: &[hir::Expression], - result: Option<&hir::Expression>, - ty: mir::Type, + func: &hir::Function, + 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 locals = + self.create_linked_locals(&func.stack.scopes[scope_index.0 as usize].locals); + + let expressions: Box<_> = expressions + .iter() + .map(|expr| self.build_expression(func, scopes, &locals, expr)) + .chain( + result + .as_ref() + .map(|result| self.build_expression(func, scopes, &locals, result)), + ) + .collect(); + + let scope = scopes[scope_index.0 as usize].clone(); + scope.borrow_mut().locals = locals.into_iter().next(); + + mir::Expression { + kind: mir::ExprKind::Block { + scope: scopes[scope_index.0 as usize].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, + func: &hir::Function, + scopes: &Vec>>, + locals: &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(func, scopes, locals, 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, + func: &hir::Function, + scopes: &Vec>>, + locals: &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(func, scopes, locals, &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), + local: Rc::downgrade(&locals[local_index.0 as usize]), + scope: Rc::downgrade(&scopes[scope_index.0 as usize]), value: Box::new(value), }, ty, @@ -466,199 +407,106 @@ 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(func, scopes, locals, &left)); + let right = Box::new(self.build_expression(func, scopes, locals, &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, + }, + 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 { + match &hir_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), + local: Rc::downgrade(&locals[local_index.0 as usize]), + scope: Rc::downgrade(&scopes[scope_index.0 as usize]), 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)), - }, - ty: value_type, - }; - - mir::Expression { - kind: mir::ExprKind::LocalSet { - local_index: local_index.0, - scope_index: mir::ScopeIndex(scope_index.0), + }, + 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(func, scopes, locals, &left)); + let right = Box::new(self.build_expression(func, scopes, locals, &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..4bdb4bd 100644 --- a/crates/wx-compiler/src/mir/mod.rs +++ b/crates/wx-compiler/src/mir/mod.rs @@ -1,3 +1,6 @@ +use std::cell::RefCell; +use std::rc::{Rc, Weak}; + use serde::Serialize; use string_interner::symbol::SymbolU32; @@ -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,8 @@ pub enum Type { pub enum ExprKind { Noop, Local { - scope_index: ScopeIndex, - local_index: LocalIndex, + scope: Weak>, + local: Weak>, }, Global { global_index: GlobalIndex, @@ -74,8 +76,8 @@ pub enum ExprKind { value: f64, }, LocalSet { - scope_index: ScopeIndex, - local_index: LocalIndex, + scope: Weak>, + local: Weak>, value: Box, }, GlobalSet { @@ -132,15 +134,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 +190,7 @@ pub enum ExprKind { right: Box, }, Loop { - scope_index: ScopeIndex, + scope: Rc>, block: Box, }, Neg { @@ -213,19 +215,17 @@ pub struct Local { pub name: SymbolU32, pub ty: Type, pub mutability: Mutability, + pub next: Option>>, + pub prev: Option>>, } #[derive(Debug, Serialize)] pub struct Function { pub name: 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, @@ -235,8 +235,9 @@ pub enum BlockKind { #[derive(Debug, Serialize)] pub struct BlockScope { pub kind: BlockKind, - pub parent: Option, - pub locals: Vec, + pub parent: Option>>, + pub children: Vec>>, + pub locals: Option>>, pub result: Type, } diff --git a/crates/wx-compiler/src/wasm/builder.rs b/crates/wx-compiler/src/wasm/builder.rs index 27cc873..f0b9a59 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,74 @@ 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<*const RefCell, wasm::LocalIndex>, + 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>) { + for local in scope.borrow().locals.iter() { + let local_index = wasm::LocalIndex(self.locals.len() as u32); + self.locals.push(wasm::Local { + name: local.borrow().name, + ty: wasm::ValueType::try_from(local.borrow().ty).unwrap(), + }); + self.local_indices.insert(Rc::as_ptr(local), local_index); + } + + 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.as_ptr() == target_scope.as_ptr() { 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.as_ptr() == target_scope.as_ptr() { 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, + }; } } } @@ -152,39 +161,12 @@ 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)) @@ -192,7 +174,7 @@ impl Builder { functions.push(wasm::FunctionBody { name: func.name, - locals: ctx.locals, + locals: ctx.locals.into_boxed_slice(), expressions, }); } @@ -270,9 +252,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 +457,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(&Rc::as_ptr(&local.upgrade().unwrap())) + .copied() + .unwrap(); + + Ok(wasm::Expression::LocalGet { local_index }) + } + mir::ExprKind::LocalSet { local, value, .. } => { + let local_index = ctx + .local_indices + .get(&Rc::as_ptr(&local.upgrade().unwrap())) + .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 +553,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,7 +569,7 @@ impl Builder { }; Ok(expr) } - mir::ExprKind::Loop { scope_index, block } => { + mir::ExprKind::Loop { scope, block } => { let expressions = match &block.kind { mir::ExprKind::Block { expressions, .. } => expressions, _ => unreachable!(), @@ -593,7 +579,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 +590,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 +600,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/plot.md b/plot.md new file mode 100644 index 0000000..6592855 --- /dev/null +++ b/plot.md @@ -0,0 +1,16 @@ +# Intro (hook) + +Hi. You know, being bored software engineer, I spent last 6 month diving deep into compilers and language design. And, as a result I built a compiler for writing high level web assembly. I want to share my process of building and learning this stuff, so you can maybe learns something as well, or at least have a fun time watching while eating. + +In this video we will explore: +What web assembly is? +How to write it by hand? (it’s actually pretty easy) +Why wasm is a better version of jvm bytecode? +How to build lexers, parsers, typechecker? +Type Inference, never type, control flow, unreachable code??? + +That’s a lot. I will try to explain it as simple as possible, and of course, it’s just my interpretation of information so I may be incorrect in some details. Correct me if I’m wrong. + +# Introduction to WASM + +You probably know, assembly is this low level language that is basically consists of instructions for specific processor architecture. This is probably the biggest problem with sharing our code, as we have different OS, processors, calling conventions which makes it difficult to distribute software. You need to compile it for every possible instruction set, os etc. But we know web, it’s different, on the web we don’t care if you are on x86, arm, linux, macos, windows. This is mostly because of interpreted nature of javascript. That's all good, but you know, this kinda limits the developers, cause now must write everything in javascript, which is not the best language for everything, because of its dynamic nature, garbage collection, unalble to control memory, etc. Wouldn't it be great if we could write our code in any language and run it everywhere? That's basically what web assembly is. It's this low level language, or more precisely bytecode format that is designed to be a compilation target for other langauges. From 55dd3c9e18c375de7a2317b6bae2029a40f4a8ed Mon Sep 17 00:00:00 2001 From: Artem Melnyk Date: Sun, 20 Jul 2025 23:41:49 +0200 Subject: [PATCH 2/3] wip --- crates/wx-compiler/src/hir/builder.rs | 1 - crates/wx-compiler/src/mir/builder.rs | 199 ++++++++++-------- crates/wx-compiler/src/mir/mod.rs | 60 +++++- .../wx_compiler__tests__factorial_mir.snap | 53 +++-- .../wx_compiler__tests__factorial_wasm.snap | 1 - ...wx_compiler__tests__func_pointers_mir.snap | 184 ++++++++-------- ...x_compiler__tests__func_pointers_wasm.snap | 1 - .../wx_compiler__tests__pow_ast.snap | 98 ++++----- .../wx_compiler__tests__pow_hir.snap | 66 +++--- .../wx_compiler__tests__pow_mir.snap | 144 ++++++++----- .../wx_compiler__tests__pow_wasm.snap | 1 - crates/wx-compiler/src/tests.rs | 8 +- crates/wx-compiler/src/wasm/builder.rs | 35 +-- crates/wx-compiler/src/wasm/mod.rs | 1 - 14 files changed, 492 insertions(+), 360 deletions(-) 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 aab2d5b..627b477 100644 --- a/crates/wx-compiler/src/mir/builder.rs +++ b/crates/wx-compiler/src/mir/builder.rs @@ -21,8 +21,9 @@ impl From for mir::Type { } } -struct Context { - scopes: Vec>>, +#[derive(Debug)] +struct ScopeWithLocals { + scope: Rc>, locals: Vec>>, } @@ -81,11 +82,11 @@ impl<'a> Builder<'a> { } fn build_function(&self, func: &hir::Function) -> mir::Function { - let block = - self.build_block_expression(func, &self.create_linked_scopes(&func.stack), &func.block); + let scopes = self.create_linked_scopes(&func.stack); + let block = self.build_block_expression(&scopes, &func.block); mir::Function { - name: func.name.symbol, + symbol: func.name.symbol, ty: self.to_mir_function_type(func.ty.clone()), block, } @@ -93,9 +94,7 @@ impl<'a> Builder<'a> { fn build_expression( &self, - func: &hir::Function, - scopes: &Vec>>, - locals: &Vec>>, + scopes: &Vec, expr: &hir::Expression, ) -> mir::Expression { let ty = self.to_mir_type(expr.ty.unwrap()); @@ -112,20 +111,21 @@ impl<'a> Builder<'a> { kind: mir::ExprKind::Bool { value: *value }, ty, }, - hir::ExprKind::Binary { .. } => { - self.build_binary_expression(func, scopes, locals, expr) - } - hir::ExprKind::Unary { .. } => self.build_unary_expression(func, scopes, locals, expr), + 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: Rc::downgrade(&locals[local_index.0 as usize]), - scope: Rc::downgrade(&scopes[scope_index.0 as usize]), - }, - ty, - }, + } => { + 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, @@ -138,10 +138,10 @@ impl<'a> Builder<'a> { }, hir::ExprKind::Call { callee, arguments } => mir::Expression { kind: mir::ExprKind::Call { - callee: Box::new(self.build_expression(func, scopes, locals, callee)), + callee: Box::new(self.build_expression(scopes, callee)), arguments: arguments .into_iter() - .map(|arg| self.build_expression(func, scopes, locals, &arg)) + .map(|arg| self.build_expression(scopes, &arg)) .collect(), }, ty, @@ -151,20 +151,22 @@ impl<'a> Builder<'a> { scope_index, expr, .. - } => mir::Expression { - kind: mir::ExprKind::LocalSet { - local: Rc::downgrade(&locals[local_index.0 as usize]), - scope: Rc::downgrade(&scopes[scope_index.0 as usize]), - value: Box::new(self.build_expression(func, scopes, locals, expr)), - }, - 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(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(func, scopes, locals, value))) - } + Some(value) => Some(Box::new(self.build_expression(scopes, value))), None => None, }, }, @@ -187,17 +189,17 @@ impl<'a> Builder<'a> { } } hir::ExprKind::Placeholder => unreachable!(), - hir::ExprKind::Block { .. } => self.build_block_expression(func, scopes, expr), + hir::ExprKind::Block { .. } => self.build_block_expression(scopes, expr), hir::ExprKind::IfElse { condition, else_block, then_block, } => { - let condition = self.build_expression(func, scopes, locals, condition); - let then_block = self.build_expression(func, scopes, locals, then_block); + 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(func, scopes, locals, expr)); + .map(|expr| self.build_expression(scopes, expr)); mir::Expression { kind: mir::ExprKind::IfElse { @@ -210,11 +212,9 @@ impl<'a> Builder<'a> { } hir::ExprKind::Break { scope_index, value } => mir::Expression { kind: mir::ExprKind::Break { - scope: Rc::downgrade(&scopes[scope_index.0 as usize]), + scope: Rc::downgrade(&scopes[scope_index.0 as usize].scope), value: match value { - Some(value) => { - Some(Box::new(self.build_expression(func, scopes, locals, value))) - } + Some(value) => Some(Box::new(self.build_expression(scopes, value))), None => None, }, }, @@ -222,7 +222,7 @@ impl<'a> Builder<'a> { }, hir::ExprKind::Continue { scope_index } => mir::Expression { kind: mir::ExprKind::Continue { - scope: Rc::downgrade(&scopes[scope_index.0 as usize]), + scope: Rc::downgrade(&scopes[scope_index.0 as usize].scope), }, ty: mir::Type::Never, }, @@ -230,27 +230,31 @@ impl<'a> Builder<'a> { kind: mir::ExprKind::Unreachable, ty: mir::Type::Never, }, - hir::ExprKind::Loop { block, scope_index } => { - let block = self.build_block_expression(func, scopes, block); + hir::ExprKind::Loop { block, .. } => { + let block = self.build_block_expression(scopes, block); mir::Expression { kind: mir::ExprKind::Loop { - scope: scopes[scope_index.0 as usize].clone(), block: Box::new(block), }, - ty: mir::Type::Never, + ty, } } hir::ExprKind::Error => panic!("invalid HIR"), } } - fn create_linked_locals(&self, hir_locals: &[hir::Local]) -> Vec>> { + 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 hir_local in hir_locals { + for (index, hir_local) in hir_locals.iter().enumerate() { let mir_local = Rc::new(RefCell::new(mir::Local { - name: hir_local.name.symbol, + 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, @@ -265,19 +269,25 @@ impl<'a> Builder<'a> { 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()); - for scope in &frame.scopes { + 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(Rc::downgrade), + Some(index) => scopes + .get(index.0 as usize) + .map(|scope| Rc::downgrade(&scope.scope)), None => None, }, children: Vec::new(), @@ -286,18 +296,25 @@ impl<'a> Builder<'a> { })); if let Some(index) = scope.parent { - let parent = scopes.get(index.0 as usize).unwrap(); + let parent = &scopes.get(index.0 as usize).unwrap().scope; parent.borrow_mut().children.push(Rc::downgrade(&mir_scope)); } - scopes.push(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, - func: &hir::Function, - scopes: &Vec>>, + scopes: &Vec, expr: &hir::Expression, ) -> mir::Expression { match &expr.kind { @@ -306,25 +323,19 @@ impl<'a> Builder<'a> { expressions, result, } => { - let locals = - self.create_linked_locals(&func.stack.scopes[scope_index.0 as usize].locals); - let expressions: Box<_> = expressions .iter() - .map(|expr| self.build_expression(func, scopes, &locals, expr)) + .map(|expr| self.build_expression(scopes, expr)) .chain( result .as_ref() - .map(|result| self.build_expression(func, scopes, &locals, result)), + .map(|result| self.build_expression(scopes, result)), ) .collect(); - let scope = scopes[scope_index.0 as usize].clone(); - scope.borrow_mut().locals = locals.into_iter().next(); - mir::Expression { kind: mir::ExprKind::Block { - scope: scopes[scope_index.0 as usize].clone(), + scope: scopes[scope_index.0 as usize].scope.clone(), expressions, }, ty: self.to_mir_type(expr.ty.unwrap()), @@ -336,9 +347,7 @@ impl<'a> Builder<'a> { fn build_unary_expression( &self, - func: &hir::Function, - scopes: &Vec>>, - locals: &Vec>>, + scopes: &Vec, expr: &hir::Expression, ) -> mir::Expression { let (operator, operand) = match &expr.kind { @@ -346,7 +355,7 @@ impl<'a> Builder<'a> { _ => unreachable!(), }; let ty = self.to_mir_type(expr.ty.unwrap()); - let value = Box::new(self.build_expression(func, scopes, locals, operand)); + let value = Box::new(self.build_expression(scopes, operand)); mir::Expression { kind: match operator.kind { @@ -360,9 +369,7 @@ impl<'a> Builder<'a> { fn build_binary_expression( &self, - func: &hir::Function, - scopes: &Vec>>, - locals: &Vec>>, + scopes: &Vec, expr: &hir::Expression, ) -> mir::Expression { let (operator, left, right) = match &expr.kind { @@ -378,19 +385,22 @@ impl<'a> Builder<'a> { use crate::ast::BinOpKind; match operator.kind { BinOpKind::Assign => { - let value = self.build_expression(func, scopes, locals, &right); + let value = self.build_expression(scopes, &right); match left.kind { hir::ExprKind::Local { local_index, scope_index, - } => mir::Expression { - kind: mir::ExprKind::LocalSet { - local: Rc::downgrade(&locals[local_index.0 as usize]), - scope: Rc::downgrade(&scopes[scope_index.0 as usize]), - 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), @@ -413,8 +423,8 @@ impl<'a> Builder<'a> { | BinOpKind::MulAssign | BinOpKind::RemAssign => { let hir_left = &left; - let left = Box::new(self.build_expression(func, scopes, locals, &left)); - let right = Box::new(self.build_expression(func, scopes, locals, &right)); + 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 { @@ -444,14 +454,17 @@ impl<'a> Builder<'a> { hir::ExprKind::Local { local_index, scope_index, - } => mir::Expression { - kind: mir::ExprKind::LocalSet { - local: Rc::downgrade(&locals[local_index.0 as usize]), - scope: Rc::downgrade(&scopes[scope_index.0 as usize]), - 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::Global { global_index } => mir::Expression { kind: mir::ExprKind::GlobalSet { global_index: global_index.0, @@ -480,8 +493,8 @@ impl<'a> Builder<'a> { | BinOpKind::GreaterEq | BinOpKind::Less | BinOpKind::LessEq => { - let left = Box::new(self.build_expression(func, scopes, locals, &left)); - let right = Box::new(self.build_expression(func, scopes, locals, &right)); + 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 }, diff --git a/crates/wx-compiler/src/mir/mod.rs b/crates/wx-compiler/src/mir/mod.rs index 4bdb4bd..b483f55 100644 --- a/crates/wx-compiler/src/mir/mod.rs +++ b/crates/wx-compiler/src/mir/mod.rs @@ -1,7 +1,7 @@ use std::cell::RefCell; use std::rc::{Rc, Weak}; -use serde::Serialize; +use serde::{Serialize, Serializer}; use string_interner::symbol::SymbolU32; pub mod builder; @@ -57,8 +57,9 @@ pub enum Type { pub enum ExprKind { Noop, Local { - scope: Weak>, local: Weak>, + #[serde(serialize_with = "serialize_scope_index")] + scope: Weak>, }, Global { global_index: GlobalIndex, @@ -76,8 +77,9 @@ pub enum ExprKind { value: f64, }, LocalSet { - scope: Weak>, local: Weak>, + #[serde(serialize_with = "serialize_scope_index")] + scope: Weak>, value: Box, }, GlobalSet { @@ -190,7 +192,6 @@ pub enum ExprKind { right: Box, }, Loop { - scope: Rc>, block: Box, }, Neg { @@ -212,16 +213,19 @@ 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 block: Expression, } @@ -234,13 +238,57 @@ pub enum BlockKind { #[derive(Debug, Serialize)] pub struct BlockScope { + pub index: u32, pub kind: BlockKind, + #[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 f0b9a59..8291cad 100644 --- a/crates/wx-compiler/src/wasm/builder.rs +++ b/crates/wx-compiler/src/wasm/builder.rs @@ -39,7 +39,7 @@ impl From for wasm::BlockResult { #[derive(Debug)] struct FunctionContext { pub locals: Vec, - pub local_indices: HashMap<*const RefCell, wasm::LocalIndex>, + pub local_indices: HashMap, pub scope: Rc>, } @@ -57,13 +57,21 @@ impl FunctionContext { } fn populate_locals(&mut self, scope: Rc>) { - for local in scope.borrow().locals.iter() { + 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().name, + name: local.borrow().symbol, ty: wasm::ValueType::try_from(local.borrow().ty).unwrap(), }); - self.local_indices.insert(Rc::as_ptr(local), local_index); + self.local_indices.insert(local.borrow().index, local_index); + + current_local = local.borrow().next.clone(); } for child_scope in scope.borrow().children.iter() { @@ -81,7 +89,7 @@ impl FunctionContext { mir::BlockKind::Block => depth + 1, }; - if scope.as_ptr() == target_scope.as_ptr() { + if scope.borrow().index == target_scope.borrow().index { return Some(depth - 1); } @@ -95,7 +103,7 @@ impl FunctionContext { let mut depth = 0; loop { - if scope.as_ptr() == target_scope.as_ptr() { + if scope.borrow().index == target_scope.borrow().index { return Some(depth); } @@ -148,7 +156,7 @@ impl Builder { wasm::ExportItem::Function { func_index: wasm::FuncIndex(func_index.0), - name: func.name, + name: func.symbol, } } }) @@ -173,7 +181,7 @@ impl Builder { .collect::, ()>>()?; functions.push(wasm::FunctionBody { - name: func.name, + name: func.symbol, locals: ctx.locals.into_boxed_slice(), expressions, }); @@ -226,7 +234,6 @@ impl Builder { }, exports: wasm::ExportSection { items: exports }, code: wasm::CodeSection { - expressions: builder.expressions.into_boxed_slice(), functions: functions.into_boxed_slice(), }, }) @@ -460,7 +467,7 @@ impl Builder { mir::ExprKind::Local { local, .. } => { let local_index = ctx .local_indices - .get(&Rc::as_ptr(&local.upgrade().unwrap())) + .get(&local.upgrade().unwrap().borrow().index) .copied() .unwrap(); @@ -469,7 +476,7 @@ impl Builder { mir::ExprKind::LocalSet { local, value, .. } => { let local_index = ctx .local_indices - .get(&Rc::as_ptr(&local.upgrade().unwrap())) + .get(&local.upgrade().unwrap().borrow().index) .copied() .unwrap(); @@ -569,9 +576,9 @@ impl Builder { }; Ok(expr) } - mir::ExprKind::Loop { scope, 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!(), }; 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]>, } From 9736baa966c671b2a599b680ef05b1f8c1084c61 Mon Sep 17 00:00:00 2001 From: Artem Melnyk Date: Sun, 20 Jul 2025 23:43:46 +0200 Subject: [PATCH 3/3] wip --- plot.md | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 plot.md diff --git a/plot.md b/plot.md deleted file mode 100644 index 6592855..0000000 --- a/plot.md +++ /dev/null @@ -1,16 +0,0 @@ -# Intro (hook) - -Hi. You know, being bored software engineer, I spent last 6 month diving deep into compilers and language design. And, as a result I built a compiler for writing high level web assembly. I want to share my process of building and learning this stuff, so you can maybe learns something as well, or at least have a fun time watching while eating. - -In this video we will explore: -What web assembly is? -How to write it by hand? (it’s actually pretty easy) -Why wasm is a better version of jvm bytecode? -How to build lexers, parsers, typechecker? -Type Inference, never type, control flow, unreachable code??? - -That’s a lot. I will try to explain it as simple as possible, and of course, it’s just my interpretation of information so I may be incorrect in some details. Correct me if I’m wrong. - -# Introduction to WASM - -You probably know, assembly is this low level language that is basically consists of instructions for specific processor architecture. This is probably the biggest problem with sharing our code, as we have different OS, processors, calling conventions which makes it difficult to distribute software. You need to compile it for every possible instruction set, os etc. But we know web, it’s different, on the web we don’t care if you are on x86, arm, linux, macos, windows. This is mostly because of interpreted nature of javascript. That's all good, but you know, this kinda limits the developers, cause now must write everything in javascript, which is not the best language for everything, because of its dynamic nature, garbage collection, unalble to control memory, etc. Wouldn't it be great if we could write our code in any language and run it everywhere? That's basically what web assembly is. It's this low level language, or more precisely bytecode format that is designed to be a compilation target for other langauges.