diff --git a/Cargo.lock b/Cargo.lock index 9fbafa5..c3a0311 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "bad-lang-2" -version = "0.2.1" +version = "0.3.0" dependencies = [ "meval", "rand", diff --git a/Cargo.toml b/Cargo.toml index 69c830f..59a587d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bad-lang-2" -version = "0.2.1" +version = "0.3.0" edition = "2024" [[bin]] diff --git a/samples/bogosort.bl b/samples/bogosort.bl index 02f055d..0fce47d 100644 --- a/samples/bogosort.bl +++ b/samples/bogosort.bl @@ -3,14 +3,11 @@ fn is_sorted(n) { if (#lt(len, 2)) { return true } + let prev = array#get(n, 0) - prev = array#get(n, 0) - // This double assignment is because the language - // is broken currently - let j = null - j = 1 - let sorted = null - sorted = true + + let j = 1 + let sorted = true loop { if (#eq(j, len)) { sorted = true @@ -28,21 +25,20 @@ fn is_sorted(n) { fn bogosort(n) { let len = array#len(n) - // Non-fn scope variables seem broken atm - let i = null - let new_pos = null - let tmp = null + loop { if (is_sorted(n)) { break } - i = 0 + let i = 0 loop { if (#gt(#=("{} + 1", i), len)) { break } - new_pos = math#round(rng#rand_range(0, #=("{} - 1", len))) - tmp = array#get(n, new_pos) + + let new_pos = math#round(rng#rand_range(0, #=("{} - 1", len))) + let tmp = array#get(n, new_pos) + array#set(n, new_pos, array#get(n, i)) array#set(n, i, tmp) i++ @@ -50,7 +46,7 @@ fn bogosort(n) { } } -let numbers = [5, 4, 3, 2, 1, 0, -1] +let numbers = [5, -1, 4, 3] io#println("Before:") io#println(numbers) @@ -61,4 +57,4 @@ io#println("After:") io#println(numbers) io#println("In:") io#println(#=("{} - {}", end, start)) -io#println("s") +io#println("s") \ No newline at end of file diff --git a/samples/random.bl b/samples/random.bl index 4285d3c..9dbdadc 100644 --- a/samples/random.bl +++ b/samples/random.bl @@ -1,8 +1,10 @@ loop { // Always NaN io#println(rng#rand_range(nan, 100)) + // f64 in [0, 1) io#println(rng#rand()) + // f64 in [0, 9] intersection N io#println(math#round(rng#rand_range(0, #=("{} - 1", 10)))) } diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index 3cd6e56..49a2bc2 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -1,114 +1,84 @@ use crate::token::{ - Token, + InsideToken, Token, base::{BaseToken, NullToken, ValueToken}, logic::{ExpressionToken, LetToken, NumOperation, ReturnToken}, runtime, }; -use std::cell::RefCell; -use std::collections::HashMap; -use std::rc::Rc; +use std::sync::Arc; +use std::{collections::HashMap, sync::Mutex}; -struct Scope { - variables: HashMap>>, - parent: Option>>, +pub struct Runtime { + tokens: Vec, + call_stack: Vec, + scopes: Vec>>>, } -impl Scope { - fn new(parent: Option>>) -> Self { +impl Runtime { + pub fn new(tokens: Vec) -> Self { Self { - variables: HashMap::new(), - parent, + tokens, + call_stack: Vec::new(), + scopes: vec![HashMap::new()], } } - fn get(&self, name: &str) -> Option>> { - if let Some(value) = self.variables.get(name) { - Some(value.clone()) - } else if let Some(parent) = &self.parent { - parent.borrow().get(name) - } else { - None + pub fn run(&mut self) { + for token in self.tokens.clone() { + self.execute(&token); } } - fn set(&mut self, name: &str, value: Rc>) { - self.variables.insert(name.to_string(), value); - } - - fn update(&mut self, name: &str, value: ExpressionToken) -> bool { - if let Some(var) = self.variables.get(name) { - *var.borrow_mut() = value; - return true; - } else if let Some(parent) = &self.parent { - return parent.borrow_mut().update(name, value); - } - false + fn scope_set(&mut self, name: &str, value: Arc>) { + self.scopes + .last_mut() + .unwrap() + .insert(name.to_string(), value); } -} - -pub struct Runtime { - tokens: Vec, - current_scope: Rc>, - call_stack: Vec, - globals: HashMap>>, -} - -impl Runtime { - pub fn new(tokens: Vec) -> Self { - let global_scope = Rc::new(RefCell::new(Scope::new(None))); - let mut globals = HashMap::new(); - for token in &tokens { - if let Token::Let(let_token) = token { - let var = let_token.value.clone(); - global_scope.borrow_mut().set(&let_token.name, var.clone()); + fn scope_aggregate(&self) -> HashMap>> { + let mut aggregate = HashMap::new(); - globals.insert(let_token.name.clone(), var); + for scope in self.scopes.iter().rev() { + for (name, value) in scope.iter() { + if !aggregate.contains_key(name) { + aggregate.insert(name.clone(), Arc::clone(value)); + } } } - Self { - tokens, - current_scope: global_scope, - call_stack: Vec::new(), - globals, - } + aggregate } - pub fn run(&mut self) { - for token in self.tokens.clone() { - self.execute(&token); - } + fn scope_create(&mut self) { + self.scopes.push(HashMap::new()); } fn execute(&mut self, token: &Token) -> Option { match token { Token::Let(let_token) => { - let value = self.extract_value(&let_token.value.borrow()).unwrap(); - let expr_value = ExpressionToken::Value(value); - *let_token.value.borrow_mut() = expr_value.clone(); + let value = self + .extract_value(&let_token.value.lock().unwrap()) + .unwrap(); - if self.globals.contains_key(&let_token.name) { - *self.globals.get(&let_token.name).unwrap().borrow_mut() = expr_value; + for variable in self.scopes.last().unwrap().iter() { + if variable.0 == &let_token.name { + return Some(ExpressionToken::Value(ValueToken::Null(NullToken { + location: Default::default(), + }))); + } } + + self.scope_set( + &let_token.name, + Arc::new(Mutex::new(ExpressionToken::Value(value))), + ); } Token::Loop(loop_token) => { - self.call_stack.push(Token::Loop(loop_token.clone())); - - let loop_scope = - Rc::new(RefCell::new(Scope::new(Some(self.current_scope.clone())))); - let old_scope = std::mem::replace(&mut self.current_scope, loop_scope); - - for token in loop_token.body.borrow().iter() { - if let Token::Let(let_token) = token { - self.current_scope - .borrow_mut() - .set(&let_token.name, let_token.value.clone()); - } - } + self.call_stack.push(InsideToken::Loop(loop_token.clone())); + self.scope_create(); - let body = loop_token.body.borrow(); + let body = loop_token.body.lock().unwrap(); loop { let mut break_loop = false; @@ -123,55 +93,47 @@ impl Runtime { if break_loop { break; } + + self.scopes.last_mut().unwrap().clear(); } - self.current_scope = old_scope; + self.scopes.pop(); self.call_stack.pop(); } Token::If(if_token) => { - self.call_stack.push(Token::If(if_token.clone())); + self.call_stack.push(InsideToken::If(if_token.clone())); let condition = self.extract_value(&if_token.condition).unwrap(); if (if_token.reversed && !condition.truthy()) || (!if_token.reversed && condition.truthy()) { - let if_scope = - Rc::new(RefCell::new(Scope::new(Some(self.current_scope.clone())))); - let old_scope = std::mem::replace(&mut self.current_scope, if_scope); - - for token in if_token.body.borrow().iter() { - if let Token::Let(let_token) = token { - self.current_scope - .borrow_mut() - .set(&let_token.name, let_token.value.clone()); - } - } + self.scope_create(); - let body = if_token.body.borrow(); + let body = if_token.body.lock().unwrap(); for token in body.iter() { let value = self.execute(token); if value.is_none() { - self.current_scope = old_scope; + self.scopes.pop(); self.call_stack.pop(); return None; } else if let Some(ExpressionToken::Return(return_token)) = value { - self.current_scope = old_scope; + self.scopes.pop(); self.call_stack.pop(); return Some(ExpressionToken::Return(return_token)); } } - self.current_scope = old_scope; + self.scopes.pop(); } self.call_stack.pop(); } Token::Break(_) => { for token in self.call_stack.iter().rev() { - if let Token::Loop(_) = token { + if let InsideToken::Loop(_) = token { return None; } } @@ -179,171 +141,110 @@ impl Runtime { Token::Return(token) => { let value = self.extract_value(&token.value).unwrap(); - for token in self.call_stack.iter().rev() { - if let Token::Fn(_) = token { - return Some(ExpressionToken::Return(ReturnToken { - value: Rc::new(ExpressionToken::Value(value)), - })); - } - } + return Some(ExpressionToken::Return(ReturnToken { + value: Arc::new(ExpressionToken::Value(value)), + })); } Token::FnCall(call_token) => { if runtime::FUNCTIONS.contains(&call_token.name.as_str()) { - let mut arg_refs = Vec::new(); - for arg in &call_token.args { - arg_refs.push(arg.clone()); - } + let args: Vec> = call_token + .args + .iter() + .map(|arg| Arc::new((*arg.lock().unwrap()).clone())) + .collect(); - let result = runtime::run(call_token.name.as_str(), &call_token.args, self); + let result = runtime::run(call_token.name.as_str(), &args, self); return result; } - let fn_token_opt = self.tokens.iter().find_map(|token| { - if let Token::Fn(fn_token) = token { - if call_token.name == fn_token.name { - Some(fn_token.clone()) - } else { - None - } - } else { - None + for variable in self.scope_aggregate().iter() { + if variable.1.try_lock().is_err() { + continue; } - }); - - if let Some(fn_token) = fn_token_opt { - self.call_stack.push(Token::Fn(fn_token.clone())); - let fn_scope = - Rc::new(RefCell::new(Scope::new(Some(self.current_scope.clone())))); - let old_scope = std::mem::replace(&mut self.current_scope, fn_scope); - - for token in fn_token.body.borrow().iter() { - if let Token::Let(let_token) = token { - if !fn_token.args.contains(&let_token.name) { - self.current_scope - .borrow_mut() - .set(&let_token.name, let_token.value.clone()); - } - } - } - - let mut evaluated_args = Vec::new(); - for (index, arg_name) in fn_token.args.iter().enumerate() { - if let Some(arg_expr) = call_token.args.get(index) { - if let ExpressionToken::Let(let_token) = &**arg_expr { - if let Some(original_var) = - self.find_original_variable(&let_token.name) - { - evaluated_args.push((arg_name.clone(), original_var)); - continue; + if let ValueToken::Function(fn_token) = + self.extract_value(&*variable.1.lock().unwrap()).unwrap() + { + if variable.0 == &call_token.name { + self.call_stack + .push(InsideToken::Function(fn_token.clone())); + self.scope_create(); + + for (index, arg) in fn_token.args.iter().enumerate() { + if let Some(arg_expr) = call_token.args.get(index) { + let extracted = + self.extract_value(&arg_expr.lock().unwrap()).unwrap(); + + self.scope_set( + arg, + Arc::new(Mutex::new(ExpressionToken::Value(extracted))), + ); } } - let arg_value = self.extract_value(&arg_expr).unwrap(); - let value_expr = ExpressionToken::Value(arg_value); - let value_ref = Rc::new(RefCell::new(value_expr)); - evaluated_args.push((arg_name.clone(), value_ref)); - } else { - let null_value = ExpressionToken::Value(ValueToken::Null(NullToken { - location: Default::default(), - })); - evaluated_args - .push((arg_name.clone(), Rc::new(RefCell::new(null_value)))); - } - } + let body = fn_token.body.lock().unwrap(); - for (arg_name, arg_value) in evaluated_args { - self.current_scope.borrow_mut().set(&arg_name, arg_value); - } - - let mut return_value = None; - let body_tokens = fn_token.body.borrow().clone(); + for token in body.iter() { + let value = self.execute(token); - for token in body_tokens.iter() { - let value = self.execute(token); + if value.is_none() { + break; + } else if let Some(ExpressionToken::Return(return_token)) = value { + self.call_stack.pop(); + return Some(ExpressionToken::Return(return_token)); + } + } - if value.is_none() { - break; - } else if let Some(ExpressionToken::Return(return_token)) = value { - return_value = Some((*return_token.value).clone()); - break; + self.scopes.pop(); + self.call_stack.pop(); } } - - self.current_scope = old_scope; - self.call_stack.pop(); - - return return_value; } } Token::LetAssign(assign_token) => { let value = self.extract_value(&assign_token.value).unwrap(); let expr_value = ExpressionToken::Value(value); - let updated = self - .current_scope - .borrow_mut() - .update(&assign_token.name, expr_value.clone()); - - if !updated { - self.current_scope.borrow_mut().set( - &assign_token.name, - Rc::new(RefCell::new(expr_value.clone())), - ); - } - - if self.globals.contains_key(&assign_token.name) { - *self.globals.get(&assign_token.name).unwrap().borrow_mut() = expr_value; + for variable in self.scope_aggregate().iter() { + if variable.0 == &assign_token.name { + *variable.1.lock().unwrap() = expr_value; + break; + } } } Token::LetAssignNum(assign_token) => { let value = self.extract_value(&assign_token.value).unwrap(); - if let Some(var) = self.current_scope.borrow().get(&assign_token.name) { - let mut var_ref = var.borrow_mut(); - - if let ExpressionToken::Value(ValueToken::Number(ref mut number_token)) = - *var_ref - { - if let ValueToken::Number(value_token) = &value { - match assign_token.operation { - NumOperation::Add => { - number_token.value += value_token.value; - } - NumOperation::Sub => { - number_token.value -= value_token.value; - } - NumOperation::Mul => { - number_token.value *= value_token.value; - } - NumOperation::Div => { - number_token.value /= value_token.value; + for variable in self.scope_aggregate().iter() { + if variable.0 == &assign_token.name { + let mut var_ref = variable.1.lock().unwrap(); + + if let ExpressionToken::Value(ValueToken::Number(ref mut number_token)) = + *var_ref + { + if let ValueToken::Number(value_token) = &value { + match assign_token.operation { + NumOperation::Add => { + number_token.value += value_token.value; + } + NumOperation::Sub => { + number_token.value -= value_token.value; + } + NumOperation::Mul => { + number_token.value *= value_token.value; + } + NumOperation::Div => { + number_token.value /= value_token.value; + } } } + } else { + *var_ref = ExpressionToken::Value(value.clone()); } - } else { - *var_ref = ExpressionToken::Value(value.clone()); - } - - if self.globals.contains_key(&assign_token.name) { - *self.globals.get(&assign_token.name).unwrap().borrow_mut() = - ExpressionToken::Value(value); - } - } else { - let value_expr = ExpressionToken::Value(value.clone()); - let value_ref = Rc::new(RefCell::new(value_expr)); - - self.current_scope - .borrow_mut() - .set(&assign_token.name, value_ref.clone()); - - if self.call_stack.is_empty() { - self.globals.insert(assign_token.name.clone(), value_ref); } } } - _ => {} } Some(ExpressionToken::Value(ValueToken::Null(NullToken { @@ -351,39 +252,17 @@ impl Runtime { }))) } - fn find_original_variable(&self, name: &str) -> Option>> { - if let Some(global_var) = self.globals.get(name) { - return Some(global_var.clone()); - } - - self.current_scope.borrow().get(name) - } - pub fn extract_value(&mut self, token: &ExpressionToken) -> Option { match token { ExpressionToken::Value(value) => Some(value.clone()), ExpressionToken::Let(LetToken { name, .. }) => { - let var_opt = self.current_scope.borrow().get(name).clone(); - - if let Some(var) = var_opt { - if let ExpressionToken::Value(value) = &*var.borrow() { - Some(value.clone()) - } else { - self.extract_value(&var.borrow()) - } - } else { - if let Some(global_var) = self.globals.get(name).cloned() { - if let ExpressionToken::Value(value) = &*global_var.borrow() { - Some(value.clone()) - } else { - self.extract_value(&global_var.borrow()) - } - } else { - Some(ValueToken::Null(NullToken { - location: Default::default(), - })) + for variable in self.scope_aggregate().iter() { + if variable.0 == name { + return self.extract_value(&*variable.1.lock().unwrap()); } } + + None } ExpressionToken::FnCall(value) => { let value = diff --git a/src/token/base.rs b/src/token/base.rs index c706f2b..445a119 100644 --- a/src/token/base.rs +++ b/src/token/base.rs @@ -1,6 +1,6 @@ -use std::{cell::RefCell, rc::Rc}; +use std::sync::{Arc, Mutex}; -use super::{TokenLocation, logic::ExpressionToken}; +use super::{Token, TokenLocation, logic::ExpressionToken}; pub trait BaseToken { fn inspect(&self) -> String; @@ -71,14 +71,14 @@ impl BaseToken for BooleanToken { #[derive(Debug, Clone)] pub struct ArrayToken { pub location: TokenLocation, - pub value: Rc>>, + pub value: Arc>>, } impl BaseToken for ArrayToken { fn inspect(&self) -> String { - let mut result = format!("Array({}) {{\n", self.value.borrow().len()); + let mut result = format!("Array({}) {{\n", self.value.lock().unwrap().len()); - for token in self.value.borrow().iter() { + for token in self.value.lock().unwrap().iter() { if let ExpressionToken::Value(value_token) = token { result.push_str(&format!("{}\n", value_token.inspect())); } @@ -90,7 +90,7 @@ impl BaseToken for ArrayToken { fn value(&self) -> String { let mut result = "[\n".to_string(); - for token in self.value.borrow().iter() { + for token in self.value.lock().unwrap().iter() { if let ExpressionToken::Value(value_token) = token { result.push_str(&format!("{}\n", value_token.value())); } @@ -100,7 +100,46 @@ impl BaseToken for ArrayToken { } fn truthy(&self) -> bool { - !self.value.borrow().is_empty() + !self.value.lock().unwrap().is_empty() + } +} + +#[derive(Debug, Clone)] +pub struct BufferToken { + pub location: TokenLocation, + pub value: Arc>>, +} + +impl BaseToken for BufferToken { + fn inspect(&self) -> String { + let mut result = format!("Buffer({}) {{ ", self.value.lock().unwrap().len()); + + for byte in self.value.lock().unwrap().iter().take(100) { + result.push_str(&format!("{:02x} ", byte)); + } + + if self.value.lock().unwrap().len() > 100 { + result + .push_str(format!("... {} more ", self.value.lock().unwrap().len() - 100).as_str()); + } + + result + "}" + } + + fn value(&self) -> String { + let length = self.value.lock().unwrap().len(); + + self.value + .lock() + .unwrap() + .iter() + .fold(String::with_capacity(length * 3), |acc, byte| { + acc + &format!("{:02x} ", byte) + }) + } + + fn truthy(&self) -> bool { + !self.value.lock().unwrap().is_empty() } } @@ -123,6 +162,52 @@ impl BaseToken for NullToken { } } +#[derive(Debug, Clone)] +pub struct NativeMemoryToken { + pub name: String, + pub memory: Arc>>, +} + +impl BaseToken for NativeMemoryToken { + fn inspect(&self) -> String { + format!("NativeMemory({}) {{ }}", self.name) + } + + fn value(&self) -> String { + self.inspect() + } + + fn truthy(&self) -> bool { + true + } +} + +#[derive(Debug, Clone)] +pub struct FunctionToken { + pub name: String, + pub args: Vec, + pub body: Arc>>, +} + +impl BaseToken for FunctionToken { + fn inspect(&self) -> String { + format!( + "Function({}, {}) {{ <{} tokens> }}", + self.name, + self.args.join(", "), + self.body.lock().unwrap().len() + ) + } + + fn value(&self) -> String { + self.inspect() + } + + fn truthy(&self) -> bool { + true + } +} + #[derive(Debug, Clone)] pub enum ValueToken { String(StringToken), @@ -130,6 +215,9 @@ pub enum ValueToken { Boolean(BooleanToken), Null(NullToken), Array(ArrayToken), + Buffer(BufferToken), + NativeMemory(NativeMemoryToken), + Function(FunctionToken), } impl BaseToken for ValueToken { @@ -140,6 +228,9 @@ impl BaseToken for ValueToken { ValueToken::Boolean(boolean_token) => boolean_token.inspect(), ValueToken::Null(null_token) => null_token.inspect(), ValueToken::Array(array_token) => array_token.inspect(), + ValueToken::Buffer(buffer_token) => buffer_token.inspect(), + ValueToken::NativeMemory(native_memory_token) => native_memory_token.inspect(), + ValueToken::Function(function_token) => function_token.inspect(), } } @@ -150,6 +241,9 @@ impl BaseToken for ValueToken { ValueToken::Boolean(boolean_token) => boolean_token.value(), ValueToken::Null(null_token) => null_token.value(), ValueToken::Array(array_token) => array_token.value(), + ValueToken::Buffer(buffer_token) => buffer_token.value(), + ValueToken::NativeMemory(native_memory_token) => native_memory_token.value(), + ValueToken::Function(function_token) => function_token.value(), } } @@ -160,6 +254,9 @@ impl BaseToken for ValueToken { ValueToken::Boolean(boolean_token) => boolean_token.truthy(), ValueToken::Null(null_token) => null_token.truthy(), ValueToken::Array(array_token) => array_token.truthy(), + ValueToken::Buffer(buffer_token) => buffer_token.truthy(), + ValueToken::NativeMemory(native_memory_token) => native_memory_token.truthy(), + ValueToken::Function(function_token) => function_token.truthy(), } } } diff --git a/src/token/logic.rs b/src/token/logic.rs index 5825fae..f319495 100644 --- a/src/token/logic.rs +++ b/src/token/logic.rs @@ -1,6 +1,6 @@ use super::{Token, base::ValueToken}; -use std::{cell::RefCell, rc::Rc}; +use std::sync::{Arc, Mutex}; #[derive(Debug, Clone)] pub enum NumOperation { @@ -14,7 +14,8 @@ pub enum NumOperation { pub struct LetToken { pub name: String, pub is_const: bool, - pub value: Rc>, + pub is_function: bool, + pub value: Arc>, } #[derive(Debug, Clone)] @@ -28,39 +29,32 @@ pub enum ExpressionToken { #[derive(Debug, Clone)] pub struct LetAssignToken { pub name: String, - pub value: Rc, + pub value: Arc, } #[derive(Debug, Clone)] pub struct LetAssignNumToken { pub name: String, pub operation: NumOperation, - pub value: Rc, -} - -#[derive(Debug, Clone)] -pub struct FnToken { - pub name: String, - pub args: Vec, - pub body: Rc>>, + pub value: Arc, } #[derive(Debug, Clone)] pub struct FnCallToken { pub name: String, - pub args: Vec>, + pub args: Vec>>, } #[derive(Debug, Clone)] pub struct LoopToken { - pub body: Rc>>, + pub body: Arc>>, } #[derive(Debug, Clone)] pub struct IfToken { pub reversed: bool, - pub condition: Rc, - pub body: Rc>>, + pub condition: Arc, + pub body: Arc>>, } #[derive(Debug, Clone)] @@ -68,5 +62,5 @@ pub struct BreakToken; #[derive(Debug, Clone)] pub struct ReturnToken { - pub value: Rc, + pub value: Arc, } diff --git a/src/token/macros/mod.rs b/src/token/macros/mod.rs index 0a2563b..3ee9d61 100644 --- a/src/token/macros/mod.rs +++ b/src/token/macros/mod.rs @@ -17,7 +17,7 @@ pub fn extract_number(token: &ExpressionToken) -> Option { } if let ExpressionToken::Value(ValueToken::Number(NumberToken { value, .. })) = - &*value.borrow() + &*value.lock().unwrap() { Some(*value) } else { @@ -41,7 +41,7 @@ pub fn extract_string(token: &ExpressionToken) -> Option { } if let ExpressionToken::Value(ValueToken::String(StringToken { value, .. })) = - &*value.borrow() + &*value.lock().unwrap() { Some(value.clone()) } else { @@ -110,7 +110,7 @@ pub fn inline(args: Vec) -> Option { return None; } - match &*value.as_ref().borrow() { + match &*value.as_ref().lock().unwrap() { ExpressionToken::Value(ValueToken::String(StringToken { value, location })) => { Some(ExpressionToken::Value(ValueToken::String(StringToken { location: *location, diff --git a/src/token/mod.rs b/src/token/mod.rs index 5a30c0c..c4616ef 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -3,12 +3,17 @@ pub mod logic; pub mod macros; pub mod runtime; -use base::{ArrayToken, BooleanToken, NullToken, NumberToken, StringToken, ValueToken}; +use base::{ + ArrayToken, BooleanToken, FunctionToken, NullToken, NumberToken, StringToken, ValueToken, +}; use logic::{ - BreakToken, ExpressionToken, FnCallToken, FnToken, IfToken, LetAssignNumToken, LetAssignToken, - LetToken, LoopToken, ReturnToken, + BreakToken, ExpressionToken, FnCallToken, IfToken, LetAssignNumToken, LetAssignToken, LetToken, + LoopToken, ReturnToken, +}; +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, }; -use std::{cell::RefCell, collections::HashMap, rc::Rc}; #[derive(Debug, Clone, Copy)] pub struct TokenLocation { @@ -26,7 +31,6 @@ pub enum Token { Let(LetToken), LetAssign(LetAssignToken), LetAssignNum(LetAssignNumToken), - Fn(FnToken), FnCall(FnCallToken), Loop(LoopToken), Break(BreakToken), @@ -34,14 +38,21 @@ pub enum Token { If(IfToken), } +pub enum InsideToken { + Function(FunctionToken), + Loop(LoopToken), + If(IfToken), +} + pub static mut LINE: usize = 0; +type MacroFn = fn(Vec) -> Option; pub struct Tokenizer { input: String, - default_macros: HashMap) -> Option>, + default_macros: HashMap, pub tokens: Vec, - inside: Vec>>, + inside: Vec>>, } impl Tokenizer { @@ -49,22 +60,10 @@ impl Tokenizer { Self { input: input.to_string(), default_macros: HashMap::from([ - ( - "concat!".to_string(), - macros::concat as fn(Vec) -> Option, - ), - ( - "inline!".to_string(), - macros::inline as fn(Vec) -> Option, - ), - ( - "add!".to_string(), - macros::number::add as fn(Vec) -> Option, - ), - ( - "sqrt!".to_string(), - macros::number::sqrt as fn(Vec) -> Option, - ), + ("concat!".to_string(), macros::concat as MacroFn), + ("inline!".to_string(), macros::inline as MacroFn), + ("add!".to_string(), macros::number::add as MacroFn), + ("sqrt!".to_string(), macros::number::sqrt as MacroFn), ]), tokens: Vec::new(), inside: Vec::new(), @@ -88,17 +87,16 @@ impl Tokenizer { fn push_token(&mut self, token: Token) { if !self.inside.is_empty() { - match &*self.inside.last().unwrap().borrow() { - Token::Fn(fn_token) => { - fn_token.body.borrow_mut().push(token); + match &*self.inside.last().unwrap().lock().unwrap() { + InsideToken::Function(fn_token) => { + fn_token.body.lock().unwrap().push(token); } - Token::Loop(loop_token) => { - loop_token.body.borrow_mut().push(token); + InsideToken::Loop(loop_token) => { + loop_token.body.lock().unwrap().push(token); } - Token::If(if_token) => { - if_token.body.borrow_mut().push(token); + InsideToken::If(if_token) => { + if_token.body.lock().unwrap().push(token); } - _ => unreachable!(), } } else { self.tokens.push(token); @@ -110,57 +108,83 @@ impl Tokenizer { for token in &self.tokens { tokens.push(token.clone()); - self.add_nested_tokens(token, &mut tokens); + Self::add_nested_tokens(Self::check_if_is_inside(token), &mut tokens); } for inside in &self.inside { - match &*inside.borrow() { - Token::Fn(fn_token) => { - for token in fn_token.body.borrow().iter() { + match &*inside.lock().unwrap() { + InsideToken::Function(fn_token) => { + for token in fn_token.body.lock().unwrap().iter() { tokens.push(token.clone()); - self.add_nested_tokens(token, &mut tokens); + Self::add_nested_tokens(Self::check_if_is_inside(token), &mut tokens); } } - Token::Loop(loop_token) => { - for token in loop_token.body.borrow().iter() { + InsideToken::Loop(loop_token) => { + for token in loop_token.body.lock().unwrap().iter() { tokens.push(token.clone()); - self.add_nested_tokens(token, &mut tokens); + Self::add_nested_tokens(Self::check_if_is_inside(token), &mut tokens); } } - Token::If(if_token) => { - for token in if_token.body.borrow().iter() { + InsideToken::If(if_token) => { + for token in if_token.body.lock().unwrap().iter() { tokens.push(token.clone()); - self.add_nested_tokens(token, &mut tokens); + Self::add_nested_tokens(Self::check_if_is_inside(token), &mut tokens); } } - _ => unreachable!(), } } tokens } - fn add_nested_tokens(&self, token: &Token, tokens: &mut Vec) { + fn check_if_is_inside(token: &Token) -> Option { match token { - Token::Fn(fn_token) => { - for token in fn_token.body.borrow().iter() { + Token::Loop(loop_token) => { + return Some(InsideToken::Loop(loop_token.clone())); + } + Token::If(if_token) => { + return Some(InsideToken::If(if_token.clone())); + } + Token::Let(let_token) => { + if let_token.is_function { + match &*let_token.value.lock().unwrap() { + ExpressionToken::Value(ValueToken::Function(fn_token)) => { + return Some(InsideToken::Function(fn_token.clone())); + } + _ => {} + } + } + } + _ => {} + } + + None + } + + fn add_nested_tokens(token: Option, tokens: &mut Vec) { + if token.is_none() { + return; + } + + match token.unwrap() { + InsideToken::Function(fn_token) => { + for token in fn_token.body.lock().unwrap().iter() { tokens.push(token.clone()); - self.add_nested_tokens(token, tokens); + Self::add_nested_tokens(Self::check_if_is_inside(token), tokens); } } - Token::Loop(loop_token) => { - for token in loop_token.body.borrow().iter() { + InsideToken::Loop(loop_token) => { + for token in loop_token.body.lock().unwrap().iter() { tokens.push(token.clone()); - self.add_nested_tokens(token, tokens); + Self::add_nested_tokens(Self::check_if_is_inside(token), tokens); } } - Token::If(if_token) => { - for token in if_token.body.borrow().iter() { + InsideToken::If(if_token) => { + for token in if_token.body.lock().unwrap().iter() { tokens.push(token.clone()); - self.add_nested_tokens(token, tokens); + Self::add_nested_tokens(Self::check_if_is_inside(token), tokens); } } - _ => {} } } @@ -205,7 +229,8 @@ impl Tokenizer { return Some(Token::Let(LetToken { name: name.to_string(), is_const: parts[1] == "const", - value: Rc::new(RefCell::new(value.unwrap())), + is_function: false, + value: Arc::new(Mutex::new(value.unwrap())), })); } else if segment.starts_with("fn") { let parts: Vec<&str> = segment.split("(").collect(); @@ -229,7 +254,8 @@ impl Tokenizer { body.push(Token::Let(LetToken { name: arg.clone(), is_const: false, - value: Rc::new(RefCell::new(ExpressionToken::Value(ValueToken::Null( + is_function: false, + value: Arc::new(Mutex::new(ExpressionToken::Value(ValueToken::Null( NullToken { location: self.location(), }, @@ -237,36 +263,45 @@ impl Tokenizer { })); } - let body = Rc::new(RefCell::new(body)); - let token = Token::Fn(FnToken { + let body = Arc::new(Mutex::new(body)); + + let value = ValueToken::Function(FunctionToken { name: name.clone(), args: args.clone(), - body: Rc::clone(&body), + body: Arc::clone(&body), + }); + + let token = Token::Let(LetToken { + name: name.clone(), + is_const: true, + is_function: true, + value: Arc::new(Mutex::new(ExpressionToken::Value(value))), }); self.push_token(token); - self.inside.push(Rc::new(RefCell::new(Token::Fn(FnToken { - name, - args, - body, - })))); + self.inside + .push(Arc::new(Mutex::new(InsideToken::Function(FunctionToken { + name, + args, + body, + })))); return None; } else if segment.starts_with("loop") { - let body = Rc::new(RefCell::new(Vec::new())); + let body = Arc::new(Mutex::new(Vec::new())); let token = Token::Loop(LoopToken { - body: Rc::clone(&body), + body: Arc::clone(&body), }); self.push_token(token); self.inside - .push(Rc::new(RefCell::new(Token::Loop(LoopToken { body })))); + .push(Arc::new(Mutex::new(InsideToken::Loop(LoopToken { body })))); return None; } else if segment.starts_with("return") && !self.inside.is_empty() { if segment.len() < 7 { return Some(Token::Return(ReturnToken { - value: Rc::new(ExpressionToken::Value(ValueToken::Null(NullToken { + value: Arc::new(ExpressionToken::Value(ValueToken::Null(NullToken { location: self.location(), }))), })); @@ -280,7 +315,7 @@ impl Tokenizer { } return Some(Token::Return(ReturnToken { - value: Rc::new(value.unwrap()), + value: Arc::new(value.unwrap()), })); } else if segment.starts_with("if") { let reversed; @@ -293,25 +328,26 @@ impl Tokenizer { condition = self.parse_expression(segment[4..segment.len() - 3].trim()); } - let condition = Rc::new(condition.unwrap_or_else(|| { + let condition = Arc::new(condition.unwrap_or_else(|| { panic!("unexpected condition at line {} (did you typo?)", unsafe { LINE }) })); - let body = Rc::new(RefCell::new(Vec::new())); + let body = Arc::new(Mutex::new(Vec::new())); let token = Token::If(IfToken { reversed, - condition: Rc::clone(&condition), - body: Rc::clone(&body), + condition: Arc::clone(&condition), + body: Arc::clone(&body), }); self.push_token(token); - self.inside.push(Rc::new(RefCell::new(Token::If(IfToken { - reversed, - condition, - body, - })))); + self.inside + .push(Arc::new(Mutex::new(InsideToken::If(IfToken { + reversed, + condition, + body, + })))); return None; } else if segment == "break" && !self.inside.is_empty() { @@ -324,23 +360,23 @@ impl Tokenizer { return Some(Token::FnCall(FnCallToken { name: func.to_string(), - args: tokens.into_iter().map(Rc::new).collect(), + args: tokens.into_iter().map(Mutex::new).map(Arc::new).collect(), })); } } for token in self.current_tokens_context().iter().rev() { - if let Token::Fn(fn_token) = token { - if segment.starts_with(&format!("{}(", fn_token.name)) { + if let Token::Let(let_token) = token { + if segment.starts_with(&format!("{}(", let_token.name)) { let tokens = - self.parse_args(&segment[fn_token.name.len() + 1..segment.len() - 1]); + self.parse_args(&segment[let_token.name.len() + 1..segment.len() - 1]); return Some(Token::FnCall(FnCallToken { - name: fn_token.name.clone(), - args: tokens.into_iter().map(Rc::new).collect(), + name: let_token.name.clone(), + args: tokens.into_iter().map(Mutex::new).map(Arc::new).collect(), })); } - } else if let Token::Let(let_token) = token { + if let_token.is_const { continue; } @@ -355,7 +391,7 @@ impl Tokenizer { return Some(Token::LetAssign(LetAssignToken { name: let_token.name.clone(), - value: Rc::new(value.unwrap()), + value: Arc::new(value.unwrap()), })); } @@ -370,13 +406,13 @@ impl Tokenizer { return Some(Token::LetAssignNum(LetAssignNumToken { name: let_token.name.clone(), operation: logic::NumOperation::Add, - value: Rc::new(value.unwrap()), + value: Arc::new(value.unwrap()), })); } else if segment == format!("{}++", let_token.name) { return Some(Token::LetAssignNum(LetAssignNumToken { name: let_token.name.clone(), operation: logic::NumOperation::Add, - value: Rc::new(ExpressionToken::Value(ValueToken::Number(NumberToken { + value: Arc::new(ExpressionToken::Value(ValueToken::Number(NumberToken { location: self.location(), value: 1.0, }))), @@ -392,13 +428,13 @@ impl Tokenizer { return Some(Token::LetAssignNum(LetAssignNumToken { name: let_token.name.clone(), operation: logic::NumOperation::Sub, - value: Rc::new(value.unwrap()), + value: Arc::new(value.unwrap()), })); } else if segment == format!("{}--", let_token.name) { return Some(Token::LetAssignNum(LetAssignNumToken { name: let_token.name.clone(), operation: logic::NumOperation::Sub, - value: Rc::new(ExpressionToken::Value(ValueToken::Number(NumberToken { + value: Arc::new(ExpressionToken::Value(ValueToken::Number(NumberToken { location: self.location(), value: 1.0, }))), @@ -414,7 +450,7 @@ impl Tokenizer { return Some(Token::LetAssignNum(LetAssignNumToken { name: let_token.name.clone(), operation: logic::NumOperation::Mul, - value: Rc::new(value.unwrap()), + value: Arc::new(value.unwrap()), })); } else if segment.starts_with(&format!("{} /= ", let_token.name)) { let value = self.parse_expression(segment[let_token.name.len() + 4..].trim()); @@ -427,7 +463,7 @@ impl Tokenizer { return Some(Token::LetAssignNum(LetAssignNumToken { name: let_token.name.clone(), operation: logic::NumOperation::Div, - value: Rc::new(value.unwrap()), + value: Arc::new(value.unwrap()), })); } } @@ -449,7 +485,7 @@ impl Tokenizer { return Some(ExpressionToken::Value(ValueToken::Array(ArrayToken { location: self.location(), - value: Rc::new(RefCell::new(tokens)), + value: Arc::new(Mutex::new(tokens)), }))); } @@ -490,7 +526,7 @@ impl Tokenizer { return Some(ExpressionToken::FnCall(FnCallToken { name: func.to_string(), - args: tokens.into_iter().map(Rc::new).collect(), + args: tokens.into_iter().map(Mutex::new).map(Arc::new).collect(), })); } } @@ -505,21 +541,25 @@ impl Tokenizer { for token in self.current_tokens_context().iter().rev() { if let Token::Let(let_token) = token { - if segment == let_token.name { - return Some(ExpressionToken::Let(LetToken { + if segment.starts_with(&format!("{}(", let_token.name)) && let_token.is_function { + let tokens = + self.parse_args(&segment[let_token.name.len() + 1..segment.len() - 1]); + + return Some(ExpressionToken::FnCall(FnCallToken { name: let_token.name.clone(), - is_const: let_token.is_const, - value: Rc::clone(&let_token.value), + args: tokens.into_iter().map(Mutex::new).map(Arc::new).collect(), })); } - } else if let Token::Fn(fn_token) = token { - if segment.starts_with(&format!("{}(", fn_token.name)) { - let tokens = - self.parse_args(&segment[fn_token.name.len() + 1..segment.len() - 1]); - return Some(ExpressionToken::FnCall(FnCallToken { - name: fn_token.name.clone(), - args: tokens.into_iter().map(Rc::new).collect(), + if segment == let_token.name { + return Some(ExpressionToken::Let(LetToken { + name: let_token.name.clone(), + is_const: let_token.is_const, + is_function: match &*let_token.value.lock().unwrap() { + ExpressionToken::Value(ValueToken::Function(_)) => true, + _ => false, + }, + value: Arc::clone(&let_token.value), })); } } diff --git a/src/token/runtime/array.rs b/src/token/runtime/array.rs index 5d88107..9501ccc 100644 --- a/src/token/runtime/array.rs +++ b/src/token/runtime/array.rs @@ -9,7 +9,7 @@ use crate::{ }, }; -use std::{cell::RefCell, rc::Rc, sync::LazyLock}; +use std::sync::{Arc, LazyLock, Mutex}; pub static FUNCTIONS: LazyLock> = LazyLock::new(|| { vec![ @@ -26,7 +26,7 @@ pub static FUNCTIONS: LazyLock> = LazyLock::new(|| { pub fn run( name: &str, - args: &[Rc], + args: &[Arc], runtime: &mut Runtime, ) -> Option { match name { @@ -43,7 +43,11 @@ pub fn run( ValueToken::Array(array) => { for arg in args.iter().skip(1) { let value = runtime.extract_value(arg)?; - array.value.borrow_mut().push(ExpressionToken::Value(value)); + array + .value + .lock() + .unwrap() + .push(ExpressionToken::Value(value)); } Some(ExpressionToken::Value(ValueToken::Array(array.clone()))) @@ -64,13 +68,15 @@ pub fn run( let value = runtime.extract_value(&args[0])?; match value { ValueToken::Array(array) => { - let value = array - .value - .borrow_mut() - .pop() - .unwrap_or(ExpressionToken::Value(ValueToken::Null(NullToken { - location: Default::default(), - }))); + let value = + array + .value + .lock() + .unwrap() + .pop() + .unwrap_or(ExpressionToken::Value(ValueToken::Null(NullToken { + location: Default::default(), + }))); Some(value) } @@ -90,7 +96,7 @@ pub fn run( let value = runtime.extract_value(&args[0])?; match value { ValueToken::Array(array) => { - let len = array.value.borrow().len(); + let len = array.value.lock().unwrap().len(); Some(ExpressionToken::Value(ValueToken::Number(NumberToken { location: Default::default(), @@ -115,11 +121,11 @@ pub fn run( let value = runtime.extract_value(&args[0])?; match value { ValueToken::Array(array) => { - let value = array.value.borrow().clone(); + let value = array.value.lock().unwrap().clone(); Some(ExpressionToken::Value(ValueToken::Array(ArrayToken { location: Default::default(), - value: Rc::new(RefCell::new(value)), + value: Arc::new(Mutex::new(value)), }))) } _ => { @@ -145,7 +151,7 @@ pub fn run( match value { ValueToken::Array(array) => { - result.extend(array.value.borrow().iter().cloned()); + result.extend(array.value.lock().unwrap().iter().cloned()); } _ => { panic!( @@ -158,7 +164,7 @@ pub fn run( Some(ExpressionToken::Value(ValueToken::Array(ArrayToken { location: Default::default(), - value: Rc::new(RefCell::new(result)), + value: Arc::new(Mutex::new(result)), }))) } "array#contains" => { @@ -173,7 +179,7 @@ pub fn run( ValueToken::Array(array) => { let target = runtime.extract_value(&args[1])?; - let contains = array.value.borrow().iter().any(|item| { + let contains = array.value.lock().unwrap().iter().any(|item| { let item = runtime.extract_value(item).unwrap(); item.value() == target.value() }); @@ -203,11 +209,12 @@ pub fn run( match index { ValueToken::Number(number) => { let index = number.value as usize; - let value = array.value.borrow().get(index).cloned().unwrap_or({ - ExpressionToken::Value(ValueToken::Null(NullToken { - location: Default::default(), - })) - }); + let value = + array.value.lock().unwrap().get(index).cloned().unwrap_or({ + ExpressionToken::Value(ValueToken::Null(NullToken { + location: Default::default(), + })) + }); Some(value) } @@ -294,7 +301,7 @@ pub fn run( match index { ValueToken::Number(number) => { let index = number.value as usize; - let mut arr = array.value.borrow_mut(); + let mut arr = array.value.lock().unwrap(); if index >= arr.len() { arr.resize( @@ -317,6 +324,47 @@ pub fn run( } } } + ValueToken::Number(num) => { + let index = runtime.extract_value(&args[1])?; + + match index { + ValueToken::Number(number) => { + let index = number.value as usize; + + let integer = num.value as u64; + let bit = runtime.extract_value(&args[2])?; + let bit = match bit { + ValueToken::Boolean(boolean) => { + if boolean.value { + 1 + } else { + 0 + } + } + _ => { + panic!( + "array#set requires a boolean as the third argument on line {}", + unsafe { LINE } + ); + } + }; + + let mask = 1 << index; + let value = (integer & !mask) | (bit << index); + + Some(ExpressionToken::Value(ValueToken::Number(NumberToken { + location: Default::default(), + value: value as f64, + }))) + } + _ => { + panic!( + "array#set requires a number as the second argument on line {}", + unsafe { LINE } + ); + } + } + } _ => { panic!( "array#set requires an array as the first argument on line {}", diff --git a/src/token/runtime/fs.rs b/src/token/runtime/fs.rs index 0b09e0c..bcfba07 100644 --- a/src/token/runtime/fs.rs +++ b/src/token/runtime/fs.rs @@ -7,14 +7,17 @@ use crate::{ }, }; -use std::{io::Read, rc::Rc, sync::LazyLock}; +use std::{ + io::Read, + sync::{Arc, LazyLock}, +}; pub static FUNCTIONS: LazyLock> = LazyLock::new(|| vec!["fs#readstr", "fs#readstr_until"]); pub fn run( name: &str, - args: &[Rc], + args: &[Arc], runtime: &mut Runtime, ) -> Option { match name { diff --git a/src/token/runtime/io.rs b/src/token/runtime/io.rs index 7b33c81..239cf33 100644 --- a/src/token/runtime/io.rs +++ b/src/token/runtime/io.rs @@ -7,13 +7,13 @@ use crate::{ }, }; -use std::{rc::Rc, sync::LazyLock}; +use std::sync::{Arc, LazyLock}; pub static FUNCTIONS: LazyLock> = LazyLock::new(|| vec!["io#println", "io#inspect"]); pub fn run( name: &str, - args: &[Rc], + args: &[Arc], runtime: &mut Runtime, ) -> Option { match name { diff --git a/src/token/runtime/logic.rs b/src/token/runtime/logic.rs index 56d1f5d..3e42e7e 100644 --- a/src/token/runtime/logic.rs +++ b/src/token/runtime/logic.rs @@ -7,14 +7,14 @@ use crate::{ }, }; -use std::{rc::Rc, sync::LazyLock}; +use std::sync::{Arc, LazyLock}; pub static FUNCTIONS: LazyLock> = LazyLock::new(|| vec!["#eq", "#lt", "#gt", "#and", "#or"]); pub fn run( name: &str, - args: &[Rc], + args: &[Arc], runtime: &mut Runtime, ) -> Option { match name { diff --git a/src/token/runtime/math.rs b/src/token/runtime/math.rs index 1871049..4f50b5a 100644 --- a/src/token/runtime/math.rs +++ b/src/token/runtime/math.rs @@ -9,13 +9,14 @@ use crate::{ use super::string; -use std::{rc::Rc, sync::LazyLock}; +use std::sync::{Arc, LazyLock}; -pub static FUNCTIONS: LazyLock> = LazyLock::new(|| vec!["math#eval", "#=", "math#floor", "math#ceil", "math#round"]); +pub static FUNCTIONS: LazyLock> = + LazyLock::new(|| vec!["math#eval", "#=", "math#floor", "math#ceil", "math#round"]); pub fn run( name: &str, - args: &[Rc], + args: &[Arc], runtime: &mut Runtime, ) -> Option { match name { diff --git a/src/token/runtime/mod.rs b/src/token/runtime/mod.rs index 0f0ff71..ddb813d 100644 --- a/src/token/runtime/mod.rs +++ b/src/token/runtime/mod.rs @@ -5,12 +5,13 @@ pub mod logic; pub mod math; pub mod rng; pub mod string; +pub mod tcp; pub mod time; use super::logic::ExpressionToken; use crate::runtime::Runtime; -use std::{rc::Rc, sync::LazyLock}; +use std::sync::{Arc, LazyLock}; pub static FUNCTIONS: LazyLock> = LazyLock::new(|| { let mut vec = Vec::new(); @@ -23,13 +24,14 @@ pub static FUNCTIONS: LazyLock> = LazyLock::new(|| { vec.extend(&*logic::FUNCTIONS); vec.extend(&*time::FUNCTIONS); vec.extend(&*rng::FUNCTIONS); + vec.extend(&*tcp::FUNCTIONS); vec }); pub fn run( name: &str, - args: &[Rc], + args: &[Arc], runtime: &mut Runtime, ) -> Option { if io::FUNCTIONS.contains(&name) { @@ -48,6 +50,8 @@ pub fn run( time::run(name, args, runtime) } else if rng::FUNCTIONS.contains(&name) { rng::run(name, args, runtime) + } else if tcp::FUNCTIONS.contains(&name) { + tcp::run(name, args, runtime) } else { None } diff --git a/src/token/runtime/rng.rs b/src/token/runtime/rng.rs index 0898546..51969a9 100644 --- a/src/token/runtime/rng.rs +++ b/src/token/runtime/rng.rs @@ -7,13 +7,13 @@ use crate::{ }, }; -use std::{rc::Rc, sync::LazyLock}; +use std::sync::{Arc, LazyLock}; pub static FUNCTIONS: LazyLock> = LazyLock::new(|| vec!["rng#rand", "rng#rand_range"]); pub fn run( name: &str, - args: &[Rc], + args: &[Arc], runtime: &mut Runtime, ) -> Option { match name { diff --git a/src/token/runtime/string.rs b/src/token/runtime/string.rs index d2e33d0..b814405 100644 --- a/src/token/runtime/string.rs +++ b/src/token/runtime/string.rs @@ -1,20 +1,30 @@ use crate::{ runtime::Runtime, - token::LINE, token::{ - base::{BaseToken, NumberToken, StringToken, ValueToken}, + LINE, + base::{ArrayToken, BaseToken, NumberToken, StringToken, ValueToken}, logic::ExpressionToken, }, }; -use std::{rc::Rc, sync::LazyLock}; +use std::sync::{Arc, LazyLock, Mutex}; -pub static FUNCTIONS: LazyLock> = - LazyLock::new(|| vec!["string#concat", "string#format", "string#len"]); +pub static FUNCTIONS: LazyLock> = LazyLock::new(|| { + vec![ + "string#concat", + "string#format", + "string#len", + "string#split", + "string#trim", + "string#to_number", + "string#replace", + "string#replacen", + ] +}); pub fn run( name: &str, - args: &[Rc], + args: &[Arc], runtime: &mut Runtime, ) -> Option { match name { @@ -78,6 +88,114 @@ pub fn run( value: len as f64, }))) } + "string#split" => { + if args.len() != 2 { + panic!("string#split requires 2 arguments on line {}", unsafe { + LINE + }); + } + + let value = runtime.extract_value(&args[0])?; + let separator = runtime.extract_value(&args[1])?; + + let value = value.value(); + let separator = separator.value(); + + Some(ExpressionToken::Value(ValueToken::Array(ArrayToken { + location: Default::default(), + value: Arc::new(Mutex::new( + value + .split(&separator) + .map(|s| { + ExpressionToken::Value(ValueToken::String(StringToken { + location: Default::default(), + value: s.to_string(), + })) + }) + .collect(), + )), + }))) + } + "string#trim" => { + if args.len() != 1 { + panic!("string#trim requires 1 argument on line {}", unsafe { + LINE + }); + } + + let value = runtime.extract_value(&args[0])?; + let value = value.value(); + + Some(ExpressionToken::Value(ValueToken::String(StringToken { + location: Default::default(), + value: value.trim().to_string(), + }))) + } + "string#to_number" => { + if args.len() != 1 { + panic!("string#to_number requires 1 argument on line {}", unsafe { + LINE + }); + } + + let value = runtime.extract_value(&args[0])?; + let value = value.value(); + + let value = value.parse::().unwrap(); + + Some(ExpressionToken::Value(ValueToken::Number(NumberToken { + location: Default::default(), + value, + }))) + } + "string#replace" => { + if args.len() != 3 { + panic!("string#replace requires 3 arguments on line {}", unsafe { + LINE + }); + } + + let value = runtime.extract_value(&args[0])?; + let search = runtime.extract_value(&args[1])?; + let replace = runtime.extract_value(&args[2])?; + + let value = value.value(); + let search = search.value(); + let replace = replace.value(); + + Some(ExpressionToken::Value(ValueToken::String(StringToken { + location: Default::default(), + value: value.replace(&search, &replace), + }))) + } + "string#replacen" => { + if args.len() != 4 { + panic!("string#replacen requires 4 arguments on line {}", unsafe { + LINE + }); + } + + let value = runtime.extract_value(&args[0])?; + let search = runtime.extract_value(&args[1])?; + let replace = runtime.extract_value(&args[2])?; + let n = runtime.extract_value(&args[3])?; + + let value = value.value(); + let search = search.value(); + let replace = replace.value(); + let n = match n { + ValueToken::Number(n) => n.value as usize, + _ => panic!( + "string#replacen requires a number as the last argument on line {}", + unsafe { LINE } + ), + }; + + Some(ExpressionToken::Value(ValueToken::String(StringToken { + location: Default::default(), + value: value.replacen(&search, &replace, n), + }))) + } _ => None, } } diff --git a/src/token/runtime/tcp.rs b/src/token/runtime/tcp.rs new file mode 100644 index 0000000..2abd3af --- /dev/null +++ b/src/token/runtime/tcp.rs @@ -0,0 +1,206 @@ +use crate::{ + runtime::Runtime, + token::{ + LINE, + base::{BaseToken, BufferToken, NativeMemoryToken, NullToken, StringToken, ValueToken}, + logic::ExpressionToken, + }, +}; + +use std::{ + io::{Read, Write}, + sync::{Arc, LazyLock, Mutex}, +}; + +pub static FUNCTIONS: LazyLock> = LazyLock::new(|| { + vec![ + "tcp#bind", + "tcp#getconn", + "tcp#readstr", + "tcp#readbin", + "tcp#write", + "tcp#close", + ] +}); + +pub fn run( + name: &str, + args: &[Arc], + runtime: &mut Runtime, +) -> Option { + match name { + "tcp#bind" => { + if args.len() != 2 { + panic!("tcp#bind requires 2 arguments on line {}", unsafe { LINE }); + } + + let address = runtime.extract_value(&args[0])?; + let port = runtime.extract_value(&args[1])?; + + match (address, port) { + (ValueToken::String(address), ValueToken::Number(port)) => { + let listener = + std::net::TcpListener::bind(format!("{}:{}", address.value, port.value)) + .unwrap(); + + Some(ExpressionToken::Value(ValueToken::NativeMemory( + NativeMemoryToken { + name: "TcpListener".to_string(), + memory: Arc::new(Mutex::new(Box::new(listener))), + }, + ))) + } + _ => { + panic!( + "tcp#bind requires a string and a number on line {}", + unsafe { LINE } + ); + } + } + } + "tcp#getconn" => { + if args.len() != 1 { + panic!("tcp#getconn requires 1 argument on line {}", unsafe { + LINE + }); + } + + let listener = runtime.extract_value(&args[0]); + if let Some(ValueToken::NativeMemory(listener)) = listener { + let listener = listener.memory.lock().unwrap(); + let listener = listener + .as_ref() + .downcast_ref::() + .unwrap(); + + let (stream, _) = listener.accept().unwrap(); + + Some(ExpressionToken::Value(ValueToken::NativeMemory( + NativeMemoryToken { + name: "TcpStream".to_string(), + memory: Arc::new(Mutex::new(Box::new(stream))), + }, + ))) + } else { + panic!("tcp#getconn requires a TcpListener on line {}", unsafe { + LINE + }); + } + } + "tcp#readstr" => { + if args.is_empty() || args.len() > 2 { + panic!( + "tcp#readstr requires at least 1 argument and at most 2 arguments on line {}", + unsafe { LINE } + ); + } + + let stream = runtime.extract_value(&args[0]); + let length = if args.len() == 2 { + runtime.extract_value(&args[1]) + } else { + None + }; + + if let Some(ValueToken::NativeMemory(stream)) = stream { + let stream = stream.memory.lock().unwrap(); + let mut stream = stream + .as_ref() + .downcast_ref::() + .unwrap(); + + let length = if let Some(ValueToken::Number(length)) = length { + length.value as usize + } else { + 1024 + }; + + let mut buffer = vec![0; length]; + let read = stream.read(&mut buffer).unwrap(); + + let result = String::from_utf8_lossy(&buffer[..read]).to_string(); + + Some(ExpressionToken::Value(ValueToken::String(StringToken { + location: Default::default(), + value: result, + }))) + } else { + panic!("tcp#read requires a TcpStream on line {}", unsafe { LINE }); + } + } + "tcp#readbin" => { + if args.is_empty() || args.len() > 2 { + panic!( + "tcp#readbin requires at least 1 argument and at most 2 arguments on line {}", + unsafe { LINE } + ); + } + + let stream = runtime.extract_value(&args[0]); + let length = if args.len() == 2 { + runtime.extract_value(&args[1]) + } else { + None + }; + + if let Some(ValueToken::NativeMemory(stream)) = stream { + let stream = stream.memory.lock().unwrap(); + let mut stream = stream + .as_ref() + .downcast_ref::() + .unwrap(); + + let length = if let Some(ValueToken::Number(length)) = length { + length.value as usize + } else { + 1024 + }; + + let mut buffer = vec![0; length]; + let read = stream.read(&mut buffer).unwrap(); + + let result = buffer[..read].to_vec(); + + Some(ExpressionToken::Value(ValueToken::Buffer(BufferToken { + location: Default::default(), + value: Arc::new(Mutex::new(result)), + }))) + } else { + panic!("tcp#read requires a TcpStream on line {}", unsafe { LINE }); + } + } + "tcp#write" => { + if args.len() != 2 { + panic!("tcp#write requires 2 arguments on line {}", unsafe { LINE }); + } + + let stream = runtime.extract_value(&args[0]); + let data = runtime.extract_value(&args[1]); + + if let Some(ValueToken::NativeMemory(stream)) = stream { + let stream = stream.memory.lock().unwrap(); + let mut stream = stream + .as_ref() + .downcast_ref::() + .unwrap(); + + let data = match data { + Some(data) => data.value().to_string(), + _ => panic!( + "tcp#write requires a value as the second argument on line {}", + unsafe { LINE } + ), + }; + + stream.write_all(data.as_bytes()).unwrap(); + + Some(ExpressionToken::Value(ValueToken::Null(NullToken { + location: Default::default(), + }))) + } else { + panic!("tcp#write requires a TcpStream on line {}", unsafe { LINE }); + } + } + _ => None, + } +} diff --git a/src/token/runtime/time.rs b/src/token/runtime/time.rs index b89964d..a7e14db 100644 --- a/src/token/runtime/time.rs +++ b/src/token/runtime/time.rs @@ -7,14 +7,14 @@ use crate::{ }, }; -use std::{rc::Rc, sync::LazyLock}; +use std::sync::{Arc, LazyLock}; pub static FUNCTIONS: LazyLock> = LazyLock::new(|| vec!["time#sleep", "time#now", "time#now_ms"]); pub fn run( name: &str, - args: &[Rc], + args: &[Arc], runtime: &mut Runtime, ) -> Option { match name {