From cad1f8f1ecf7976153030368d2e2c58801ccf776 Mon Sep 17 00:00:00 2001 From: Shautvast Date: Fri, 21 Nov 2025 16:05:06 +0100 Subject: [PATCH] refactored from opcode bytes to enum --- src/builtins/list.rs | 13 +- src/builtins/string.rs | 3 +- src/chunk.rs | 172 ----------- .../{bytecode_pass.rs => asm_pass.rs} | 266 ++++++++++++------ src/compiler/compiler_tests.rs | 2 +- src/compiler/mod.rs | 67 ++++- src/file_watch.rs | 6 +- src/lib.rs | 76 +---- src/main.rs | 6 +- src/repl.rs | 19 +- src/value.rs | 2 +- src/vm.rs | 262 ++++++----------- 12 files changed, 359 insertions(+), 535 deletions(-) delete mode 100644 src/chunk.rs rename src/compiler/{bytecode_pass.rs => asm_pass.rs} (70%) diff --git a/src/builtins/list.rs b/src/builtins/list.rs index e73bea2..474d2c3 100644 --- a/src/builtins/list.rs +++ b/src/builtins/list.rs @@ -17,6 +17,17 @@ macro_rules! mut_list_fn { }; } +macro_rules! list_fn { + ($list:ident, $args:ident => $body:expr) => { + |self_val: Value, $args: Vec| -> Result { + match self_val { + Value::List($list) => $body, + _ => Err(expected_a_list()), + } + } + }; +} + pub(crate) fn list_functions() -> FunctionMap { let mut list_functions: FunctionMap = HashMap::new(); let functions = &mut list_functions; @@ -26,7 +37,7 @@ pub(crate) fn list_functions() -> FunctionMap { Signature::new( vec![], U64, - mut_list_fn!(mut self_val, mut _args => Ok(u64(self_val.len() as u64))), + list_fn!(self_val, _args => Ok(u64(self_val.len() as u64))), ), ); add( diff --git a/src/builtins/string.rs b/src/builtins/string.rs index 1ae4cb2..289252f 100644 --- a/src/builtins/string.rs +++ b/src/builtins/string.rs @@ -103,7 +103,7 @@ fn string_replace_all(receiver: Value, args: Vec) -> Result) -> Result, - pub constants: Vec, - lines: Vec, - pub(crate) object_defs: HashMap>, - pub(crate) function_parameters: Vec, - pub vars: Vec<(TokenType, String)>, -} - -impl Default for Chunk { - fn default() -> Self { - Chunk::new("") - } -} - -impl Chunk { - pub(crate) fn find_constant(&self, p0: &String) -> Option { - for (i, constant) in self.constants.iter().enumerate() { - if let Value::String(s) = constant - && s == p0 - { - return Some(i); - } - } - None - } -} - -impl Chunk { - pub(crate) fn new(name: &str) -> Chunk { - Chunk { - name: name.to_string(), - code: Vec::new(), - constants: vec![], - lines: vec![], - object_defs: HashMap::new(), - function_parameters: vec![], - vars: vec![], - } - } - - pub(crate) fn add(&mut self, byte: u16, line: usize) { - self.code.push(byte); - self.lines.push(line); - } - - pub(crate) fn add_constant(&mut self, value: impl Into) -> usize { - self.constants.push(value.into()); - self.constants.len() - 1 - } - - pub(crate) fn add_var(&mut self, var_type: &TokenType, name: &str) -> usize { - self.vars.push((var_type.clone(), name.to_string())); - self.vars.len() - 1 - } - - pub(crate) fn add_object_def(&mut self, name: &str, fields: &[Parameter]) { - self.object_defs.insert(name.to_string(), fields.to_vec()); - } - - pub fn disassemble(&self) { - println!("== {} ==", self.name); - let mut offset = 0; - while offset < self.code.len() { - offset = self.disassemble_inst(offset); - } - println!(); - } - - fn disassemble_inst(&self, offset: usize) -> usize { - print!("{:04} ", offset); - if offset > 0 && self.lines[offset] == self.lines[offset - 1] { - print!(" | "); - } else { - print!("{:04} ", self.lines[offset]); - } - let instruction = self.code[offset]; - match instruction { - OP_CONSTANT => self.constant_inst("LDC", offset), - OP_ADD => self.simple_inst("ADD", offset), - OP_SUBTRACT => self.simple_inst("SUB", offset), - OP_MULTIPLY => self.simple_inst("MUL", offset), - OP_DIVIDE => self.simple_inst("DIV", offset), - OP_BITAND => self.simple_inst("BITAND", offset), - OP_BITOR => self.simple_inst("BITOR", offset), - OP_BITXOR => self.simple_inst("BITXOR", offset), - OP_NEGATE => self.simple_inst("NEG", offset), - OP_NOT => self.simple_inst("NOT", offset), - OP_RETURN => self.simple_inst("RET", offset), - OP_SHL => self.simple_inst("SHL", offset), - OP_SHR => self.simple_inst("SHR", offset), - OP_LESS => self.simple_inst("LT", offset), - OP_LESS_EQUAL => self.simple_inst("LTE", offset), - OP_GREATER => self.simple_inst("GT", offset), - OP_GREATER_EQUAL => self.simple_inst("GTE", offset), - OP_EQUAL => self.simple_inst("EQ", offset), - OP_PRINT => self.simple_inst("PRT", offset), - OP_POP => self.simple_inst("POP", offset), - OP_DEFINE => self.constant_inst("DEF", offset), - OP_DEF_STRING => self.constant_inst("DEFSTR", offset), - OP_DEF_I32 => self.constant_inst("DEFI32", offset), - OP_DEF_I64 => self.constant_inst("DEFI64", offset), - OP_DEF_F32 => self.constant_inst("DEFF32", offset), - OP_DEF_F64 => self.constant_inst("DEFF64", offset), - OP_DEF_BOOL => self.constant_inst("DEFBOOL", offset), - OP_CALL => self.call_inst("CALL", offset), - OP_GET => self.assign_inst("GET", offset), - OP_DEF_LIST => self.new_inst("DEFLIST", offset), - OP_DEF_MAP => self.new_inst("DEFMAP", offset), - OP_ASSIGN => self.assign_inst("ASSIGN", offset), - OP_GOTO_IF => self.constant_inst("GOTO_IF", offset), - _ => { - println!("Unknown instruction {}", instruction); - offset + 1 - } - } - } - - fn simple_inst(&self, op: &str, offset: usize) -> usize { - println!("{}", op); - offset + 1 - } - - fn assign_inst(&self, op: &str, offset: usize) -> usize { - let constant = self.code[offset + 1]; - print!("{} {}:", op, constant); - println!("{}",self.vars.get(constant as usize).unwrap().1); - offset + 2 - } - - fn call_inst(&self, op: &str, offset: usize) -> usize { - let constant = self.code[offset + 1]; - let num_args = self.code[offset + 2]; - println!( - "{} {}:{}({}):", - op, constant, &self.constants[constant as usize], num_args - ); - offset + 3 - } - - fn new_inst(&self, op: &str, offset: usize) -> usize { - let constant = self.code[offset + 1]; - let len = self.code[offset + 2]; - print!("{} len: {}:", op, len); - self.print_value(&self.constants[constant as usize]); - offset + 3 - } - - fn constant_inst(&self, op: &str, offset: usize) -> usize { - let constant = self.code[offset + 1]; - print!("{} {}:", op, constant); - self.print_value(&self.constants[constant as usize]); - offset + 2 - } - - fn print_value(&self, value: &Value) { - println!("{}", value); - } -} diff --git a/src/compiler/bytecode_pass.rs b/src/compiler/asm_pass.rs similarity index 70% rename from src/compiler/bytecode_pass.rs rename to src/compiler/asm_pass.rs index 269bb20..74d307a 100644 --- a/src/compiler/bytecode_pass.rs +++ b/src/compiler/asm_pass.rs @@ -1,15 +1,14 @@ +use crate::builtins::lookup; +use crate::compiler::asm_pass::Op::{Add, And, Assign, BitAnd, BitOr, BitXor, Call, CallBuiltin, Constant, DefList, DefMap, Divide, Dup, Equal, Get, Goto, GotoIf, GotoIfNot, Greater, GreaterEqual, Less, LessEqual, ListGet, Multiply, Negate, Not, NotEqual, Or, Pop, Print, Return, Shr, Subtract}; use crate::compiler::ast_pass::Expression::NamedParameter; use crate::compiler::ast_pass::{Expression, Function, Parameter, Statement}; -use crate::builtins::lookup; -use crate::chunk::Chunk; +use crate::compiler::tokens::TokenType; +use crate::compiler::tokens::TokenType::Unknown; use crate::errors::CompilerError::{IncompatibleTypes, UndeclaredVariable}; use crate::errors::{CompilerError, CompilerErrorAtLine}; use crate::symbol_builder::{Symbol, calculate_type, infer_type}; -use crate::compiler::tokens::TokenType; -use crate::compiler::tokens::TokenType::Unknown; use crate::value::Value; -use crate::vm::{OP_ADD, OP_AND, OP_ASSIGN, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CALL_BUILTIN, OP_CONSTANT, OP_DEF_LIST, OP_DEF_MAP, OP_DIVIDE, OP_DUP, OP_EQUAL, OP_GET, OP_GOTO, OP_GOTO_IF, OP_GOTO_NIF, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_LIST_GET, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_OR, OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT}; -use crate::{Registry, SymbolTable}; +use crate::{AsmRegistry, SymbolTable}; use std::collections::HashMap; use std::ops::Deref; @@ -17,7 +16,7 @@ pub fn compile( qualified_name: Option<&str>, ast: &Vec, symbols: &SymbolTable, - registry: &mut Registry, + registry: &mut AsmRegistry, ) -> Result<(), CompilerErrorAtLine> { compile_in_namespace(ast, qualified_name, symbols, registry) } @@ -25,11 +24,11 @@ pub fn compile( pub fn compile_function( function: &Function, symbols: &SymbolTable, - registry: &mut Registry, + registry: &mut AsmRegistry, namespace: &str, -) -> Result { +) -> Result { let fn_name = &function.name.lexeme; - let mut compiler = Compiler::new(fn_name); + let mut compiler = AsmPass::new(fn_name); for parm in &function.parameters { let name = parm.name.lexeme.clone(); let var_index = compiler.chunk.add_var(&parm.var_type, &parm.name.lexeme); @@ -45,26 +44,81 @@ pub fn compile_in_namespace( ast: &Vec, namespace: Option<&str>, symbols: &SymbolTable, - registry: &mut Registry, + registry: &mut AsmRegistry, ) -> Result<(), CompilerErrorAtLine> { let name = namespace.unwrap_or("main"); - let mut compiler = Compiler::new(name); + let mut compiler = AsmPass::new(name); let chunk = compiler.compile(ast, symbols, registry, name)?; registry.insert(name.to_string(), chunk); Ok(()) } -pub struct Compiler { - chunk: Chunk, +#[derive(Clone)] +pub struct AsmChunk { + pub(crate) name: String, + pub code: Vec, + pub constants: Vec, + lines: Vec, + pub(crate) object_defs: HashMap>, + pub(crate) function_parameters: Vec, + pub vars: Vec<(TokenType, String)>, +} + +impl AsmChunk { + pub(crate) fn new(name: &str) -> Self { + Self { + name: name.to_string(), + code: Vec::new(), + constants: vec![], + lines: vec![], + object_defs: HashMap::new(), + function_parameters: vec![], + vars: vec![], + } + } + + pub(crate) fn add(&mut self, op: Op, line: usize) { + self.code.push(op); + self.lines.push(line); + } + + pub(crate) fn add_constant(&mut self, value: impl Into) -> usize { + self.constants.push(value.into()); + self.constants.len() - 1 + } + + pub(crate) fn find_constant(&self, p0: &String) -> Option { + for (i, constant) in self.constants.iter().enumerate() { + if let Value::String(s) = constant + && s == p0 + { + return Some(i); + } + } + None + } + + pub(crate) fn add_var(&mut self, var_type: &TokenType, name: &str) -> usize { + self.vars.push((var_type.clone(), name.to_string())); + self.vars.len() - 1 + } + + pub(crate) fn add_object_def(&mut self, name: &str, fields: &[Parameter]) { + self.object_defs.insert(name.to_string(), fields.to_vec()); + } +} + +pub struct AsmPass { + chunk: AsmChunk, _had_error: bool, current_line: usize, vars: HashMap, } -impl Compiler { +impl AsmPass { pub fn new(name: &str) -> Self { Self { - chunk: Chunk::new(name), + chunk: AsmChunk::new(name), _had_error: false, current_line: 0, vars: HashMap::new(), @@ -76,11 +130,11 @@ impl Compiler { &mut self, ast: &Vec, symbols: &SymbolTable, - registry: &mut Registry, + registry: &mut AsmRegistry, namespace: &str, - ) -> Result { + ) -> Result { self.compile_statements(ast, symbols, registry, namespace)?; - self.emit_byte(OP_RETURN); + self.emit(Return); let chunk = self.chunk.clone(); self.chunk.code.clear(); // in case the compiler is reused, clear it for the next compilation. This is for the REPL Ok(chunk) @@ -91,7 +145,7 @@ impl Compiler { &mut self, ast: &Vec, symbols: &SymbolTable, - registry: &mut Registry, + registry: &mut AsmRegistry, namespace: &str, ) -> Result<(), CompilerErrorAtLine> { for statement in ast { @@ -105,7 +159,7 @@ impl Compiler { &mut self, statement: &Statement, symbols: &SymbolTable, - registry: &mut Registry, + registry: &mut AsmRegistry, namespace: &str, ) -> Result<(), CompilerErrorAtLine> { self.current_line = statement.line(); @@ -127,7 +181,7 @@ impl Compiler { let name_index = self.chunk.add_var(var_type, name); self.vars.insert(name.to_string(), name_index); self.compile_expression(namespace, initializer, symbols, registry)?; - self.emit_bytes(OP_ASSIGN, name_index as u16); + self.emit(Assign(name_index)); } else { return Err(self.raise(UndeclaredVariable(name.to_string()))); } @@ -135,7 +189,7 @@ impl Compiler { // replace with function Statement::PrintStmt { value } => { self.compile_expression(namespace, value, symbols, registry)?; - self.emit_byte(OP_PRINT); + self.emit(Print); } Statement::ExpressionStmt { expression } => { self.compile_expression(namespace, expression, symbols, registry)?; @@ -161,30 +215,23 @@ impl Compiler { } => { self.compile_expression(namespace, condition, symbols, registry)?; - self.emit_byte(OP_DUP); - self.emit_bytes(OP_GOTO_NIF, 0); - let goto_addr1 = self.chunk.code.len()-1; - self.emit_byte(OP_POP); + self.emit(Dup); + self.emit(GotoIfNot(0)); // placeholder + let goto_addr1 = self.chunk.code.len() - 1; + self.emit(Pop); self.compile_statements(then_branch, symbols, registry, namespace)?; - self.emit_bytes(OP_GOTO, 0); - let goto_addr2 = self.chunk.code.len()-1; + self.emit(Goto(0)); + let goto_addr2 = self.chunk.code.len() - 1;// placeholder + self.chunk.code[goto_addr1] = GotoIfNot(self.chunk.code.len()); if else_branch.is_some() { - self.chunk.code[goto_addr1] = self.chunk.code.len() as u16; - self.emit_bytes(OP_GOTO_IF, 0); - let goto_addr3 = self.chunk.code.len() - 1; - self.compile_statements( else_branch.as_ref().unwrap(), symbols, registry, namespace, )?; - - self.chunk.code[goto_addr2] = self.chunk.code.len() as u16; // fill in the placeholder - self.chunk.code[goto_addr3] = self.chunk.code.len() as u16; // fill in the placeholder - } else { - self.chunk.code[goto_addr1] = self.chunk.code.len() as u16; } + self.chunk.code[goto_addr2]= Op::Goto(self.chunk.code.len()); } Statement::ForStatement { loop_var, @@ -204,19 +251,19 @@ impl Compiler { self.vars.insert(name.to_string(), loop_var_name_index); // 3. start index - self.emit_bytes(OP_CONSTANT, start_index as u16); - self.emit_bytes(OP_ASSIGN, loop_var_name_index as u16); + self.emit(Constant(start_index)); + self.emit(Assign(loop_var_name_index)); let return_addr = self.chunk.code.len(); self.compile_statements(body, symbols, registry, namespace)?; - self.emit_bytes(OP_GET, loop_var_name_index as u16); - self.emit_bytes(OP_CONSTANT, step_const_index); - self.emit_byte(OP_ADD); - self.emit_bytes(OP_ASSIGN, loop_var_name_index as u16); - self.emit_bytes(OP_CONSTANT, end_index as u16); - self.emit_bytes(OP_GET, loop_var_name_index as u16); - self.emit_byte(OP_GREATER_EQUAL); - self.emit_bytes(OP_GOTO_IF, return_addr as u16); + self.emit(Get(loop_var_name_index)); + self.emit(Constant(step_const_index)); + self.emit(Add); + self.emit(Assign(loop_var_name_index)); + self.emit(Constant(end_index)); + self.emit(Get(loop_var_name_index)); + self.emit(GreaterEqual); + self.emit(GotoIf(return_addr)); } } Ok(()) @@ -227,7 +274,7 @@ impl Compiler { namespace: &str, expression: &Expression, symbols: &SymbolTable, - registry: &mut Registry, + registry: &mut AsmRegistry, ) -> Result<(), CompilerErrorAtLine> { match expression { Expression::FunctionCall { @@ -244,16 +291,14 @@ impl Compiler { namespace, symbols, registry, arguments, parameters, )?; - self.emit_bytes(OP_CALL, name_index as u16); - self.emit_byte(arguments.len() as u16); + self.emit(Call(name_index,arguments.len())); } // constructor function Some(Symbol::Object { fields, .. }) => { self.get_arguments_in_order( namespace, symbols, registry, arguments, fields, )?; - self.emit_bytes(OP_CALL, name_index as u16); - self.emit_byte(arguments.len() as u16); + self.emit(Call(name_index,arguments.len())); } _ => { return Err(self.raise(CompilerError::FunctionNotFound(name.to_string()))); @@ -293,15 +338,16 @@ impl Compiler { arguments, &signature.parameters, )?; - self.emit_byte(OP_CALL_BUILTIN); - self.emit_byte(name_index as u16); - self.emit_byte(type_index as u16); - self.emit_byte(arguments.len() as u16); + self.emit(CallBuiltin( + name_index, + type_index, + arguments.len(), + )); } Expression::Variable { name, .. } => { let name_index = self.vars.get(name); if let Some(name_index) = name_index { - self.emit_bytes(OP_GET, *name_index as u16); + self.emit(Get(*name_index)); } else { return Err(self.raise(UndeclaredVariable(name.to_string()))); } @@ -314,7 +360,7 @@ impl Compiler { self.compile_expression(namespace, value, symbols, registry)?; let name_index = self.vars.get(variable_name); if let Some(name_index) = name_index { - self.emit_bytes(OP_ASSIGN, *name_index as u16); + self.emit(Assign(*name_index)); } else { return Err(self.raise(UndeclaredVariable(variable_name.to_string()))); } @@ -326,14 +372,14 @@ impl Compiler { for expr in values { self.compile_expression(namespace, expr, symbols, registry)?; } - self.emit_bytes(OP_DEF_LIST, values.len() as u16); + self.emit(DefList(values.len())); } Expression::Map { entries, .. } => { for (key, value) in entries { self.compile_expression(namespace, key, symbols, registry)?; self.compile_expression(namespace, value, symbols, registry)?; } - self.emit_bytes(OP_DEF_MAP, entries.len() as u16); + self.emit(DefMap(entries.len())); } Expression::Grouping { expression, .. } => { self.compile_expression(namespace, expression, symbols, registry)? @@ -344,10 +390,10 @@ impl Compiler { self.compile_expression(namespace, right, symbols, registry)?; match operator.token_type { TokenType::Minus => { - self.emit_byte(OP_NEGATE); + self.emit(Negate); } TokenType::Bang => { - self.emit_byte(OP_NOT); + self.emit(Not); } _ => unimplemented!("unary other than ! and -"), } @@ -361,31 +407,32 @@ impl Compiler { self.compile_expression(namespace, left, symbols, registry)?; self.compile_expression(namespace, right, symbols, registry)?; match operator.token_type { - TokenType::BitAnd => self.emit_byte(OP_BITAND), - TokenType::BitXor => self.emit_byte(OP_BITXOR), + TokenType::BitAnd => self.emit(BitAnd), + TokenType::BitXor => self.emit(BitXor), TokenType::Equal => { if let Expression::Variable { name, .. } = left.deref() { let index = self.vars.get(name).unwrap(); - self.emit_bytes(OP_ASSIGN, *index as u16); - self.emit_byte(OP_POP); + self.emit(Assign(*index)); + self.emit(Pop); } else { return Err(self.raise(UndeclaredVariable("".to_string()))); } } - TokenType::EqualEqual => self.emit_byte(OP_EQUAL), - TokenType::Greater => self.emit_byte(OP_GREATER), - TokenType::GreaterEqual => self.emit_byte(OP_GREATER_EQUAL), - TokenType::GreaterGreater => self.emit_byte(OP_SHR), - TokenType::Less => self.emit_byte(OP_LESS), - TokenType::LessEqual => self.emit_byte(OP_LESS_EQUAL), - TokenType::LessLess => self.emit_byte(OP_SHL), - TokenType::LogicalAnd => self.emit_byte(OP_AND), - TokenType::LogicalOr => self.emit_byte(OP_OR), - TokenType::Minus => self.emit_byte(OP_SUBTRACT), - TokenType::Pipe => self.emit_byte(OP_BITOR), - TokenType::Plus => self.emit_byte(OP_ADD), - TokenType::Slash => self.emit_byte(OP_DIVIDE), - TokenType::Star => self.emit_byte(OP_MULTIPLY), + TokenType::EqualEqual => self.emit(Equal), + TokenType::BangEqual => self.emit(NotEqual), + TokenType::Greater => self.emit(Greater), + TokenType::GreaterEqual => self.emit(GreaterEqual), + TokenType::GreaterGreater => self.emit(Shr), + TokenType::Less => self.emit(Less), + TokenType::LessEqual => self.emit(LessEqual), + TokenType::LessLess => self.emit(Op::Shl), + TokenType::LogicalAnd => self.emit(And), + TokenType::LogicalOr => self.emit(Or), + TokenType::Minus => self.emit(Subtract), + TokenType::Pipe => self.emit(BitOr), + TokenType::Plus => self.emit(Add), + TokenType::Slash => self.emit(Divide), + TokenType::Star => self.emit(Multiply), _ => unimplemented!("binary other than plus, minus, star, slash"), } } @@ -396,7 +443,7 @@ impl Compiler { Expression::ListGet { index, list } => { self.compile_expression(namespace, list, symbols, registry)?; self.compile_expression(namespace, index, symbols, registry)?; - self.emit_byte(OP_LIST_GET); + self.emit(ListGet); } Expression::MapGet { .. } => {} Expression::FieldGet { .. } => {} @@ -415,7 +462,7 @@ impl Compiler { &mut self, namespace: &str, symbols: &SymbolTable, - registry: &mut Registry, + registry: &mut AsmRegistry, arguments: &[Expression], parameters: &[Parameter], ) -> Result<(), CompilerErrorAtLine> { @@ -441,18 +488,13 @@ impl Compiler { Ok(()) } - fn emit_byte(&mut self, byte: u16) { - self.chunk.add(byte, self.current_line); + fn emit(&mut self, op: Op) { + self.chunk.add(op, self.current_line); } - fn emit_bytes(&mut self, b1: u16, b2: u16) { - self.emit_byte(b1); - self.emit_byte(b2); - } - - fn emit_constant(&mut self, value: Value) -> u16 { - let index = self.chunk.add_constant(value) as u16; - self.emit_bytes(OP_CONSTANT, index); + fn emit_constant(&mut self, value: Value) -> usize { + let index = self.chunk.add_constant(value); + self.emit(Constant(index)); index } @@ -460,3 +502,41 @@ impl Compiler { CompilerErrorAtLine::raise(error, self.current_line) } } + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Op { + Constant(usize), + Add, + Subtract, + Multiply, + Divide, + Negate, + Print, + Return, + Call(usize,usize), + And, + Or, + Not, + Equal, + Greater, + Less, + NotEqual, + GreaterEqual, + LessEqual, + BitAnd, + BitOr, + BitXor, + Shr, + Shl, + Pop, + Get(usize), + DefList(usize), + DefMap(usize), + Assign(usize), + ListGet, + CallBuiltin(usize, usize, usize), + Dup, + GotoIf(usize), + GotoIfNot(usize), + Goto(usize), +} diff --git a/src/compiler/compiler_tests.rs b/src/compiler/compiler_tests.rs index 87915d8..7865b70 100644 --- a/src/compiler/compiler_tests.rs +++ b/src/compiler/compiler_tests.rs @@ -5,8 +5,8 @@ mod tests { use crate::errors::CrudLangError::{Compiler, Runtime}; use crate::errors::RuntimeError::{IllegalArgumentException, IndexOutOfBounds}; use crate::value::{Value, string}; - use crate::{compile, run}; use chrono::DateTime; + use crate::compiler::{compile, run}; #[test] fn literal_int() { diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index 599f3d3..f8c0387 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -1,5 +1,68 @@ +use std::collections::HashMap; +use std::fs; +use walkdir::WalkDir; +use crate::{compiler, symbol_builder, AsmRegistry}; +use crate::compiler::asm_pass::AsmChunk; +use crate::errors::CrudLangError; +use crate::errors::CrudLangError::Platform; + mod compiler_tests; -pub mod bytecode_pass; pub mod scan_pass; pub mod ast_pass; -pub mod tokens; \ No newline at end of file +pub mod tokens; +pub mod asm_pass; + +pub fn compile_sourcedir(source_dir: &str) -> Result, CrudLangError> { + let mut asm_registry = AsmRegistry::new(); + + for entry in WalkDir::new(source_dir).into_iter().filter_map(|e| e.ok()) { + let path = entry.path().to_str().unwrap(); + if path.ends_with(".crud") { + print!("-- Compiling {} -- ", path); + let source = fs::read_to_string(path).map_err(map_underlying())?; + let tokens = scan_pass::scan(&source)?; + let mut symbol_table = HashMap::new(); + match ast_pass::compile(Some(path), tokens, &mut symbol_table) { + Ok(statements) => { + let path = path.strip_prefix(source_dir).unwrap().replace(".crud", ""); + + symbol_builder::build(&path, &statements, &mut symbol_table); + asm_pass::compile(Some(&path), &statements, &symbol_table, &mut asm_registry)?; + } + Err(e) => { + println!("{}", e); + break; + } + } + } + } + + Ok(asm_registry) +} + +pub fn map_underlying() -> fn(std::io::Error) -> CrudLangError { + |e| Platform(e.to_string()) +} + + +pub fn compile(src: &str) -> Result, CrudLangError> { + let tokens = compiler::scan_pass::scan(src)?; + let mut asm_registry = HashMap::new(); + let mut symbol_table = HashMap::new(); + let ast = compiler::ast_pass::compile(None, tokens, &mut symbol_table)?; + symbol_builder::build("", &ast, &mut symbol_table); + asm_pass::compile(None, &ast, &symbol_table, &mut asm_registry)?; + Ok(asm_registry) +} + +#[cfg(test)] +pub(crate) fn run(src: &str) -> Result { + let tokens = compiler::scan_pass::scan(src)?; + let mut symbol_table = HashMap::new(); + let ast = compiler::ast_pass::compile(None, tokens, &mut symbol_table)?; + symbol_builder::build("", &ast, &mut symbol_table); + let mut asm_registry = HashMap::new(); + asm_pass::compile(None, &ast, &symbol_table, &mut asm_registry)?; + let registry = arc_swap::ArcSwap::from(std::sync::Arc::new(asm_registry)); + crate::vm::interpret(registry.load(), "main").map_err(CrudLangError::from) +} diff --git a/src/file_watch.rs b/src/file_watch.rs index e2cc1f0..2c152a9 100644 --- a/src/file_watch.rs +++ b/src/file_watch.rs @@ -1,5 +1,3 @@ -use crate::chunk::Chunk; -use crate::compile_sourcedir; use notify::{RecursiveMode, Watcher}; use std::collections::HashMap; use std::path::Path; @@ -9,10 +7,12 @@ use std::thread; use std::time::{Duration, SystemTime}; use arc_swap::ArcSwap; use log::info; +use crate::compiler::asm_pass::AsmChunk; +use crate::compiler::compile_sourcedir; const ONE_SEC: Duration = Duration::from_secs(1); -pub fn start_watch_daemon(source: &str, registry: Arc>>) { +pub fn start_watch_daemon(source: &str, registry: Arc>>) { let source = source.to_string(); let s = source.to_string(); let (tx, rx) = channel(); diff --git a/src/lib.rs b/src/lib.rs index d70f095..d17d76b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,11 @@ -use crate::chunk::Chunk; +use crate::compiler::asm_pass::AsmChunk; use crate::compiler::ast_pass::{Expression, Statement}; -use crate::errors::CrudLangError::Platform; -use crate::errors::{CompilerErrorAtLine, CrudLangError}; +use crate::errors::CompilerErrorAtLine; use crate::symbol_builder::Symbol; use std::collections::HashMap; -use std::fs; -use walkdir::WalkDir; mod builtins; -pub mod chunk; -pub(crate) mod compiler; +pub mod compiler; pub mod errors; pub mod file_watch; mod keywords; @@ -21,68 +17,4 @@ pub mod vm; pub(crate) type SymbolTable = HashMap; pub(crate) type Expr = Result; pub(crate) type Stmt = Result; -pub(crate) type Registry = HashMap; - -pub fn compile_sourcedir(source_dir: &str) -> Result, CrudLangError> { - let mut registry = HashMap::new(); - - for entry in WalkDir::new(source_dir).into_iter().filter_map(|e| e.ok()) { - let path = entry.path().to_str().unwrap(); - if path.ends_with(".crud") { - print!("-- Compiling {} -- ", path); - let source = fs::read_to_string(path).map_err(map_underlying())?; - let tokens = compiler::scan_pass::scan(&source)?; - let mut symbol_table = HashMap::new(); - match compiler::ast_pass::compile(Some(path), tokens, &mut symbol_table) { - Ok(statements) => { - let path = path.strip_prefix(source_dir).unwrap().replace(".crud", ""); - - symbol_builder::build(&path, &statements, &mut symbol_table); - compiler::bytecode_pass::compile(Some(&path), &statements, &symbol_table, &mut registry)?; - } - Err(e) => { - println!("{}", e); - break; - } - } - } - } - println!(); - Ok(registry) -} - -pub fn map_underlying() -> fn(std::io::Error) -> CrudLangError { - |e| Platform(e.to_string()) -} - -pub fn recompile(src: &str, registry: &mut HashMap) -> Result<(), CrudLangError> { - let tokens = compiler::scan_pass::scan(src)?; - let mut symbol_table = HashMap::new(); - let ast = compiler::ast_pass::compile(None, tokens, &mut symbol_table)?; - symbol_builder::build("", &ast, &mut symbol_table); - compiler::bytecode_pass::compile(None, &ast, &symbol_table, registry)?; - Ok(()) -} - -pub fn compile(src: &str) -> Result, CrudLangError> { - let tokens = compiler::scan_pass::scan(src)?; - let mut registry = HashMap::new(); - let mut symbol_table = HashMap::new(); - let ast = compiler::ast_pass::compile(None, tokens, &mut symbol_table)?; - symbol_builder::build("", &ast, &mut symbol_table); - compiler::bytecode_pass::compile(None, &ast, &symbol_table, &mut registry)?; - Ok(registry) -} - -#[cfg(test)] -pub(crate) fn run(src: &str) -> Result { - let tokens = compiler::scan_pass::scan(src)?; - let mut symbol_table = HashMap::new(); - let ast = compiler::ast_pass::compile(None, tokens, &mut symbol_table)?; - symbol_builder::build("", &ast, &mut symbol_table); - let mut registry = HashMap::new(); - compiler::bytecode_pass::compile(None, &ast, &symbol_table, &mut registry)?; - - let registry = arc_swap::ArcSwap::from(std::sync::Arc::new(registry)); - vm::interpret(registry.load(), "main").map_err(CrudLangError::from) -} +pub(crate) type AsmRegistry = HashMap; diff --git a/src/main.rs b/src/main.rs index 428f3e1..5f68d19 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,14 +3,14 @@ use axum::http::StatusCode; use axum::routing::any; use axum::{Json, Router}; use clap::Parser; -use tipi_lang::chunk::Chunk; use tipi_lang::errors::CrudLangError; use tipi_lang::vm::interpret_async; -use tipi_lang::{compile_sourcedir, map_underlying}; use std::collections::HashMap; use std::sync::Arc; use arc_swap::ArcSwap; use log::info; +use tipi_lang::compiler::asm_pass::AsmChunk; +use tipi_lang::compiler::{compile_sourcedir, map_underlying}; /// A simple CLI tool to greet users #[derive(Parser, Debug)] @@ -72,7 +72,7 @@ async fn main() -> Result<(), CrudLangError> { #[derive(Clone)] struct AppState { - registry: Arc>>, + registry: Arc>>, } async fn handle_any( diff --git a/src/repl.rs b/src/repl.rs index 755571f..f897c73 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -1,8 +1,9 @@ -use crate::chunk::Chunk; -use crate::errors::CrudLangError; +use crate::compiler::asm_pass::AsmChunk; use crate::compiler::scan_pass::scan; +use crate::compiler::{asm_pass, ast_pass, map_underlying}; +use crate::errors::CrudLangError; +use crate::symbol_builder; use crate::vm::Vm; -use crate::{compiler::ast_pass, compiler::bytecode_pass, map_underlying, symbol_builder}; use arc_swap::ArcSwap; use std::collections::HashMap; use std::io; @@ -10,12 +11,12 @@ use std::io::Write; use std::ops::Deref; use std::sync::Arc; -pub fn start(registry: Arc>>) -> Result<(), CrudLangError> { +pub fn start(registry: Arc>>) -> Result<(), CrudLangError> { println!("REPL started -- Type ctrl-c to exit (both the repl and the server)"); println!(":h for help"); let mut symbol_table = HashMap::new(); let mut vm = Vm::new(®istry.load()); - let mut bytecode_compiler = bytecode_pass::Compiler::new("main"); + let mut asm_pass = asm_pass::AsmPass::new("main"); loop { print!(">"); io::stdout().flush().map_err(map_underlying())?; @@ -34,7 +35,7 @@ pub fn start(registry: Arc>>) -> Result<(), CrudL let tokens = scan(input)?; - let ast = match ast_pass::compile(None, tokens, &mut symbol_table){ + let ast = match ast_pass::compile(None, tokens, &mut symbol_table) { Ok(ast) => ast, Err(e) => { println!("{}", e); @@ -43,7 +44,7 @@ pub fn start(registry: Arc>>) -> Result<(), CrudL }; symbol_builder::build("", &ast, &mut symbol_table); - match bytecode_compiler.compile(&ast, &symbol_table, &mut registry_copy, "") { + match asm_pass.compile(&ast, &symbol_table, &mut registry_copy, "") { Ok(chunk) => { registry_copy.insert("main".to_string(), chunk); registry.store(Arc::new(registry_copy)); @@ -67,7 +68,7 @@ pub fn start(registry: Arc>>) -> Result<(), CrudL } } -fn list_endpoints(registry: Arc>) { +fn list_endpoints(registry: Arc>) { registry .iter() .filter(|(k, _)| k.contains("get")) @@ -76,7 +77,7 @@ fn list_endpoints(registry: Arc>) { }); } -fn list_functions(registry: Arc>) { +fn list_functions(registry: Arc>) { registry.iter().for_each(|(k, _)| { println!("{}", k); //number }); diff --git a/src/value.rs b/src/value.rs index 7b35143..463f9e4 100644 --- a/src/value.rs +++ b/src/value.rs @@ -36,7 +36,7 @@ pub(crate) fn string(v: impl Into) -> Value { Value::String(v.into()) } -pub(crate) fn i64(v: impl Into) -> Value { +pub(crate) fn _i64(v: impl Into) -> Value { Value::I64(v.into()) } diff --git a/src/vm.rs b/src/vm.rs index 5ca334d..5ffe4b2 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,35 +1,15 @@ -use crate::Registry; -use crate::chunk::Chunk; -use crate::errors::RuntimeError::Something; +use crate::compiler::asm_pass::{AsmChunk, Op}; use crate::errors::{RuntimeError, ValueError}; -use crate::compiler::tokens::TokenType; use crate::value::{Object, Value}; +use crate::{AsmRegistry}; use arc_swap::Guard; use std::collections::HashMap; use std::sync::Arc; use tracing::debug; - -pub struct Vm { - ip: usize, - stack: Vec, - local_vars: HashMap, - error_occurred: bool, - pub(crate) registry: Arc>, -} - -pub fn interpret( - registry: Guard>>, - function: &str, -) -> Result { - let chunk = registry.get(function).unwrap().clone(); - // chunk.disassemble(); - let mut vm = Vm::new(®istry); - vm.run(&get_context(function), &chunk) - // Ok(Value::Void) -} +use crate::compiler::tokens::TokenType; pub async fn interpret_async( - registry: Guard>>, + registry: Guard>>, function: &str, uri: &str, query_params: HashMap, @@ -50,20 +30,27 @@ pub async fn interpret_async( } } -fn value_map(strings: HashMap) -> HashMap { - strings - .into_iter() - .map(|(k, v)| (Value::String(k.to_string()), Value::String(v.to_string()))) - .collect() +pub fn interpret(registry: Guard>, function: &str) -> Result { + let chunk = registry.get(function).unwrap().clone(); + let mut vm = Vm::new(®istry); + vm.run(&get_context(function), &chunk) } -pub fn interpret_function(chunk: &Chunk, args: Vec) -> Result { +pub fn interpret_function(chunk: &AsmChunk, args: Vec) -> Result { let mut vm = Vm::new(&Arc::new(HashMap::new())); vm.run_function(chunk, args) } +pub(crate) struct Vm { + ip: usize, + stack: Vec, + local_vars: HashMap, + error_occurred: bool, + pub(crate) registry: Arc, +} + impl Vm { - pub(crate) fn new(registry: &Arc) -> Self { + pub(crate) fn new(registry: &Arc) -> Self { Self { ip: 0, stack: vec![], @@ -73,7 +60,7 @@ impl Vm { } } - fn run_function(&mut self, chunk: &Chunk, mut args: Vec) -> Result { + fn run_function(&mut self, chunk: &AsmChunk, mut args: Vec) -> Result { // arguments -> locals for (_, name) in chunk.vars.iter() { self.local_vars.insert(name.clone(), args.remove(0)); @@ -81,117 +68,101 @@ impl Vm { self.run("", chunk) } - pub(crate) fn run(&mut self, context: &str, chunk: &Chunk) -> Result { + pub(crate) fn run(&mut self, context: &str, chunk: &AsmChunk) -> Result { self.ip = 0; loop { - if self.error_occurred { - return Err(Something); - } - debug!("{:?}", self.stack); - let opcode = chunk.code[self.ip]; + let opcode = &chunk.code[self.ip]; self.ip += 1; match opcode { - OP_CONSTANT => { - let value = &chunk.constants[self.read(chunk)]; + Op::Constant(c) => { + let value = &chunk.constants[*c]; self.push(value.clone()); } - OP_ADD => binary_op(self, |a, b| a + b), - OP_SUBTRACT => binary_op(self, |a, b| a - b), - OP_MULTIPLY => binary_op(self, |a, b| a * b), - OP_DIVIDE => binary_op(self, |a, b| a / b), - OP_AND => binary_op(self, |a, b| { + Op::Add => binary_op(self, |a, b| a + b), + Op::Subtract => binary_op(self, |a, b| a - b), + Op::Multiply => binary_op(self, |a, b| a * b), + Op::Divide => binary_op(self, |a, b| a / b), + Op::And => binary_op(self, |a, b| { if let (Value::Bool(a), Value::Bool(b)) = (a, b) { Ok(Value::Bool(*a && *b)) } else { Err(ValueError::Some("Cannot and")) } }), - OP_OR => binary_op(self, |a, b| { + Op::Or => binary_op(self, |a, b| { if let (Value::Bool(a), Value::Bool(b)) = (a, b) { Ok(Value::Bool(*a || *b)) } else { Err(ValueError::Some("Cannot compare")) } }), - OP_NOT => unary_op(self, |a| !a), - OP_BITAND => binary_op(self, |a, b| a & b), - OP_BITOR => binary_op(self, |a, b| a | b), - OP_BITXOR => binary_op(self, |a, b| a ^ b), - OP_NEGATE => unary_op(self, |a| -a), - OP_RETURN => { - debug!("return {:?}", self.stack); + Op::Not => unary_op(self, |a| !a), + Op::BitAnd => binary_op(self, |a, b| a & b), + Op::BitOr => binary_op(self, |a, b| a | b), + Op::BitXor => binary_op(self, |a, b| a ^ b), + Op::Negate => unary_op(self, |a| -a), + Op::Return => { return if self.stack.is_empty() { Ok(Value::Void) } else { Ok(self.pop()) }; } - OP_SHL => binary_op(self, |a, b| a << b), - OP_SHR => binary_op(self, |a, b| a >> b), - OP_EQUAL => binary_op(self, |a, b| Ok(Value::Bool(a == b))), - OP_GREATER => binary_op(self, |a, b| Ok(Value::Bool(a > b))), - OP_GREATER_EQUAL => binary_op(self, |a, b| Ok(Value::Bool(a >= b))), - OP_LESS => binary_op(self, |a, b| Ok(Value::Bool(a < b))), - OP_LESS_EQUAL => binary_op(self, |a, b| Ok(Value::Bool(a <= b))), - OP_PRINT => { + Op::Shl => binary_op(self, |a, b| a << b), + Op::Shr => binary_op(self, |a, b| a >> b), + Op::Equal => binary_op(self, |a, b| Ok(Value::Bool(a == b))), + Op::Greater => binary_op(self, |a, b| Ok(Value::Bool(a > b))), + Op::GreaterEqual => binary_op(self, |a, b| Ok(Value::Bool(a >= b))), + Op::Less => binary_op(self, |a, b| Ok(Value::Bool(a < b))), + Op::LessEqual => binary_op(self, |a, b| Ok(Value::Bool(a <= b))), + Op::NotEqual => binary_op(self, |a, b| Ok(Value::Bool(a != b))), + Op::Print => { debug!("print {:?}", self.stack); let v = self.pop(); println!("{}", v); } - OP_DEFINE => { - let name = self.read_name(chunk); - let value = self.pop(); - self.local_vars.insert(name, value); - } - OP_DEF_LIST => { - let len = self.read(chunk); + Op::DefList(len) => { let mut list = vec![]; - for _ in 0..len { + for _ in 0..*len { let value = self.pop(); list.push(value); } list.reverse(); self.push(Value::List(list)); } - OP_ASSIGN => { - let index = self.read(chunk); - let (var_type, name) = chunk.vars.get(index).unwrap(); + Op::Assign(var_index) =>{ + let (var_type, name) = chunk.vars.get(*var_index).unwrap(); let value = self.pop(); - let value = Self::number(var_type, value)?; + let value = number(var_type, value)?; self.local_vars.insert(name.to_string(), value); //insert or update } - OP_DEF_MAP => { - let len = self.read(chunk); + Op::DefMap(len) => { let mut map = HashMap::new(); - for _ in 0..len { + for _ in 0..*len { let value = self.pop(); let key = self.pop(); map.insert(key, value); } self.push(Value::Map(map)); } - OP_GET => { - let var_index = self.read(chunk); - let (_, name_index) = chunk.vars.get(var_index).unwrap(); + Op::Get(var_index) => { + let (_, name_index) = chunk.vars.get(*var_index).unwrap(); let value = self.local_vars.get(name_index).unwrap().clone(); self.push(value); } - OP_LIST_GET => { + Op::ListGet => { let index = self.pop(); let list = self.pop(); if let Value::List(list) = list { self.push(list.get(index.cast_usize()?).cloned().unwrap()) } } - OP_CALL_BUILTIN => { - let function_name_index = self.read(chunk); - let function_name = chunk.constants[function_name_index].to_string(); - let function_type_index = self.read(chunk); - let receiver_type_name = chunk.constants[function_type_index].to_string(); + Op::CallBuiltin(function_name_index, function_type_index, num_args) => { + let function_name = chunk.constants[*function_name_index].to_string(); + let receiver_type_name = chunk.constants[*function_type_index].to_string(); - let num_args = self.read(chunk); let mut args = vec![]; - for _ in 0..num_args { + for _ in 0..*num_args { let arg = self.pop(); args.push(arg); } @@ -201,21 +172,16 @@ impl Vm { crate::builtins::call(&receiver_type_name, &function_name, receiver, args)?; self.push(return_value); } - OP_POP => { - self.pop(); // discards the value - } - OP_CALL => { - let function_name_index = self.read(chunk); - let num_args = self.read(chunk); - + Op::Pop => {self.pop();} + Op::Call(function_name_index, num_args) => { let mut args = vec![]; - for _ in 0..num_args { + for _ in 0..*num_args { let arg = self.pop(); args.push(arg); } args.reverse(); - let function_name = chunk.constants[function_name_index].to_string(); + let function_name = chunk.constants[*function_name_index].to_string(); let function_chunk = self .registry .get(&function_name) @@ -250,55 +216,30 @@ impl Vm { self.push(result); } } - OP_GOTO_NIF => { + Op::GotoIfNot(goto_addr) => { let b = self.pop(); - let goto_addr = self.read(chunk); if b == Value::Bool(false) { - self.ip = goto_addr; + self.ip = *goto_addr; } } - OP_GOTO_IF => { + Op::GotoIf(goto_addr) => { let b = self.pop(); - let goto_addr = self.read(chunk); if b == Value::Bool(true) { - self.ip = goto_addr; + self.ip = *goto_addr; } } - OP_GOTO => { - let goto_addr = self.read(chunk); - self.ip = goto_addr; + Op::Goto(goto_addr) => { + self.ip = *goto_addr; } - OP_DUP =>{ + Op::Dup =>{ let value = self.pop(); self.push(value.clone()); self.push(value); } - _ => {} } } } - fn number(var_type: &TokenType, value: Value) -> Result { - let value = match var_type { - TokenType::U32 => value.cast_u32()?, - TokenType::U64 => value.cast_u64()?, - TokenType::F32 => value.cast_f32()?, - TokenType::I32 => value.cast_i32()?, - _ => value, - }; - Ok(value) - } - - fn read(&mut self, chunk: &Chunk) -> usize { - self.ip += 1; - chunk.code[self.ip - 1] as usize - } - - fn read_name(&mut self, chunk: &Chunk) -> String { - let index = self.read(chunk); - chunk.constants[index].to_string() //string?? - } - fn push(&mut self, value: Value) { self.stack.push(value); } @@ -341,51 +282,20 @@ pub(crate) fn get_context(path: &str) -> String { parts.join("/") } -pub const OP_CONSTANT: u16 = 1; -pub const OP_ADD: u16 = 2; -pub const OP_SUBTRACT: u16 = 3; -pub const OP_MULTIPLY: u16 = 4; -pub const OP_DIVIDE: u16 = 5; -pub const OP_NEGATE: u16 = 6; -pub const OP_PRINT: u16 = 7; -pub const OP_RETURN: u16 = 8; -pub const OP_CALL: u16 = 9; -pub const OP_DEF_FN: u16 = 10; -pub const OP_AND: u16 = 11; -pub const OP_OR: u16 = 12; -pub const OP_NOT: u16 = 13; -pub const OP_EQUAL: u16 = 14; -pub const OP_GREATER: u16 = 15; -pub const OP_LESS: u16 = 16; -pub const OP_NOT_EQUAL: u16 = 17; -pub const OP_GREATER_EQUAL: u16 = 18; -pub const OP_LESS_EQUAL: u16 = 19; -pub const OP_BITAND: u16 = 20; -pub const OP_BITOR: u16 = 21; -pub const OP_BITXOR: u16 = 22; -pub const OP_SHR: u16 = 23; -pub const OP_SHL: u16 = 24; -pub const OP_POP: u16 = 25; -pub const OP_DEFINE: u16 = 26; // may be obsolete already -pub const OP_GET: u16 = 27; -pub const OP_DEF_I32: u16 = 28; -pub const OP_DEF_I64: u16 = 29; -pub const OP_DEF_U32: u16 = 30; -pub const OP_DEF_U64: u16 = 31; -pub const OP_DEF_DATE: u16 = 32; -pub const OP_DEF_STRING: u16 = 33; -pub const OP_DEF_CHAR: u16 = 34; -pub const OP_DEF_BOOL: u16 = 35; -pub const OP_DEF_LIST: u16 = 36; -pub const OP_DEF_MAP: u16 = 37; -pub const OP_DEF_STRUCT: u16 = 38; -pub const OP_DEF_F32: u16 = 39; -pub const OP_DEF_F64: u16 = 40; -pub const OP_ASSIGN: u16 = 41; -pub const OP_LIST_GET: u16 = 42; -pub const OP_CALL_BUILTIN: u16 = 43; -pub const OP_DUP: u16 = 44; -// pub const OP_IF_ELSE: u16 = 45; -pub const OP_GOTO_IF: u16 = 46; -pub const OP_GOTO_NIF: u16 = 48; -pub const OP_GOTO: u16 = 47; +fn number(var_type: &TokenType, value: Value) -> Result { + let value = match var_type { + TokenType::U32 => value.cast_u32()?, + TokenType::U64 => value.cast_u64()?, + TokenType::F32 => value.cast_f32()?, + TokenType::I32 => value.cast_i32()?, + _ => value, + }; + Ok(value) +} + +fn value_map(strings: HashMap) -> HashMap { + strings + .into_iter() + .map(|(k, v)| (Value::String(k.to_string()), Value::String(v.to_string()))) + .collect() +} \ No newline at end of file