diff --git a/src/enviroment.rs b/src/enviroment.rs index 7c88a05..0d84cb7 100644 --- a/src/enviroment.rs +++ b/src/enviroment.rs @@ -44,6 +44,10 @@ fn get_type_str(mem: &VMMemory) -> String { } } fn arg_expect(args: &Vec, pos: usize, expected_type: &str, machine: &Machine, op: &DecompiledOperation) { + if args.len() <= pos { + let err_str = format!("#{} expected {}, got nil", pos + 1, expected_type); + error(err_str, machine, op); + } let err_str = format!("#{} expected {}, got {}", pos + 1, expected_type, get_type_str(&args[pos])); if args.len() <= pos { error(err_str.clone(), machine, op); @@ -97,6 +101,64 @@ fn get_mem_tbl_val(tbl: &VMMemoryTable, key: VMMemory) -> Option<&VMMemory> { } None } +fn convert_type(mem: &VMMemory, target_type: &str) -> VMMemory { + match (mem, target_type) { + (VMMemory::String(s), "string") => { + VMMemory::String(VMMemoryString { value: s.value.clone(), variable_id: 0 }) + }, + (VMMemory::String(s), "number") => { + match s.value.parse::() { + Ok(num) => VMMemory::Number(VMMemoryNumber { value: num, variable_id: 0 }), + Err(_) => VMMemory::Null(VMMemoryNull { variable_id: 0 }), + } + }, + (VMMemory::String(s), "boolean") => { + if s.value.to_lowercase() == "true" { + VMMemory::Boolean(VMMemoryBoolean { value: true, variable_id: 0 }) + } else if s.value.to_lowercase() == "false" { + VMMemory::Boolean(VMMemoryBoolean { value: false, variable_id: 0 }) + } else { + VMMemory::Null(VMMemoryNull { variable_id: 0 }) + } + }, + (VMMemory::Number(n), "string") => { + VMMemory::String(VMMemoryString { value: n.value.to_string(), variable_id: 0 }) + }, + (VMMemory::Number(n), "number") => { + VMMemory::Number(VMMemoryNumber { value: n.value, variable_id: 0 }) + }, + (VMMemory::Number(n), "boolean") => { + if n.value != 0.0 { + VMMemory::Boolean(VMMemoryBoolean { value: true, variable_id: 0 }) + } else { + VMMemory::Boolean(VMMemoryBoolean { value: false, variable_id: 0 }) + } + }, + (VMMemory::Boolean(b), "string") => { + VMMemory::String(VMMemoryString { value: b.value.to_string(), variable_id: 0 }) + }, + (VMMemory::Boolean(b), "number") => { + if b.value { + VMMemory::Number(VMMemoryNumber { value: 1.0, variable_id: 0 }) + } else { + VMMemory::Number(VMMemoryNumber { value: 0.0, variable_id: 0 }) + } + }, + (VMMemory::Boolean(b), "boolean") => { + VMMemory::Boolean(VMMemoryBoolean { value: b.value, variable_id: 0 }) + }, + (VMMemory::Null(_), "string") => { + VMMemory::String(VMMemoryString { value: String::from("null"), variable_id: 0 }) + }, + (VMMemory::Null(_), "number") => { + VMMemory::Number(VMMemoryNumber { value: 0.0, variable_id: 0 }) + }, + (VMMemory::Null(_), "boolean") => { + VMMemory::Boolean(VMMemoryBoolean { value: false, variable_id: 0 }) + }, + _ => VMMemory::Null(VMMemoryNull { variable_id: 0 }) + } +} fn ugass(_machine: &mut Machine, _op: &DecompiledOperation, args: Vec) -> VMMemory { let mut out = String::new(); @@ -133,6 +195,15 @@ fn tarh(_machine: &mut Machine, _op: &DecompiledOperation, args: Vec) } return VMMemory::String(VMMemoryString { value: get_type_str(&args[0]), variable_id: 0 }); } +fn bimbabemb(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 1, "string", machine, op); + let val = args[0].clone(); + let target = match &args[1] { + VMMemory::String(s) => s.value.clone(), + _ => String::new() + }; + return convert_type(&val, &target); +} fn nerd_abs(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "number", machine, op); @@ -144,6 +215,126 @@ fn nerd_abs(machine: &mut Machine, op: &DecompiledOperation, args: Vec } return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } +fn nerd_kerek(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "number", machine, op); + arg_expect(&args, 1, "string", machine, op); + let num = match &args[0] { + VMMemory::Number(n) => n.value, + _ => { + error(String::from("Expected a number"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + let mode = match &args[1] { + VMMemory::String(s) => s.value.clone(), + _ => { + error(String::from("Expected a string"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + let rounded = match mode.as_str() { + "up" => num.ceil(), + "down" => num.floor(), + "nearest" => num.round(), + _ => { + error(format!("Unknown rounding mode: {}", mode), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + return VMMemory::Number(VMMemoryNumber { value: rounded, variable_id: 0 }); +} +fn nerd_sin(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "number", machine, op); + let num = match &args[0] { + VMMemory::Number(n) => n.value, + _ => { + error(String::from("Expected a number"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + let result = num.sin(); + return VMMemory::Number(VMMemoryNumber { value: result, variable_id: 0 }); +} +fn nerd_cos(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "number", machine, op); + let num = match &args[0] { + VMMemory::Number(n) => n.value, + _ => { + error(String::from("Expected a number"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + let result = num.cos(); + return VMMemory::Number(VMMemoryNumber { value: result, variable_id: 0 }); +} +fn nerd_tan(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "number", machine, op); + let num = match &args[0] { + VMMemory::Number(n) => n.value, + _ => { + error(String::from("Expected a number"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + let result = num.tan(); + return VMMemory::Number(VMMemoryNumber { value: result, variable_id: 0 }); +} +fn nerd_sqrt(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "number", machine, op); + let num = match &args[0] { + VMMemory::Number(n) => n.value, + _ => { + error(String::from("Expected a number"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + let result = num.sqrt(); + return VMMemory::Number(VMMemoryNumber { value: result, variable_id: 0 }); +} +fn nerd_legnagyobb(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "number", machine, op); + let mut nums = Vec::new(); + for arg in 0..args.len() { + match &args[arg] { + VMMemory::Number(n) => nums.push(n.value), + _ => { + error(format!("#{} expected number, got {}", arg, get_type_str(&args[arg])), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + } + } + let mut result: f64 = 0.0; + let mut first = true; + for num in nums { + if first || num > result { + result = num; + } + first = false; + } + return VMMemory::Number(VMMemoryNumber { value: result, variable_id: 0 }); +} +fn nerd_legkisebb(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "number", machine, op); + let mut nums = Vec::new(); + for arg in 0..args.len() { + match &args[arg] { + VMMemory::Number(n) => nums.push(n.value), + _ => { + error(format!("#{} expected number, got {}", arg, get_type_str(&args[arg])), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + } + } + let mut result: f64 = 0.0; + let mut first = true; + for num in nums { + if first || num < result { + result = num; + } + first = false; + } + return VMMemory::Number(VMMemoryNumber { value: result, variable_id: 0 }); +} fn kabel_olvass(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "table", machine, op); @@ -556,11 +747,40 @@ pub fn generate() -> HashMap { mem.insert(String::from("bimba"), VMMemory::NativeFunction(VMMemoryNativeFunction { func: bimba, variable_id: 0 })); mem.insert(String::from("csömör"), VMMemory::NativeFunction(VMMemoryNativeFunction { func: csomor, variable_id: 0 })); mem.insert(String::from("tarh"), VMMemory::NativeFunction(VMMemoryNativeFunction { func: tarh, variable_id: 0 })); + mem.insert(String::from("bimbabemb"), VMMemory::NativeFunction(VMMemoryNativeFunction { func: bimbabemb, variable_id: 0 })); let nerd: Vec = vec![ TableValue { key: VMMemory::String(VMMemoryString { value: String::from("abs"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: nerd_abs, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("kerek"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: nerd_kerek, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("sin"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: nerd_sin, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("cos"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: nerd_cos, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("tan"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: nerd_tan, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("sqrt"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: nerd_sqrt, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("legnagyobb"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: nerd_legnagyobb, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("legkisebb"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: nerd_legkisebb, variable_id: 0 }), } ]; mem.insert(String::from("nerd"), VMMemory::Table(VMMemoryTable { values: nerd, variable_id: 0 }));