diff --git a/src/enviroment.rs b/src/enviroment.rs index 03911f6..618f9fa 100644 --- a/src/enviroment.rs +++ b/src/enviroment.rs @@ -1,6 +1,6 @@ -use std::{collections::HashMap, process, thread::sleep, time::Duration}; +use std::{collections::HashMap, io::{BufRead, BufReader, Read, Write}, net::{self, TcpListener, TcpStream}, process, thread::sleep, time::Duration}; -use crate::{errors::{create_error, print_error, ErrorSubType, ErrorType}, virtualmachine::{DecompiledOperation, Machine, VMMemory, VMMemoryNativeFunction, VMMemoryNull, VMMemoryString}}; +use crate::{errors::{create_error, print_error, ErrorSubType, ErrorType}, virtualmachine::{DecompiledOperation, Machine, TableValue, VMMemory, VMMemoryNativeFunction, VMMemoryNull, VMMemoryNumber, VMMemoryString, VMMemoryTable}}; fn get_string_from_vmmem(mem: &VMMemory) -> String { let mut out = String::new(); @@ -43,12 +43,14 @@ fn get_type_str(mem: &VMMemory) -> String { VMMemory::NativeFunction(_) => "native_function".to_string(), } } -fn expect(mem: &VMMemory, expected_type: &str) -> bool { - let actual_type = get_type_str(&mem); - if actual_type == expected_type { - return true; - } else { - return false; +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) { @@ -58,6 +60,43 @@ fn error(msg: String, machine: &Machine, op: &DecompiledOperation) { 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(); @@ -68,11 +107,8 @@ fn ugass(_machine: &mut Machine, _op: &DecompiledOperation, args: Vec) println!("{}", out.trim_end()); return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } - fn bimba(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { - if args.len() < 1 || !expect(&args[0], "number") { - error(format!("#1 number expected got {}", get_type_str(&args[0])), machine, op); - } + arg_expect(&args, 0, "number", machine, op); match &args[0] { VMMemory::Number(n) => { sleep(Duration::from_millis(n.value as u64)); @@ -81,11 +117,8 @@ fn bimba(machine: &mut Machine, op: &DecompiledOperation, args: Vec) - } return VMMemory::Null(VMMemoryNull { variable_id: 0 }); } - fn csomor(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { - if args.len() < 1 || !expect(&args[0], "string") { - error(format!("#1 string expected got {}", get_type_str(&args[0])), machine, op); - } + arg_expect(&args, 0, "string", machine, op); match &args[0] { VMMemory::String(s) => { error(s.value.clone(), machine, op); @@ -94,7 +127,6 @@ fn csomor(machine: &mut Machine, op: &DecompiledOperation, args: Vec) } 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 }); @@ -102,6 +134,185 @@ fn tarh(_machine: &mut Machine, _op: &DecompiledOperation, args: Vec) 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_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("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 }); +} + pub fn generate() -> HashMap { let mut mem: HashMap = HashMap::new(); @@ -110,5 +321,21 @@ pub fn generate() -> HashMap { 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 })); + return mem; } \ No newline at end of file diff --git a/src/parser.rs b/src/parser.rs index 3a09491..a745c60 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -835,6 +835,18 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par let var = ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: token.pos }); let cal = read_call(var, pos, input, ctx); return check_continue(pos, input, cal, op_ends, parse_ends, ctx) + } else if next_token.typ == TokenType::SEPARATOR && next_token.value == "." { + let var_pos = token.pos; + *pos += 1; + let keyy = &input[*pos]; + if keyy.typ != TokenType::IDENTIFIER { + let err = create_error(&format!("Expected identifier after `.`"), keyy.pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); + } + *pos += 1; + let gt = ASTPart::TableGet(AstTableGet { table: Box::new(ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: var_pos })), key: Box::new(ASTPart::String(AstString { value: keyy.value.clone(), pos: keyy.pos })), pos: var_pos+1 }); + return check_continue(pos, input, gt, op_ends, parse_ends, ctx); } else if next_token.typ == TokenType::SEPARATOR && next_token.value == "[" { *pos += 1; let key_ends: Vec = vec![ diff --git a/src/virtualmachine.rs b/src/virtualmachine.rs index eaa9da2..0ccb502 100644 --- a/src/virtualmachine.rs +++ b/src/virtualmachine.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, process, vec}; +use std::{any::Any, collections::HashMap, process, vec}; use crate::{enviroment, errors::{create_error, print_error, ErrorSubType, ErrorType}, Context}; const ASXVERSION: [u8; 3] = [0,1,0]; @@ -98,6 +98,7 @@ pub struct Machine { pub call_stack: Vec, pub env: HashMap, pub ctx: Vec, + pub storage: Vec>, } fn read_be_num(input: &[u8]) -> usize { @@ -520,6 +521,7 @@ impl Machine { }], env: enviroment::generate(), ctx: ctx, + storage: Vec::new(), }; } diff --git a/test.asl b/test.asl index cc237d2..7623d20 100644 --- a/test.asl +++ b/test.asl @@ -1,7 +1,8 @@ -gethelj a = { - [szaft"test"szaft] = szaft"test"szaft, - [szaft"teher"szaft] = szaft"teher"szaft -} -ugass(a) -//csömör(szaft"háh, appja hám"szaft) -ugass(tarh(a)) \ No newline at end of file +gethelj listener = kábel.halgass(szaft"0.0.0.0"szaft, 1010) +gethelj stream = listener.kérés(listener) + +ugass(stream.olvass(stream, 1024)) +stream.írj(stream, szaft"HTTP/1.1 200 OK +Content-type: text/html; charset=utf-8 + +szafal a pofád!"szaft) \ No newline at end of file