fix reassignment bugs

This commit is contained in:
Shautvast 2025-11-14 17:37:22 +01:00
parent 44f063fb6b
commit 0bce2ae9eb
12 changed files with 226 additions and 63 deletions

View file

@ -68,7 +68,6 @@ impl AstCompiler {
&mut self, &mut self,
symbol_table: &mut SymbolTable, symbol_table: &mut SymbolTable,
) -> Result<Vec<Statement>, CompilerErrorAtLine> { ) -> Result<Vec<Statement>, CompilerErrorAtLine> {
self.current_line();
if !self.had_error { if !self.had_error {
let mut statements = vec![]; let mut statements = vec![];
while !self.is_at_end() { while !self.is_at_end() {
@ -365,10 +364,19 @@ impl AstCompiler {
} }
fn bit_xor(&mut self, symbol_table: &mut SymbolTable) -> Expr { fn bit_xor(&mut self, symbol_table: &mut SymbolTable) -> Expr {
let expr = self.equality(symbol_table)?; let expr = self.assignment(symbol_table)?;
self.binary(&[TokenType::BitXor], expr, symbol_table) self.binary(&[TokenType::BitXor], expr, symbol_table)
} }
fn assignment(&mut self, symbol_table: &mut SymbolTable) -> Expr {
let expr = self.equality(symbol_table)?;
self.binary(
&[TokenType::Equal],
expr,
symbol_table,
)
}
fn equality(&mut self, symbol_table: &mut SymbolTable) -> Expr { fn equality(&mut self, symbol_table: &mut SymbolTable) -> Expr {
let expr = self.comparison(symbol_table)?; let expr = self.comparison(symbol_table)?;
self.binary( self.binary(

65
src/builtins/list.rs Normal file
View file

@ -0,0 +1,65 @@
use crate::ast_compiler::Parameter;
use crate::builtins::{FunctionMap, Signature, add, expected};
use crate::errors::RuntimeError;
use crate::tokens::TokenType;
use crate::tokens::TokenType::U64;
use crate::value::{Value, u64};
use std::collections::HashMap;
macro_rules! mut_list_fn {
(mut $list:ident, mut $args:ident => $body:expr) => {
|self_val: Value, mut $args: Vec<Value>| -> Result<Value, RuntimeError> {
match self_val {
Value::List(mut $list) => $body,
_ => Err(expected_a_list()),
}
}
};
}
pub(crate) fn list_functions() -> FunctionMap {
let mut list_functions: FunctionMap = HashMap::new();
let functions = &mut list_functions;
add(
functions,
"len",
Signature::new(
vec![],
U64,
mut_list_fn!(mut self_val, mut _args => Ok(u64(self_val.len() as u64))),
),
);
add(
functions,
"push",
Signature::new(
vec![Parameter::new("element", TokenType::Any)],
U64,
mut_list_fn!(mut list, mut args => {
list.push(args.remove(0));
Ok(Value::List(list))
}),
),
);
add(
functions,
"remove",
Signature::new(
vec![Parameter::new("index", U64)],
U64,
mut_list_fn!(mut list, mut args => {
let index = args.remove(0).cast_usize().unwrap();
if index >= list.len() {
return Err(RuntimeError::IndexOutOfBounds(index, list.len()))
}
list.remove(index);
Ok(Value::List(list))
}),
),
);
list_functions
}
fn expected_a_list() -> RuntimeError {
expected("list")
}

View file

@ -1,24 +1,26 @@
mod string; mod string;
mod list;
use crate::builtins::string::string_methods; use crate::builtins::string::string_functions;
use crate::errors::{CompilerError, RuntimeError}; use crate::errors::{CompilerError, RuntimeError};
use crate::tokens::TokenType; use crate::tokens::TokenType;
use crate::value::Value; use crate::value::Value;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::LazyLock; use std::sync::LazyLock;
use crate::ast_compiler::Parameter; use crate::ast_compiler::Parameter;
use crate::builtins::list::list_functions;
pub(crate) struct Signature { pub(crate) struct Signature {
pub(crate) parameters: Vec<Parameter>, pub(crate) parameters: Vec<Parameter>,
pub(crate) return_type: TokenType, pub(crate) return_type: TokenType,
pub(crate) function: MethodFn, pub(crate) function: FunctionFn,
} }
impl Signature { impl Signature {
pub(crate) fn new( pub(crate) fn new(
parameters: Vec<Parameter>, parameters: Vec<Parameter>,
return_type: TokenType, return_type: TokenType,
function: MethodFn, function: FunctionFn,
) -> Self { ) -> Self {
Self { Self {
parameters, parameters,
@ -32,17 +34,19 @@ impl Signature {
} }
} }
pub(crate) type MethodFn = fn(Value, Vec<Value>) -> Result<Value, RuntimeError>; pub(crate) type FunctionFn = fn(Value, Vec<Value>) -> Result<Value, RuntimeError>;
pub(crate) type MethodMap = HashMap<String, Signature>; pub(crate) type FunctionMap = HashMap<String, Signature>;
pub(crate) type MethodTable = HashMap<String, MethodMap>; pub(crate) type FunctionTable = HashMap<String, FunctionMap>;
static METHODS: LazyLock<FunctionTable> = LazyLock::new(|| {
let mut table: FunctionTable = HashMap::new();
table.insert("string".to_string(), string_functions());
table.insert("list".to_string(), list_functions());
static METHODS: LazyLock<MethodTable> = LazyLock::new(|| {
let mut table: MethodTable = HashMap::new();
table.insert("string".to_string(), string_methods());
table table
}); });
pub(crate) fn add(m: &mut MethodMap, name: &str, method: Signature) { pub(crate) fn add(m: &mut FunctionMap, name: &str, method: Signature) {
m.insert(name.to_string(), method); m.insert(name.to_string(), method);
} }

View file

@ -1,35 +1,35 @@
use crate::builtins::{MethodMap, Parameter, Signature, add, expected}; use crate::builtins::{FunctionMap, Parameter, Signature, add, expected};
use crate::errors::RuntimeError; use crate::errors::RuntimeError;
use crate::tokens::TokenType::{StringType, U64}; use crate::tokens::TokenType::{StringType, U64};
use crate::value::{Value, bool, i64, string}; use crate::value::{Value, bool, i64, string, u64};
use regex::Regex; use regex::Regex;
use std::collections::HashMap; use std::collections::HashMap;
pub(crate) fn string_methods() -> MethodMap { pub(crate) fn string_functions() -> FunctionMap {
let mut string_methods: MethodMap = HashMap::new(); let mut string_functions: FunctionMap = HashMap::new();
let m = &mut string_methods; let functions = &mut string_functions;
add(m, "len", Signature::new(vec![], U64, string_len)); add(functions, "len", Signature::new(vec![], U64, string_len));
add( add(
m, functions,
"to_uppercase", "to_uppercase",
Signature::new(vec![], StringType, string_to_uppercase), Signature::new(vec![], StringType, string_to_uppercase),
); );
add( add(
m, functions,
"to_lowercase", "to_lowercase",
Signature::new(vec![], StringType, string_to_lowercase), Signature::new(vec![], StringType, string_to_lowercase),
); );
add(m, "contains", Signature::new(vec![], StringType, string_contains)); add(functions, "contains", Signature::new(vec![Parameter::new("key", StringType)], StringType, string_contains));
add(m, "reverse", Signature::new(vec![], StringType, string_reverse)); add(functions, "reverse", Signature::new(vec![], StringType, string_reverse));
add(m, "trim", Signature::new(vec![], StringType, string_trim)); add(functions, "trim", Signature::new(vec![], StringType, string_trim));
add( add(
m, functions,
"trim_start", "trim_start",
Signature::new(vec![], StringType, string_trim_start), Signature::new(vec![], StringType, string_trim_start),
); );
add(m, "trim_end", Signature::new(vec![], StringType, string_trim_end)); add(functions, "trim_end", Signature::new(vec![], StringType, string_trim_end));
add( add(
m, functions,
"replace_all", "replace_all",
Signature::new( Signature::new(
vec![ vec![
@ -40,12 +40,12 @@ pub(crate) fn string_methods() -> MethodMap {
string_replace_all, string_replace_all,
), ),
); );
string_methods string_functions
} }
fn string_len(self_val: Value, _args: Vec<Value>) -> Result<Value, RuntimeError> { fn string_len(self_val: Value, _args: Vec<Value>) -> Result<Value, RuntimeError> {
match self_val { match self_val {
Value::String(s) => Ok(i64(s.len() as i64)), Value::String(s) => Ok(u64(s.len() as u64)),
_ => Err(expected_a_string()), _ => Err(expected_a_string()),
} }
} }
@ -98,7 +98,6 @@ fn string_trim_end(self_val: Value, _: Vec<Value>) -> Result<Value, RuntimeError
_ => Err(expected_a_string()), _ => Err(expected_a_string()),
} }
} }
//TODO check arity in compiler (generically)
fn string_replace_all(receiver: Value, args: Vec<Value>) -> Result<Value, RuntimeError> { fn string_replace_all(receiver: Value, args: Vec<Value>) -> Result<Value, RuntimeError> {
let pattern = if let Value::String(s) = &args[0] { let pattern = if let Value::String(s) = &args[0] {
Regex::new(s).map_err(|_| RuntimeError::IllegalArgumentException("Invalid regex".into()))? Regex::new(s).map_err(|_| RuntimeError::IllegalArgumentException("Invalid regex".into()))?

View file

@ -3,6 +3,7 @@ use crate::ast_compiler::{Expression, Function, Parameter, Statement};
use crate::builtins::lookup; use crate::builtins::lookup;
use crate::chunk::Chunk; use crate::chunk::Chunk;
use crate::errors::CompilerError::{IncompatibleTypes, UndeclaredVariable}; use crate::errors::CompilerError::{IncompatibleTypes, UndeclaredVariable};
use crate::errors::RuntimeError::IllegalArgumentsException;
use crate::errors::{CompilerError, CompilerErrorAtLine}; use crate::errors::{CompilerError, CompilerErrorAtLine};
use crate::symbol_builder::{Symbol, calculate_type, infer_type}; use crate::symbol_builder::{Symbol, calculate_type, infer_type};
use crate::tokens::TokenType; use crate::tokens::TokenType;
@ -12,11 +13,12 @@ use crate::vm::{
OP_ADD, OP_AND, OP_ASSIGN, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CALL_BUILTIN, 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_EQUAL, OP_GET, OP_GREATER, OP_CONSTANT, OP_DEF_LIST, OP_DEF_MAP, OP_DIVIDE, OP_EQUAL, OP_GET, OP_GREATER,
OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_LIST_GET, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_OR, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_LIST_GET, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_OR,
OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT,
}; };
use crate::{Registry, SymbolTable}; use crate::{Registry, SymbolTable};
use clap::arg;
use std::collections::HashMap; use std::collections::HashMap;
use std::mem; use std::ops::Deref;
pub fn compile( pub fn compile(
qualified_name: Option<&str>, qualified_name: Option<&str>,
@ -216,7 +218,13 @@ impl Compiler {
.add_constant(Value::String(method_name.to_string())) .add_constant(Value::String(method_name.to_string()))
}); });
let signature = lookup(&receiver_type, method_name).map_err(|e| self.raise(e))?; let signature = lookup(&receiver_type, method_name).map_err(|e| self.raise(e))?;
if signature.parameters.len() != arguments.len() {
return Err(self.raise(CompilerError::IllegalArgumentsException(
format!("{}.{}", receiver_type, method_name),
signature.parameters.len(),
arguments.len(),
)));
}
self.get_arguments_in_order( self.get_arguments_in_order(
namespace, namespace,
symbols, symbols,
@ -279,22 +287,31 @@ impl Compiler {
self.compile_expression(namespace, left, symbols, registry)?; self.compile_expression(namespace, left, symbols, registry)?;
self.compile_expression(namespace, right, symbols, registry)?; self.compile_expression(namespace, right, symbols, registry)?;
match operator.token_type { match operator.token_type {
TokenType::Plus => self.emit_byte(OP_ADD),
TokenType::Minus => self.emit_byte(OP_SUBTRACT),
TokenType::Star => self.emit_byte(OP_MULTIPLY),
TokenType::Slash => self.emit_byte(OP_DIVIDE),
TokenType::BitAnd => self.emit_byte(OP_BITAND), TokenType::BitAnd => self.emit_byte(OP_BITAND),
TokenType::Pipe => self.emit_byte(OP_BITOR),
TokenType::BitXor => self.emit_byte(OP_BITXOR), TokenType::BitXor => self.emit_byte(OP_BITXOR),
TokenType::GreaterGreater => self.emit_byte(OP_SHR), TokenType::Equal => {
TokenType::LessLess => self.emit_byte(OP_SHL), 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);
} else {
return Err(self.raise(UndeclaredVariable("".to_string())));
}
}
TokenType::EqualEqual => self.emit_byte(OP_EQUAL), TokenType::EqualEqual => self.emit_byte(OP_EQUAL),
TokenType::Greater => self.emit_byte(OP_GREATER), TokenType::Greater => self.emit_byte(OP_GREATER),
TokenType::GreaterEqual => self.emit_byte(OP_GREATER_EQUAL), TokenType::GreaterEqual => self.emit_byte(OP_GREATER_EQUAL),
TokenType::GreaterGreater => self.emit_byte(OP_SHR),
TokenType::Less => self.emit_byte(OP_LESS), TokenType::Less => self.emit_byte(OP_LESS),
TokenType::LessEqual => self.emit_byte(OP_LESS_EQUAL), TokenType::LessEqual => self.emit_byte(OP_LESS_EQUAL),
TokenType::LessLess => self.emit_byte(OP_SHL),
TokenType::LogicalAnd => self.emit_byte(OP_AND), TokenType::LogicalAnd => self.emit_byte(OP_AND),
TokenType::LogicalOr => self.emit_byte(OP_OR), 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),
_ => unimplemented!("binary other than plus, minus, star, slash"), _ => unimplemented!("binary other than plus, minus, star, slash"),
} }
} }

View file

@ -1,8 +1,12 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::errors::CompilerError::IllegalArgumentsException;
use crate::errors::CompilerErrorAtLine;
use crate::errors::CrudLangError::{Compiler, Runtime};
use crate::value::{Value, string}; use crate::value::{Value, string};
use crate::{compile, run}; use crate::{compile, run};
use chrono::DateTime; use chrono::DateTime;
use crate::errors::RuntimeError::{IllegalArgumentException, IndexOutOfBounds};
#[test] #[test]
fn literal_int() { fn literal_int() {
@ -165,14 +169,8 @@ p"#);
assert!(result.is_ok()); assert!(result.is_ok());
let result = result.unwrap(); let result = result.unwrap();
if let Value::Map(map) = result { if let Value::Map(map) = result {
assert_eq!( assert_eq!(map.get(&string("name")).unwrap(), &string("Dent"));
map.get(&string("name")).unwrap(), assert_eq!(map.get(&string("age")).unwrap(), &Value::I64(40));
&string("Dent")
);
assert_eq!(
map.get(&string("age")).unwrap(),
&Value::I64(40)
);
} }
} }
@ -183,10 +181,7 @@ m"#);
let result = result.unwrap(); let result = result.unwrap();
if let Value::Map(map) = result { if let Value::Map(map) = result {
assert_eq!( assert_eq!(map.get(&string("name")).unwrap(), &string("Dent"));
map.get(&string("name")).unwrap(),
&string("Dent")
);
} }
} }
@ -267,7 +262,7 @@ date"#),
#[test] #[test]
fn string_len() { fn string_len() {
assert_eq!(run(r#""abc".len()"#), Ok(Value::I64(3))); assert_eq!(run(r#""abc".len()"#), Ok(Value::U64(3)));
} }
#[test] #[test]
@ -275,6 +270,56 @@ date"#),
assert_eq!(run(r#""Hello".replace_all("l","p")"#), Ok(string("Heppo"))); assert_eq!(run(r#""Hello".replace_all("l","p")"#), Ok(string("Heppo")));
} }
#[test]
fn string_replace_wrong_nr_of_args() {
assert_eq!(
run(r#""Hello".replace_all("l")"#),
Err(Compiler(CompilerErrorAtLine {
error: IllegalArgumentsException("string.replace_all".to_string(), 2, 1),
line: 1
}))
);
}
#[test]
fn string_replace_wrong_type_of_args() {
assert_eq!(
run(r#""Hello".replace_all("l", 1)"#),
Err(Runtime(IllegalArgumentException("Illegal replacement. Expected a string but got 1".to_string())))
);
}
#[test]
fn string_contains() {
assert_eq!(run(r#""Hello".contains("l")"#), Ok(Value::Bool(true)));
}
#[test]
fn list_length(){
assert_eq!(run(r#"[1,2,3].len()"#), Ok(Value::U64(3)));
}
#[test]
fn list_push(){
assert_eq!(run(r#"[1,2].push(3)"#), Ok(Value::List(vec![Value::I64(1), Value::I64(2), Value::I64(3)])));
}
#[test]
fn list_remove(){
assert_eq!(run(r#"[1,2,3].remove(0)"#), Ok(Value::List(vec![Value::I64(2), Value::I64(3)])));
}
#[test]
fn list_remove_out_of_bounds(){
assert_eq!(run(r#"[1,2,3].remove(4)"#), Err(Runtime(IndexOutOfBounds(4, 3))));
}
#[test]
fn reassign(){
assert_eq!(run(r#"let a=1
a=2"#), Ok(Value::Void));
}
// #[test] // #[test]
// fn package() { // fn package() {
// assert_eq!(run(r#"a.b.c()"#), Ok(Value::U32(48))); // assert_eq!(run(r#"a.b.c()"#), Ok(Value::U32(48)));

View file

@ -69,6 +69,8 @@ pub enum CompilerError {
IllegalIndexArgument(TokenType), IllegalIndexArgument(TokenType),
#[error("Illegal argument: '{0}' cannot be indexed")] #[error("Illegal argument: '{0}' cannot be indexed")]
IllegalTypeToIndex(String), IllegalTypeToIndex(String),
#[error("The number of of arguments for {0} is not correct. Should be {1}, got {2}")]
IllegalArgumentsException(String,usize,usize),
} }
#[derive(Error, Debug, PartialEq)] #[derive(Error, Debug, PartialEq)]
@ -87,6 +89,8 @@ pub enum RuntimeError {
IllegalArgumentException(String), IllegalArgumentException(String),
#[error("Expected {0}")] #[error("Expected {0}")]
ExpectedType(String), ExpectedType(String),
#[error("Index out of bounds: {0} > {1}")]
IndexOutOfBounds(usize, usize),
} }
#[derive(Error, Debug, PartialEq)] #[derive(Error, Debug, PartialEq)]

View file

@ -57,7 +57,7 @@ async fn main() -> Result<(), CrudLangError> {
); );
if args.repl { if args.repl {
std::thread::spawn(move || tipi_lang::repl::start(swap.clone()).unwrap()); let _ = std::thread::spawn(move || tipi_lang::repl::start(swap.clone()));
} }
axum::serve(listener, app).await.map_err(map_underlying())?; axum::serve(listener, app).await.map_err(map_underlying())?;

View file

@ -34,7 +34,13 @@ pub fn start(registry: Arc<ArcSwap<HashMap<String, Chunk>>>) -> Result<(), CrudL
let tokens = scan(input)?; let tokens = scan(input)?;
let ast = ast_compiler::compile(None, tokens, &mut symbol_table)?; let ast = match ast_compiler::compile(None, tokens, &mut symbol_table){
Ok(ast) => ast,
Err(e) => {
println!("{}", e);
continue;
}
};
symbol_builder::build("", &ast, &mut symbol_table); symbol_builder::build("", &ast, &mut symbol_table);
match bytecode_compiler.compile(&ast, &symbol_table, &mut registry_copy, "") { match bytecode_compiler.compile(&ast, &symbol_table, &mut registry_copy, "") {

View file

@ -19,6 +19,7 @@ impl Token {
#[derive(Debug, PartialEq, Clone, Hash)] #[derive(Debug, PartialEq, Clone, Hash)]
pub enum TokenType { pub enum TokenType {
Any,
Bang, Bang,
BangEqual, BangEqual,
BitAnd, BitAnd,
@ -93,6 +94,7 @@ pub enum TokenType {
impl fmt::Display for TokenType { impl fmt::Display for TokenType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
TokenType::Any => write!(f, "any"),
TokenType::StringType => write!(f, "string"), TokenType::StringType => write!(f, "string"),
TokenType::DateTime => write!(f, "datetime"), TokenType::DateTime => write!(f, "datetime"),
TokenType::Char => write!(f, "char"), TokenType::Char => write!(f, "char"),

View file

@ -40,6 +40,10 @@ pub(crate) fn i64(v: impl Into<i64>) -> Value {
Value::I64(v.into()) Value::I64(v.into())
} }
pub(crate) fn u64(v: impl Into<u64>) -> Value {
Value::U64(v.into())
}
pub(crate) fn bool(v: impl Into<bool>) -> Value { pub(crate) fn bool(v: impl Into<bool>) -> Value {
Value::Bool(v.into()) Value::Bool(v.into())
} }
@ -419,6 +423,7 @@ impl PartialEq for Value {
equal equal
} }
// TODO objects // TODO objects
(Value::Void, Value::Void) => true,
_ => false, //? _ => false, //?
} }
} }

View file

@ -156,13 +156,7 @@ impl Vm {
let index = self.read(chunk); let index = self.read(chunk);
let (var_type, name) = chunk.vars.get(index).unwrap(); let (var_type, name) = chunk.vars.get(index).unwrap();
let value = self.pop(); let value = self.pop();
let value = match var_type { let value = Self::number(var_type, value)?;
TokenType::U32 => value.cast_u32()?,
TokenType::U64 => value.cast_u64()?,
TokenType::F32 => value.cast_f32()?,
TokenType::I32 => value.cast_i32()?,
_ => value,
};
self.local_vars.insert(name.to_string(), value); self.local_vars.insert(name.to_string(), value);
} }
OP_DEF_MAP => { OP_DEF_MAP => {
@ -178,8 +172,8 @@ impl Vm {
OP_GET => { OP_GET => {
let var_index = self.read(chunk); let var_index = self.read(chunk);
let (_, name_index) = chunk.vars.get(var_index).unwrap(); let (_, name_index) = chunk.vars.get(var_index).unwrap();
let value = self.local_vars.get(name_index).unwrap(); let value = self.local_vars.remove(name_index).unwrap();
self.push(value.clone()); // not happy , take ownership, no clone self.push(value);
} }
OP_LIST_GET => { OP_LIST_GET => {
let index = self.pop(); let index = self.pop();
@ -205,6 +199,9 @@ impl Vm {
let return_value = crate::builtins::call(&receiver_type_name, &function_name, receiver, args)?; let return_value = crate::builtins::call(&receiver_type_name, &function_name, receiver, args)?;
self.push(return_value); self.push(return_value);
} }
OP_POP =>{
self.pop(); // discards the value
}
OP_CALL => { OP_CALL => {
let function_name_index = self.read(chunk); let function_name_index = self.read(chunk);
let num_args = self.read(chunk); let num_args = self.read(chunk);
@ -259,6 +256,17 @@ impl Vm {
} }
} }
fn number(var_type: &TokenType, value: Value) -> Result<Value, RuntimeError> {
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 { fn read(&mut self, chunk: &Chunk) -> usize {
self.ip += 1; self.ip += 1;
chunk.code[self.ip - 1] as usize chunk.code[self.ip - 1] as usize