AstroLang/src/enviroment.rs
2025-06-16 14:30:40 +02:00

549 lines
No EOL
23 KiB
Rust

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<VMMemory>, 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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::<TcpStream>();
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<u8> = 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>) -> 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::<TcpStream>();
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>) -> 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::<TcpStream>();
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>) -> 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::<TcpListener>();
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<TableValue> = 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>) -> 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<TableValue> = 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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<String, VMMemory> {
let mut mem: HashMap<String, VMMemory> = 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<TableValue> = 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<TableValue> = 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<TableValue> = 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;
}