diff --git a/crates/oxide_compiler/src/compiler.rs b/crates/oxide_compiler/src/compiler.rs index 191f5917..7322cddc 100644 --- a/crates/oxide_compiler/src/compiler.rs +++ b/crates/oxide_compiler/src/compiler.rs @@ -2,18 +2,10 @@ use crate::module::CompiledModule; use crate::opcode::{self, OpCode}; use crate::symbol_table::SymbolTable; +pub use crate::hash::structural_hash; +pub use crate::module::Constant; pub use oxide_parser::{BinaryOperator, Expression, Statement, UnaryOperator}; -/// Literal constant stored in bytecode module's constant pool. -#[derive(Debug, Clone, PartialEq)] -pub enum Constant { - Number(f64), - String(String), - Boolean(bool), - Null, - Undefined, -} - pub struct Compiler; struct CompileCtx { @@ -536,92 +528,3 @@ impl Compiler { } } } - -pub fn structural_hash(program: &oxide_parser::Program) -> u64 { - use std::hash::Hasher; - - let mut h = rustc_hash::FxHasher::default(); - - for stmt in &program.body { - hash_statement(stmt, &mut h); - } - - h.finish() -} - -fn hash_statement(stmt: &Statement, h: &mut rustc_hash::FxHasher) { - use std::hash::Hash; - - match stmt { - Statement::ExpressionStatement(es) => { - 0u8.hash(h); - hash_expression(&es.expression, h); - } - Statement::VariableDeclaration(decl) => { - 1u8.hash(h); - (decl.declarations.len() as u32).hash(h); - } - Statement::ReturnStatement(ret) => { - 2u8.hash(h); - if let Some(arg) = &ret.argument { - hash_expression(arg, h); - } - } - Statement::IfStatement(ifs) => { - 3u8.hash(h); - hash_expression(&ifs.test, h); - hash_statement(&ifs.consequent, h); - if let Some(alt) = &ifs.alternate { - hash_statement(alt, h); - } - } - Statement::WhileStatement(wh) => { - 4u8.hash(h); - hash_expression(&wh.test, h); - hash_statement(&wh.body, h); - } - Statement::ForStatement(fr) => { - 5u8.hash(h); - hash_statement(&fr.body, h); - } - Statement::BlockStatement(block) => { - 6u8.hash(h); - for s in &block.body { - hash_statement(s, h); - } - } - _ => { - std::mem::discriminant(stmt).hash(h); - } - } -} - -fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher) { - use std::hash::Hash; - - match expr { - Expression::BinaryExpression(bin) => { - 0u8.hash(h); - std::mem::discriminant(&bin.operator).hash(h); - hash_expression(&bin.left, h); - hash_expression(&bin.right, h); - } - Expression::UnaryExpression(un) => { - 1u8.hash(h); - std::mem::discriminant(&un.operator).hash(h); - hash_expression(&un.argument, h); - } - Expression::CallExpression(_) => { - 2u8.hash(h); - } - Expression::LogicalExpression(log) => { - 3u8.hash(h); - std::mem::discriminant(&log.operator).hash(h); - hash_expression(&log.left, h); - hash_expression(&log.right, h); - } - _ => { - std::mem::discriminant(expr).hash(h); - } - } -} diff --git a/crates/oxide_compiler/src/hash.rs b/crates/oxide_compiler/src/hash.rs new file mode 100644 index 00000000..04027f5d --- /dev/null +++ b/crates/oxide_compiler/src/hash.rs @@ -0,0 +1,90 @@ +use oxide_parser::{Expression, Statement}; + +pub fn structural_hash(program: &oxide_parser::Program) -> u64 { + use std::hash::Hasher; + + let mut h = rustc_hash::FxHasher::default(); + + for stmt in &program.body { + hash_statement(stmt, &mut h); + } + + h.finish() +} + +fn hash_statement(stmt: &Statement, h: &mut rustc_hash::FxHasher) { + use std::hash::Hash; + + match stmt { + Statement::ExpressionStatement(es) => { + 0u8.hash(h); + hash_expression(&es.expression, h); + } + Statement::VariableDeclaration(decl) => { + 1u8.hash(h); + (decl.declarations.len() as u32).hash(h); + } + Statement::ReturnStatement(ret) => { + 2u8.hash(h); + if let Some(arg) = &ret.argument { + hash_expression(arg, h); + } + } + Statement::IfStatement(ifs) => { + 3u8.hash(h); + hash_expression(&ifs.test, h); + hash_statement(&ifs.consequent, h); + if let Some(alt) = &ifs.alternate { + hash_statement(alt, h); + } + } + Statement::WhileStatement(wh) => { + 4u8.hash(h); + hash_expression(&wh.test, h); + hash_statement(&wh.body, h); + } + Statement::ForStatement(fr) => { + 5u8.hash(h); + hash_statement(&fr.body, h); + } + Statement::BlockStatement(block) => { + 6u8.hash(h); + for s in &block.body { + hash_statement(s, h); + } + } + _ => { + std::mem::discriminant(stmt).hash(h); + } + } +} + +fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher) { + use std::hash::Hash; + + match expr { + Expression::BinaryExpression(bin) => { + 0u8.hash(h); + std::mem::discriminant(&bin.operator).hash(h); + hash_expression(&bin.left, h); + hash_expression(&bin.right, h); + } + Expression::UnaryExpression(un) => { + 1u8.hash(h); + std::mem::discriminant(&un.operator).hash(h); + hash_expression(&un.argument, h); + } + Expression::CallExpression(_) => { + 2u8.hash(h); + } + Expression::LogicalExpression(log) => { + 3u8.hash(h); + std::mem::discriminant(&log.operator).hash(h); + hash_expression(&log.left, h); + hash_expression(&log.right, h); + } + _ => { + std::mem::discriminant(expr).hash(h); + } + } +} diff --git a/crates/oxide_compiler/src/lib.rs b/crates/oxide_compiler/src/lib.rs index fbe66017..c941aba3 100644 --- a/crates/oxide_compiler/src/lib.rs +++ b/crates/oxide_compiler/src/lib.rs @@ -1,6 +1,7 @@ #![doc = "OxideJS - AST to bytecode compiler"] pub mod compiler; +pub mod hash; pub mod module; pub mod opcode; pub mod symbol_table; diff --git a/crates/oxide_compiler/src/module.rs b/crates/oxide_compiler/src/module.rs index daecd30b..ff024a4b 100644 --- a/crates/oxide_compiler/src/module.rs +++ b/crates/oxide_compiler/src/module.rs @@ -1,8 +1,16 @@ use std::fmt; -use crate::compiler::Constant; use crate::opcode::{self, OpCode}; +#[derive(Debug, Clone, PartialEq)] +pub enum Constant { + Number(f64), + String(String), + Boolean(bool), + Null, + Undefined, +} + pub struct CompiledModule { pub bytecode: Vec, pub constants: Vec,