use std::{collections::HashMap, io::{BufReader, Read, Write}, net::{self, TcpListener, TcpStream}, process, thread::sleep, time::Duration}; use crate::{errors::{create_error, print_error, ErrorSubType, ErrorType}, virtualmachine::{DecompiledOperation, Machine, TableValue, VMMemory, VMMemoryBoolean, VMMemoryNativeFunction, VMMemoryNull, VMMemoryNumber, VMMemoryString, VMMemoryTable}}; fn get_string_from_vmmem(mem: &VMMemory) -> String { let mut out = String::new(); match mem { VMMemory::String(s) => out.push_str(&s.value), VMMemory::Number(n) => out.push_str(&n.value.to_string()), VMMemory::Boolean(b) => out.push_str(if b.value { "true" } else { "false" }), VMMemory::Null(_) => out.push_str("null"), VMMemory::Table(tbl) => { out.push_str("{"); for val in &tbl.values { out.push_str(&get_string_from_vmmem(&val.key.clone())); out.push_str("="); out.push_str(&get_string_from_vmmem(&val.value.clone())); out.push_str(", "); } out.pop(); out.pop(); out.push_str("}"); }, VMMemory::Function(func) => { out.push_str("|function: "); out.push_str(&func.id.to_string()); out.push_str("|"); }, VMMemory::NativeFunction(_) => { out.push_str("|native function|"); }, } return out; } fn get_type_str(mem: &VMMemory) -> String { match mem { VMMemory::String(_) => "string".to_string(), VMMemory::Number(_) => "number".to_string(), VMMemory::Boolean(_) => "boolean".to_string(), VMMemory::Null(_) => "null".to_string(), VMMemory::Table(_) => "table".to_string(), VMMemory::Function(_) => "function".to_string(), VMMemory::NativeFunction(_) => "native_function".to_string(), } } fn arg_expect(args: &Vec, pos: usize, expected_type: &str, machine: &Machine, op: &DecompiledOperation) { 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); } let actual_type = get_type_str(&args[pos]); if actual_type != expected_type { error(err_str, machine, op); } } fn error(msg: String, machine: &Machine, op: &DecompiledOperation) { let err = create_error(&msg, op.pos, ErrorType::MachineError, ErrorSubType::RuntimeError); let curr = machine.call_stack.len()-1; let func = machine.call_stack[curr].func; print_error(&err, &machine.ctx[func]); process::exit(1); } fn set_mem_tbl_val(tbl: &mut VMMemoryTable, key: VMMemory, value: VMMemory) { for i in 0..tbl.values.len() { let found = match (&tbl.values[i].key, &key) { (VMMemory::Number(num1), VMMemory::Number(num2)) => num1.value == num2.value, (VMMemory::String(str1), VMMemory::String(str2)) => str1.value == str2.value, (VMMemory::Boolean(bool1), VMMemory::Boolean(bool2)) => bool1.value == bool2.value, (VMMemory::Null(_), VMMemory::Null(_)) => true, (VMMemory::Function(_), VMMemory::Function(_)) => false, (VMMemory::Table(_), VMMemory::Table(_)) => false, (VMMemory::NativeFunction(_), VMMemory::NativeFunction(_)) => false, _ => false, }; if found { tbl.values[i].value = value; return; } } tbl.values.push(TableValue { key, value }); } fn get_mem_tbl_val(tbl: &VMMemoryTable, key: VMMemory) -> Option<&VMMemory> { for i in 0..tbl.values.len() { let found = match (&tbl.values[i].key, &key) { (VMMemory::Number(num1), VMMemory::Number(num2)) => num1.value == num2.value, (VMMemory::String(str1), VMMemory::String(str2)) => str1.value == str2.value, (VMMemory::Boolean(bool1), VMMemory::Boolean(bool2)) => bool1.value == bool2.value, (VMMemory::Null(_), VMMemory::Null(_)) => true, (VMMemory::Function(_), VMMemory::Function(_)) => false, (VMMemory::Table(_), VMMemory::Table(_)) => false, (VMMemory::NativeFunction(_), VMMemory::NativeFunction(_)) => false, _ => false, }; if found { return Some(&tbl.values[i].value); } } None } fn ugass(_machine: &mut Machine, _op: &DecompiledOperation, args: Vec) -> VMMemory { let mut out = String::new(); for arg in args { out.push_str(&get_string_from_vmmem(&arg)); out.push_str(" "); } println!("{}", out.trim_end()); return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } fn bimba(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "number", machine, op); match &args[0] { VMMemory::Number(n) => { sleep(Duration::from_millis(n.value as u64)); }, _ => {} } return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } fn csomor(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "string", machine, op); match &args[0] { VMMemory::String(s) => { error(s.value.clone(), machine, op); }, _ => {} } return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } fn tarh(_machine: &mut Machine, _op: &DecompiledOperation, args: Vec) -> VMMemory { if args.len() < 1 { return VMMemory::String(VMMemoryString { value: String::from("null"), variable_id: 0 }); } return VMMemory::String(VMMemoryString { value: get_type_str(&args[0]), variable_id: 0 }); } fn nerd_abs(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "number", machine, op); match &args[0] { VMMemory::Number(n) => { return VMMemory::Number(VMMemoryNumber { value: n.value.abs(), variable_id: 0 }); }, _ => {} } return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } fn kabel_olvass(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "table", machine, op); arg_expect(&args, 1, "number", machine, op); let id = match &args[0] { VMMemory::Table(tbl) => { get_mem_tbl_val(tbl, VMMemory::String(VMMemoryString { value: String::from("id"), variable_id: 0 })) }, _ => None }; if id.is_none() { error(String::from("Stream not found"), machine, op); } let real_id = match &id.unwrap() { VMMemory::Number(n) => n.value as usize, _ => { error(String::from("Stream is not a number"), machine, op); 0 } }; let stored_stream = machine.storage.get(real_id); if stored_stream.is_none() { error(String::from("Stream not found in storage"), machine, op); } let boxed_stream = stored_stream.unwrap(); let stream = boxed_stream.downcast_ref::(); if stream.is_none() { error(String::from("Stream is not a TcpStream"), machine, op); } let stream = stream.unwrap(); let mut reader = BufReader::new(stream); let len = match &args[1] { VMMemory::Number(n) => n.value as usize, _ => 1024 }; let mut buf: Vec = vec![0; len]; match reader.read(&mut buf) { Ok(_) => {}, Err(e) => { error(format!("Failed to read from stream: {}", e), machine, op); return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } } let str = match String::from_utf8(buf) { Ok(s) => s, Err(_) => { error(String::from("Stream data is not valid UTF-8"), machine, op); String::new() } }; return VMMemory::String(VMMemoryString { value: str, variable_id: 0 }); } fn kabel_irj(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "table", machine, op); arg_expect(&args, 1, "string", machine, op); let id = match &args[0] { VMMemory::Table(tbl) => { get_mem_tbl_val(tbl, VMMemory::String(VMMemoryString { value: String::from("id"), variable_id: 0 })) }, _ => None }; if id.is_none() { error(String::from("Stream not found"), machine, op); } let real_id = match &id.unwrap() { VMMemory::Number(n) => n.value as usize, _ => { error(String::from("Stream is not a number"), machine, op); 0 } }; let stored_stream = machine.storage.get(real_id); if stored_stream.is_none() { error(String::from("Stream not found in storage"), machine, op); } let boxed_stream = stored_stream.unwrap(); let stream = boxed_stream.downcast_ref::(); if stream.is_none() { error(String::from("Stream is not a TcpStream"), machine, op); } let mut listener = stream.unwrap(); let write = match &args[1] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; match listener.write_all(write.as_bytes()) { Ok(_) => {}, Err(e) => { error(format!("Failed to write to stream: {}", e), machine, op); return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } } return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } fn kabel_zar(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "table", machine, op); let id = match &args[0] { VMMemory::Table(tbl) => { get_mem_tbl_val(tbl, VMMemory::String(VMMemoryString { value: String::from("id"), variable_id: 0 })) }, _ => None }; if id.is_none() { error(String::from("Stream not found"), machine, op); } let real_id = match &id.unwrap() { VMMemory::Number(n) => n.value as usize, _ => { error(String::from("Stream is not a number"), machine, op); 0 } }; let stored_stream = machine.storage.get(real_id); if stored_stream.is_none() { error(String::from("Stream not found in storage"), machine, op); } let boxed_stream = stored_stream.unwrap(); let stream = boxed_stream.downcast_ref::(); if stream.is_none() { error(String::from("Stream is not a TcpStream"), machine, op); } let listener = stream.unwrap(); match listener.shutdown(net::Shutdown::Both) { Ok(_) => {}, Err(e) => { error(format!("Failed to close stream: {}", e), machine, op); return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } }; return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } fn kabel_keres(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "table", machine, op); let id = match &args[0] { VMMemory::Table(tbl) => { get_mem_tbl_val(tbl, VMMemory::String(VMMemoryString { value: String::from("id"), variable_id: 0 })) }, _ => None }; if id.is_none() { error(String::from("Halgató not found"), machine, op); } let real_id = match &id.unwrap() { VMMemory::Number(n) => n.value as usize, _ => { error(String::from("Halgató is not a number"), machine, op); 0 } }; let stored_listener = machine.storage.get(real_id); if stored_listener.is_none() { error(String::from("Halgató not found in storage"), machine, op); } let boxed_listener = stored_listener.unwrap(); let listener = boxed_listener.downcast_ref::(); if listener.is_none() { error(String::from("Halgató is not a TcpListener"), machine, op); } let listener = listener.unwrap(); for stream in listener.incoming() { let stream = stream.unwrap(); machine.storage.push(Box::new(stream)); let ret_table: Vec = vec![ TableValue { key: VMMemory::String(VMMemoryString { value: String::from("olvass"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: kabel_olvass, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("írj"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: kabel_irj, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("zár"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: kabel_zar, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("id"), variable_id: 0 }), value: VMMemory::Number(VMMemoryNumber { value: (machine.storage.len()-1) as i64, variable_id: 0 }), } ]; return VMMemory::Table(VMMemoryTable { values: ret_table, variable_id: 0 }); } return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } fn kabel_halgass(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "string", machine, op); arg_expect(&args, 1, "number", machine, op); let host = match &args[0] { VMMemory::String(s) => s.value.clone(), _ => String::from("0.0.0.0") }; let port = match &args[1] { VMMemory::Number(n) => n.value as u16, _ => 1010 }; let listener = net::TcpListener::bind(host + ":" + &port.to_string()).unwrap(); machine.storage.push(Box::new(listener)); let ret_table: Vec = vec![ TableValue { key: VMMemory::String(VMMemoryString { value: String::from("kérés"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: kabel_keres, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("id"), variable_id: 0 }), value: VMMemory::Number(VMMemoryNumber { value: (machine.storage.len()-1) as i64, variable_id: 0 }), } ]; return VMMemory::Table(VMMemoryTable { values: ret_table, variable_id: 0 }); } fn szaft_csemerdfel(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "string", machine, op); let str = match &args[0] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; return VMMemory::String(VMMemoryString { value: str.to_uppercase(), variable_id: 0 }); } fn szaft_csemerdle(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "string", machine, op); let str = match &args[0] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; return VMMemory::String(VMMemoryString { value: str.to_lowercase(), variable_id: 0 }); } fn szaft_hossz(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "string", machine, op); let str = match &args[0] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; return VMMemory::Number(VMMemoryNumber { value: str.len() as i64, variable_id: 0 }); } fn szaft_ismeteld(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "string", machine, op); arg_expect(&args, 1, "number", machine, op); let str = match &args[0] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; let times = match &args[1] { VMMemory::Number(n) => n.value as usize, _ => 1 }; return VMMemory::String(VMMemoryString { value: str.repeat(times), variable_id: 0 }); } fn szaft_unoreverse(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "string", machine, op); let str = match &args[0] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; return VMMemory::String(VMMemoryString { value: str.chars().rev().collect(), variable_id: 0 }); } fn szaft_darabos(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "string", machine, op); arg_expect(&args, 1, "number", machine, op); arg_expect(&args, 2, "number", machine, op); let str = match &args[0] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; let num1 = match &args[1] { VMMemory::Number(n) => n.value as usize, _ => 0 }; let num2 = match &args[2] { VMMemory::Number(n) => n.value as usize, _ => 0 }; return VMMemory::String(VMMemoryString { value: str[num1..num2].to_string(), variable_id: 0 }); } fn szaft_keres(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "string", machine, op); arg_expect(&args, 1, "string", machine, op); let str = match &args[0] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; let str2 = match &args[1] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; return VMMemory::Boolean(VMMemoryBoolean { value: str.contains(&str2), variable_id: 0 }); } fn szaft_atrak(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "string", machine, op); arg_expect(&args, 1, "string", machine, op); arg_expect(&args, 2, "string", machine, op); let str = match &args[0] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; let str2 = match &args[1] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; let str3 = match &args[2] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; return VMMemory::String(VMMemoryString { value: str.replace(&str2, &str3), variable_id: 0 }); } fn szaft_szamma(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "string", machine, op); arg_expect(&args, 1, "number", machine, op); let str = match &args[0] { VMMemory::String(s) => s.value.clone(), _ => String::new() }; let num = match &args[1] { VMMemory::Number(n) => n.value as usize, _ => 0 }; return VMMemory::Number(VMMemoryNumber { value: str.as_bytes()[num] as i64, variable_id: 0 }); } fn szaft_betuve(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 as usize, _ => 0 }; let str = match String::from_utf8(vec![num.try_into().unwrap()]) { Ok(s) => s, Err(_) => { error(String::from("Invalid UTF-8 sequence"), machine, op); return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } }; return VMMemory::String(VMMemoryString { value: str, variable_id: 0 }) } pub fn generate() -> HashMap { let mut mem: HashMap = HashMap::new(); mem.insert(String::from("ugass"), VMMemory::NativeFunction(VMMemoryNativeFunction { func: ugass, variable_id: 0 })); 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 })); 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 }), } ]; mem.insert(String::from("nerd"), VMMemory::Table(VMMemoryTable { values: nerd, variable_id: 0 })); let kabel: Vec = vec![ TableValue { key: VMMemory::String(VMMemoryString { value: String::from("halgass"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: kabel_halgass, variable_id: 0 }), } ]; mem.insert(String::from("kábel"), VMMemory::Table(VMMemoryTable { values: kabel, variable_id: 0 })); let szaft: Vec = vec![ TableValue { key: VMMemory::String(VMMemoryString { value: String::from("csemerd fel"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: szaft_csemerdfel, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("csemerd le"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: szaft_csemerdle, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("hossz"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: szaft_hossz, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("ismételd"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: szaft_ismeteld, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("uno reverse"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: szaft_unoreverse, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("darabos"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: szaft_darabos, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("keres"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: szaft_keres, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("átrak"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: szaft_atrak, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("számmá"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: szaft_szamma, variable_id: 0 }), }, TableValue { key: VMMemory::String(VMMemoryString { value: String::from("betűvé"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: szaft_betuve, variable_id: 0 }), } ]; mem.insert(String::from("szaft"), VMMemory::Table(VMMemoryTable { values: szaft, variable_id: 0 })); return mem; }