From d0cf7ab58816836a0df10b32cfd6275e78984605 Mon Sep 17 00:00:00 2001 From: Dummi26 Date: Mon, 13 Mar 2023 23:05:27 +0100 Subject: [PATCH] added the concept of references: prefix any (single) type or variable with & to get a reference. This is used for List.{push, insert, pop, remove, get} to avoid copying the list unnecessarily. --- src/parse/parse.rs | 26 +++-- src/script/block.rs | 49 ++++++-- src/script/builtins.rs | 247 ++++++++++++++++++++++++++++++++++++++++- src/script/value.rs | 7 ++ 4 files changed, 309 insertions(+), 20 deletions(-) diff --git a/src/parse/parse.rs b/src/parse/parse.rs index 3a2b0c1..2316d4c 100644 --- a/src/parse/parse.rs +++ b/src/parse/parse.rs @@ -141,11 +141,6 @@ fn parse_statement_adv( SStatementEnum::Tuple(v).into() }) } - Some('$') => { - file.next(); - file.skip_whitespaces(); - Some(SStatementEnum::Variable(file.take_while(|v| !v.is_whitespace()).collect()).into()) - } Some('"') => { file.next(); let mut buf = String::new(); @@ -280,15 +275,22 @@ fn parse_statement_adv( break SStatementEnum::Value(VDataEnum::Bool(false).to()).into() } _ => { + // int, float, var break { if let Ok(v) = start.parse() { SStatementEnum::Value(VDataEnum::Int(v).to()).into() } else if let Ok(v) = start.replace(",", ".").parse() { SStatementEnum::Value(VDataEnum::Float(v).to()).into() } else { - SStatementEnum::Variable(start.to_string()).into() + if start.starts_with('&') { + SStatementEnum::Variable(start[1..].to_string(), true) + .into() + } else { + SStatementEnum::Variable(start.to_string(), false) + .into() + } } - } + }; } } } @@ -378,9 +380,7 @@ fn parse_type(file: &mut File) -> Result { fn parse_type_adv(file: &mut File, in_fn_args: bool) -> Result<(VType, bool), ParseError> { let mut types = vec![]; let mut closed_fn_args = false; - let mut count = 0; loop { - count += 1; let (st, closed_bracket) = parse_single_type_adv(file, in_fn_args)?; types.push(st); if closed_bracket { @@ -414,6 +414,13 @@ fn parse_single_type_adv( let mut closed_bracket_in_fn_args = false; Ok(( match file.next() { + Some('&') => { + let parse_output = parse_single_type_adv(file, in_fn_args)?; + if parse_output.1 { + closed_bracket_in_fn_args = true; + } + VSingleType::Reference(Box::new(parse_output.0)) + } // Tuple or Array Some('[') => { let mut types = vec![]; @@ -439,6 +446,7 @@ fn parse_single_type_adv( loop { match file.peek() { Some(']') => break, + Some('/') => break, _ => (), } match file.next() { diff --git a/src/script/block.rs b/src/script/block.rs index a836efd..7aafde2 100644 --- a/src/script/block.rs +++ b/src/script/block.rs @@ -59,7 +59,7 @@ pub enum SStatementEnum { Value(VData), Tuple(Vec), List(Vec), - Variable(String), + Variable(String, bool), FunctionCall(String, Vec), FunctionDefinition(Option, SFunction), Block(SBlock), @@ -266,9 +266,9 @@ pub mod to_runnable { RStatementEnum::Tuple(w) } } - SStatementEnum::Variable(v) => { + SStatementEnum::Variable(v, is_ref) => { if let Some(var) = linfo.vars.get(v) { - RStatementEnum::Variable(var.0, var.1.clone()) + RStatementEnum::Variable(var.0, var.1.clone(), *is_ref) } else { return Err(ToRunnableError::UseOfUndefinedVariable(v.clone())); } @@ -405,7 +405,7 @@ pub mod to_runnable { } } RStatementEnum::Switch( - RStatementEnum::Variable(switch_on_v.0, switch_on_out).to(), + RStatementEnum::Variable(switch_on_v.0, switch_on_out, false).to(), ncases, ) } else { @@ -554,7 +554,7 @@ pub enum RStatementEnum { Value(VData), Tuple(Vec), List(Vec), - Variable(usize, VType), // Arc> here, because imagine variable in for loop that is used in a different thread -> we need multiple "same" variables + Variable(usize, VType, bool), // Arc> here, because imagine variable in for loop that is used in a different thread -> we need multiple "same" variables FunctionCall(Arc, Vec), BuiltinFunction(BuiltinFunction, Vec), Block(RBlock), @@ -585,7 +585,13 @@ impl RStatementEnum { } VDataEnum::List(out, w).to() } - Self::Variable(v, _) => vars[*v].lock().unwrap().clone(), + Self::Variable(v, _, is_ref) => { + if *is_ref { + VDataEnum::Reference(vars[*v].clone()).to() + } else { + vars[*v].lock().unwrap().clone() + } + } Self::FunctionCall(func, args) => { for (i, input) in func.inputs.iter().enumerate() { *vars[*input].lock().unwrap() = args[i].run(vars); @@ -627,6 +633,7 @@ impl RStatementEnum { vars[*v] = Arc::new(Mutex::new(c)); b.run(&vars); }; + match c.data { VDataEnum::Int(v) => { for i in 0..v { @@ -666,10 +673,28 @@ impl RStatementEnum { pub fn out(&self) -> VType { match self { Self::Value(v) => v.out(), - Self::Tuple(v) | Self::List(v) => { - VSingleType::Tuple(v.iter().map(|v| v.out()).collect()).into() + Self::Tuple(v) => VSingleType::Tuple(v.iter().map(|v| v.out()).collect()).into(), + Self::List(v) => VSingleType::List({ + let mut types = VType { types: vec![] }; + for t in v { + types = types | t.out(); + } + types + }) + .into(), + Self::Variable(_, t, is_ref) => { + if *is_ref { + VType { + types: t + .types + .iter() + .map(|t| VSingleType::Reference(Box::new(t.clone()))) + .collect(), + } + } else { + t.clone() + } } - Self::Variable(_, t) => t.clone(), Self::FunctionCall(f, _) => { eprintln!("Warn: generalizing a functions return type regardless of the inputs. Type-checker might assume this value can have more types than it really can."); f.out_all() @@ -793,6 +818,7 @@ impl Display for VSingleType { Self::List(t) => write!(f, "[{t}]"), Self::Function(args, out) => write!(f, "({args:?}) -> {out}"), Self::Thread(_) => write!(f, "THREAD"), + Self::Reference(r) => write!(f, "&{r}"), } } } @@ -822,7 +848,9 @@ impl Display for SStatementEnum { v.iter().map(|v| format!("{} ", v)).collect::() ) } - SStatementEnum::Variable(v) => write!(f, "{v}"), + SStatementEnum::Variable(v, is_ref) => { + write!(f, "{}{v}", if *is_ref { "&" } else { "" }) + } SStatementEnum::FunctionCall(func, args) => { write!(f, "{func}(")?; for (i, arg) in args.iter().enumerate() { @@ -902,6 +930,7 @@ impl Display for VDataEnum { } Self::Function(v) => write!(f, "{v}"), Self::Thread(..) => write!(f, "THREAD"), + Self::Reference(r) => write!(f, "{}", r.lock().unwrap()), } } } diff --git a/src/script/builtins.rs b/src/script/builtins.rs index b914d85..9291524 100644 --- a/src/script/builtins.rs +++ b/src/script/builtins.rs @@ -39,6 +39,20 @@ pub enum BuiltinFunction { // OS RunCommand, RunCommandGetBytes, + // Math + Add, + Sub, + Mul, + Div, + Mod, + Pow, + // List + Push, + Insert, + Pop, + Remove, + Get, + Len, } impl BuiltinFunction { @@ -62,6 +76,18 @@ impl BuiltinFunction { "string_to_bytes" => Self::StringToBytes, "run_command" => Self::RunCommand, "run_command_get_bytes" => Self::RunCommandGetBytes, + "add" => Self::Add, + "sub" => Self::Sub, + "mul" => Self::Mul, + "div" => Self::Div, + "mod" => Self::Mod, + "pow" => Self::Pow, + "push" => Self::Push, + "insert" => Self::Insert, + "pop" => Self::Pop, + "remove" => Self::Remove, + "get" => Self::Get, + "len" => Self::Len, _ => return None, }) } @@ -74,7 +100,7 @@ impl BuiltinFunction { // String Self::ToString | Self::Format => VSingleType::String.into(), // ! - Self::Run | Self::Thread | Self::Await => { + Self::Run | Self::Thread | Self::Await | Self::Pop | Self::Remove | Self::Get => { VType { types: vec![] } // TODO! // unreachable!("this has to be implemented somewhere else!") } @@ -136,6 +162,11 @@ impl BuiltinFunction { ]), ], }, + Self::Add | Self::Sub | Self::Mul | Self::Div | Self::Mod | Self::Pow => VType { + types: vec![VSingleType::Int, VSingleType::Float], + }, + Self::Push | Self::Insert => VSingleType::Tuple(vec![]).into(), + Self::Len => VSingleType::Int.into(), } } pub fn run(&self, args: &Vec, vars: &Vec>>) -> VData { @@ -443,6 +474,220 @@ impl BuiltinFunction { unreachable!("run_command not 1 arg") } } + Self::Add => { + if args.len() == 2 { + match (args[0].run(vars).data, args[1].run(vars).data) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a + b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float(a as f64 + b).to() + } + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float(a + b as f64).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a + b).to(), + _ => unreachable!("add: not a number"), + } + } else { + unreachable!("add: not 2 args") + } + } + Self::Sub => { + if args.len() == 2 { + match (args[0].run(vars).data, args[1].run(vars).data) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a - b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float(a as f64 - b).to() + } + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float(a - b as f64).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a - b).to(), + _ => unreachable!("sub: not a number"), + } + } else { + unreachable!("sub: not 2 args") + } + } + Self::Mul => { + if args.len() == 2 { + match (args[0].run(vars).data, args[1].run(vars).data) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a * b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float(a as f64 * b).to() + } + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float(a * b as f64).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a * b).to(), + _ => unreachable!("mul: not a number"), + } + } else { + unreachable!("mul: not 2 args") + } + } + Self::Div => { + if args.len() == 2 { + match (args[0].run(vars).data, args[1].run(vars).data) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a / b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float(a as f64 / b).to() + } + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float(a / b as f64).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a / b).to(), + _ => unreachable!("div: not a number"), + } + } else { + unreachable!("div: not 2 args") + } + } + Self::Mod => { + if args.len() == 2 { + match (args[0].run(vars).data, args[1].run(vars).data) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a % b).to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float(a as f64 % b).to() + } + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float(a % b as f64).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Float(a % b).to(), + _ => unreachable!("mod: not a number"), + } + } else { + unreachable!("mod: not 2 args") + } + } + Self::Pow => { + if args.len() == 2 { + match (args[0].run(vars).data, args[1].run(vars).data) { + (VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(if b == 0 { + 1 + } else if b > 0 { + a.pow(b as _) + } else { + 0 + }) + .to(), + (VDataEnum::Int(a), VDataEnum::Float(b)) => { + VDataEnum::Float((a as f64).powf(b)).to() + } + (VDataEnum::Float(a), VDataEnum::Int(b)) => { + VDataEnum::Float(a.powi(b as _)).to() + } + (VDataEnum::Float(a), VDataEnum::Float(b)) => { + VDataEnum::Float(a.powf(b)).to() + } + _ => unreachable!("pow: not a number"), + } + } else { + unreachable!("pow: not 2 args") + } + } + Self::Push => { + if args.len() == 2 { + if let VDataEnum::Reference(v) = args[0].run(vars).data { + if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data { + v.push(args[1].run(vars)); + } + VDataEnum::Tuple(vec![]).to() + } else { + unreachable!("push: not a reference") + } + } else { + unreachable!("push: not 2 args") + } + } + Self::Insert => { + if args.len() == 3 { + if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = + (args[0].run(vars).data, args[1].run(vars).data) + { + if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data { + v.insert(i as _, args[2].run(vars)); + } + VDataEnum::Tuple(vec![]).to() + } else { + unreachable!("insert: not a reference and index") + } + } else { + unreachable!("insert: not 3 args") + } + } + Self::Pop => { + if args.len() == 1 { + if let VDataEnum::Reference(v) = args[0].run(vars).data { + if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data { + v.pop().unwrap_or_else(|| VDataEnum::Tuple(vec![]).to()) + } else { + unreachable!("pop: not a list") + } + } else { + unreachable!("pop: not a reference") + } + } else { + unreachable!("pop: not 1 arg") + } + } + Self::Remove => { + if args.len() == 2 { + if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = + (args[0].run(vars).data, args[1].run(vars).data) + { + if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data { + if v.len() > i as _ && i >= 0 { + v.remove(i as _) + } else { + VDataEnum::Tuple(vec![]).to() + } + } else { + unreachable!("remove: not a list") + } + } else { + unreachable!("remove: not a reference and index") + } + } else { + unreachable!("remove: not 2 args") + } + } + Self::Get => { + if args.len() == 2 { + if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = + (args[0].run(vars).data, args[1].run(vars).data) + { + if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data { + if i >= 0 { + match v.get(i as usize) { + Some(v) => v.clone(), + None => VDataEnum::Tuple(vec![]).to(), + } + } else { + VDataEnum::Tuple(vec![]).to() + } + } else { + unreachable!("get: not a list") + } + } else { + unreachable!("get: not a reference and index") + } + } else { + unreachable!("get: not 2 args") + } + } + Self::Len => { + if args.len() == 1 { + VDataEnum::Int(match args[0].run(vars).data { + VDataEnum::String(v) => v.len(), + VDataEnum::Tuple(v) => v.len(), + VDataEnum::List(_, v) => v.len(), + _ => unreachable!("len: invalid type"), + } as _) + .to() + } else { + unreachable!("len: not 1 arg") + } + } } } } diff --git a/src/script/value.rs b/src/script/value.rs index 7109c30..19791b2 100644 --- a/src/script/value.rs +++ b/src/script/value.rs @@ -32,6 +32,7 @@ impl VData { f.out_all() }), VDataEnum::Thread(_, o) => VSingleType::Thread(o.clone()), + VDataEnum::Reference(r) => r.lock().unwrap().out_single(), } } pub fn get(&self, i: usize) -> Option { @@ -49,6 +50,7 @@ pub enum VDataEnum { List(VType, Vec), Function(RFunction), Thread(VDataThread, VType), + Reference(Arc>), } #[derive(Clone)] @@ -136,6 +138,7 @@ impl VDataEnum { None => None, }, Self::Tuple(v) | Self::List(_, v) => v.get(i).cloned(), + Self::Reference(r) => r.lock().unwrap().get(i), } } } @@ -147,6 +150,7 @@ impl VSingleType { Self::String => Some(VSingleType::String.into()), Self::Tuple(t) => t.get(i).cloned(), Self::List(t) => Some(t.clone()), + Self::Reference(r) => r.get(i), } } } @@ -209,6 +213,7 @@ pub enum VSingleType { List(VType), Function(Vec, VType), Thread(VType), + Reference(Box), } impl VSingleType { pub fn inner_types(&self) -> Vec { @@ -256,6 +261,8 @@ impl VSingleType { (Self::Function(..), _) => false, (Self::Thread(a), Self::Thread(b)) => a.fits_in(b).is_empty(), (Self::Thread(..), _) => false, + (Self::Reference(r), Self::Reference(b)) => r.fits_in(b), + (Self::Reference(_), _) => false, } } }