diff --git a/README.md b/README.md index 15d64fa..8971e9a 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ WRITE text cout | `TO_BOOL` | `source_var`, `result_var` | Скопировать строку `source_var` (тип переменной: `string`/`integer`) в `result_var`, переводя в `bool` | | `TO_FLOAT` | `source_var`, `result_var` | Скопировать строку `source_var` в `result_var`, переводя в `float` | | `GET_SYMBOL` | `str_var`, `index_var`, `result_var` | Скопировать символ из строки `str_var` по индексу `index_var` и записать в `result_var` | +| `GET_ITEM` | `list_var`, `index_var`, `result_var` | Скопировать предмет из списка `str_var` по индексу `index_var` и записать в `result_var` | +| `GET_VALUE` | `map_var`, `key_var`, `result_var` | Скопировать предмет из мапы `map_var` по ключу `key_var` и записать в `result_var` | | `ADD_INT` | `int_var1`, `int_var2` | Прибавить к числу `int_var1` значение `int_var2` | | `ADD_FLOAT` | `float_var1`, `float_var2` | Прибавить к числу `float_var1` значение `float_var2` | | `ADD_STR` | `str_var`, `value_var` | Прибавить к строке `str_var` значение `value_var` (может быть типа `string/char/list[char]`) | diff --git a/src/lib.rs b/src/lib.rs index 190df32..fa23640 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,15 @@ use std::{ char::EscapeDebug, collections::HashMap, + env::Vars, error::Error, fmt::Display, hash::Hash, io::{Read, Write}, ptr::hash, sync::{Arc, Mutex}, + thread, + time::Duration, }; #[derive(Debug)] @@ -17,6 +20,9 @@ pub enum ScriptError { CommandArgsInvalidError(usize), UnknownVarError, TypeMismatchError, + VarNotInitedError, + StringUTF8Error, + VarInitedError, } impl Display for ScriptError { @@ -130,6 +136,60 @@ impl Variable { } } + pub fn to_string(&self) -> Result { + Ok(match self.clone() { + Variable::Bool(_, Some(v)) => if v { "true" } else { "false" }.to_string(), + Variable::String(_, Some(v)) => v, + Variable::Integer(_, Some(v)) => v.to_string(), + Variable::Float(_, Some(v)) => v.to_string(), + Variable::Char(_, Some(v)) => { + String::from_utf8(vec![v]).or(Err(ScriptError::StringUTF8Error))? + } + Variable::List(VarType::Char, Some(v)) => { + let mut bytes = Vec::new(); + for ele in v { + bytes.push(ele.as_char()?); + } + String::from_utf8(bytes).or(Err(ScriptError::StringUTF8Error))? + } + Variable::List(_, Some(v)) => { + let mut text = String::from("["); + for i in 0..v.len() { + let item = &v[i]; + text.push_str(&item.to_string()?); + if i != v.len() - 1 { + text.push_str(", "); + } + } + text.push(']'); + text + } + Variable::Map(_, Some(v)) => { + let mut text = String::from("{"); + let mut i = 0; + for (key, value) in &v { + text.push_str(&key.to_string()?); + text.push_str(": "); + text.push_str(&value.to_string()?); + if i != v.len() - 1 { + text.push_str(", "); + } + i += 1; + } + text.push('}'); + text + } + Variable::Optional(_, Some(v)) => match v { + Some(v) => format!("({})", v.to_string()?), + None => String::from("none"), + }, + Variable::InStream(_, Some(_)) => String::from("IN_STREAM"), + Variable::OutStream(_, Some(_)) => String::from("OUT_STREAM"), + Variable::Null(_) => String::from("null"), + _ => return Err(ScriptError::VarNotInitedError), + }) + } + pub fn is_null(&self) -> bool { if let Variable::Null(_) = self { true @@ -629,6 +689,18 @@ pub enum CommandType { /// Параметры: `str_var`, `index_var`, `result_var` GetSymbol, + /// Скопировать предмет из списка `str_var` по индексу `index_var` и записать в `result_var` + /// + /// Название: GET_ITEM \ + /// Параметры: `list_var`, `index_var`, `result_var` + GetItem, + + /// Скопировать предмет из мапы `map_var` по ключу `key_var` и записать в `result_var` + /// + /// Название: GET_VALUE \ + /// Параметры: `map_var`, key_var`, `result_var` + GetValue, + /// Прибавить к числу `var` значение `other_var` /// /// Название: ADD_INT \ @@ -789,6 +861,12 @@ pub enum CommandType { /// Параметры: `var`, `other_var`, `result_var` Or, + /// Если `var` равен `true`, то результат `false`, иначе `true`, записать результат в `result_var` + /// + /// Название: NOT \ + /// Параметры: `var`, `result_var` + Not, + /// Если `var` равен `true` то вызвать функцию `func` /// /// Название: IF \ @@ -879,6 +957,8 @@ impl CommandType { "TO_CHAR" => Ok(CommandType::ToChar), "TO_BOOL" => Ok(CommandType::ToBool), "GET_SYMBOL" => Ok(CommandType::GetSymbol), + "GET_ITEM" => Ok(CommandType::GetItem), + "GET_VALUE" => Ok(CommandType::GetValue), "ADD_INT" => Ok(CommandType::AddInt), "ADD_FLOAT" => Ok(CommandType::AddFloat), "ADD_STR" => Ok(CommandType::AddStr), @@ -910,6 +990,7 @@ impl CommandType { "LESS" => Ok(CommandType::Less), "AND" => Ok(CommandType::And), "OR" => Ok(CommandType::Or), + "NOT" => Ok(CommandType::Not), "IF" => Ok(CommandType::If), "HAS_STR" => Ok(CommandType::HasStr), "HAS_ITEM" => Ok(CommandType::HasItem), @@ -1108,18 +1189,21 @@ impl RunningScript { VarType::String, ), true, + true, &mut HashMap::new(), )?; self.set_var( String::from("cout"), Variable::from_out_stream(Some(Arc::new(Mutex::new(cout)))), true, + true, &mut HashMap::new(), )?; self.set_var( String::from("cin"), Variable::from_in_stream(Some(Arc::new(Mutex::new(cin)))), true, + true, &mut HashMap::new(), )?; @@ -1236,17 +1320,35 @@ impl RunningScript { Err(ScriptError::UnknownVarError) } - pub fn set_var( + fn set_var( &mut self, name: String, value: Variable, global: bool, + init: bool, locals: &mut HashMap, ) -> Result<(), ScriptError> { + let var_type = value.get_type(); let mut var: Option<&mut Variable> = None; - let parts: Vec<&str> = name.split('.').collect(); + let parts: Vec<&str> = (&name).split('.').collect(); - let global = global || (self.variables.contains_key(&name) && !locals.contains_key(&name)); + match self.get_var(name.clone(), locals) { + Ok(i) => { + if init { + return Err(ScriptError::VarInitedError); + } else if i.get_type() != var_type { + return Err(ScriptError::TypeMismatchError); + } + } + Err(_) => { + if !init { + return Err(ScriptError::UnknownVarError); + } + } + } + + let global = + global || (self.variables.contains_key(parts[0]) && !locals.contains_key(parts[0])); if parts.len() == 1 { if global { @@ -1331,419 +1433,983 @@ impl RunningScript { None } + fn exec_command( + &mut self, + command: Command, + global: bool, + locals: &mut HashMap, + temp_vars: &mut Vec, + ) -> Result<(), ScriptError> { + match command.command_type { + CommandType::InitVar => { + let type_var = command.args[0].clone(); + let type_var = VarType::from_name(&type_var)?; + let name_var = command.args[1].clone(); + + self.set_var( + name_var, + Variable::empty_var(type_var)?, + global, + true, + locals, + )?; + } + CommandType::SetVar => { + let name_var = command.args[0].clone(); + let value_var = command.args[1..].join(" "); + + let type_var = self + .get_var(name_var.clone(), &mut locals.clone())? + .get_type(); + let var = Variable::parse_var(type_var, value_var)?; + + self.set_var(name_var, var, global, false, locals)?; + } + CommandType::TempVar => { + let type_var = command.args[0].clone(); + let name_var = command.args[1].clone(); + let value_var = command.args[2..].join(" "); + + self.set_var( + name_var.clone(), + Variable::parse_var(VarType::from_name(&type_var)?, value_var)?, + global, + true, + locals, + )?; + + temp_vars.push(name_var); + } + CommandType::MoveVar => { + let source_var = command.args[0].clone(); + let target_var = command.args[1].clone(); + + let var = self.get_var(source_var.clone(), locals)?; + + self.set_var(target_var, var, global, false, locals)?; + self.drop_var(source_var, locals)?; + } + CommandType::CopyVar => { + let source_var = command.args[0].clone(); + let target_var = command.args[1].clone(); + + let var = self.get_var(source_var.clone(), locals)?; + + self.set_var(target_var, var, global, false, locals)?; + } + CommandType::DropVar => { + let name_var = command.args[0].clone(); + + self.drop_var(name_var, locals)?; + } + CommandType::HasVar => { + let name_var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let result = self.get_var(name_var, locals).is_ok(); + + self.set_var( + result_var, + Variable::from_bool(Some(result)), + global, + false, + locals, + )?; + } + CommandType::AddStr => { + let var_name = command.args[0].clone(); + let other_var = command.args[1].clone(); + + let other_var = self.get_var(other_var.clone(), locals)?; + let other_var: String = if let Variable::List(VarType::Char, Some(list)) = other_var + { + let mut bytes = Vec::new(); + for ele in list { + bytes.push(ele.as_char()?); + } + String::from_utf8(bytes).or(Err(ScriptError::StringUTF8Error))? + } else if let Variable::String(_, Some(string)) = other_var { + string + } else if let Variable::Char(_, Some(value)) = other_var { + String::from_utf8(vec![value]).or(Err(ScriptError::StringUTF8Error))? + } else { + return Err(ScriptError::TypeMismatchError); + }; + + let var = self.get_var(var_name.clone(), locals)?.as_str()?; + + self.set_var( + var_name, + Variable::from_str(Some(var + &other_var)), + global, + false, + locals, + )?; + } + CommandType::Write => { + let name_var = command.args[0].clone(); + let stream_var = command.args[1].clone(); + + let text = self.get_var(name_var.clone(), locals)?; + let text: Vec = if let Variable::List(VarType::Char, Some(list)) = text { + let mut bytes = Vec::new(); + for ele in list { + bytes.push(ele.as_char()?); + } + bytes + } else if let Variable::String(_, Some(string)) = text { + string.as_bytes().to_vec() + } else if let Variable::Char(_, Some(value)) = text { + vec![value] + } else { + return Err(ScriptError::TypeMismatchError); + }; + + let stream = self.get_var(stream_var.clone(), locals)?.as_out_stream()?; + stream.lock().unwrap().write_all(&text).unwrap(); + } + CommandType::UseFunc => { + let func_name = command.args[0].clone(); + let result_name = command.args[1].clone(); + let args_names = command.args[2..].to_vec(); + + let func = self.get_function(func_name).unwrap(); + + let mut args = Vec::new(); + for name in args_names { + args.push(self.get_var(name, locals)?); + } + + self.exec_function(func, result_name, args)?; + } + CommandType::Return => { + return Ok(()); + } + CommandType::For => { + let func_name = command.args[0].clone(); + let start_index = self.get_var(command.args[1].clone(), locals)?.as_int()?; + let end_index = self.get_var(command.args[2].clone(), locals)?.as_int()?; + + let func = self.get_function(func_name).unwrap(); + + for index in start_index..=end_index { + self.exec_function( + func.clone(), + "null".to_string(), + vec![Variable::from_int(Some(index))], + )?; + } + } + CommandType::ToString => { + let source_var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let source_var = self.get_var(source_var, locals)?; + + let result = source_var.to_string()?; + + self.set_var( + result_var, + Variable::from_str(Some(result)), + global, + false, + locals, + )?; + } + CommandType::ToChars => { + let source_var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let source_var = self.get_var(source_var, locals)?; + + let result = source_var + .as_str()? + .as_bytes() + .iter() + .map(|f| Variable::from_char(Some(*f))) + .collect(); + let result = + Variable::from_list(Some(result), VarType::List(Box::new(VarType::Char))); + + self.set_var(result_var, result, global, false, locals)?; + } + CommandType::ToInteger => { + let source_var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let source_var = self.get_var(source_var, locals)?; + + let result = source_var + .as_str()? + .parse::() + .or(Err(ScriptError::ParseVarError))?; + let result = Variable::from_int(Some(result)); + + self.set_var(result_var, result, global, false, locals)?; + } + CommandType::ToFloat => { + let source_var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let source_var = self.get_var(source_var, locals)?; + + let result = source_var + .as_str()? + .parse::() + .or(Err(ScriptError::ParseVarError))?; + let result = Variable::from_float(Some(result)); + + self.set_var(result_var, result, global, false, locals)?; + } + CommandType::ToBool => { + let source_var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let source_var = self.get_var(source_var, locals)?; + + let result = if let Variable::List(_, Some(value)) = source_var { + !value.is_empty() + } else if let Variable::String(_, Some(value)) = source_var { + value == "true" || value == "1" + } else if let Variable::Char(_, Some(value)) = source_var { + value != 0 + } else if let Variable::Integer(_, Some(value)) = source_var { + value != 0 + } else if let Variable::Float(_, Some(value)) = source_var { + value != 0.0 + } else if let Variable::Bool(_, Some(value)) = source_var { + value + } else if let Variable::Map(_, Some(value)) = source_var { + !value.is_empty() + } else if let Variable::Optional(_, Some(value)) = source_var { + value.is_some() + } else if let Variable::Null(_) = source_var { + false + } else if let Variable::OutStream(_, Some(_)) = source_var { + true + } else if let Variable::InStream(_, Some(_)) = source_var { + true + } else { + false + }; + + self.set_var( + result_var, + Variable::from_bool(Some(result)), + global, + false, + locals, + )?; + } + CommandType::ToChar => { + let source_var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let source_var = self.get_var(source_var, locals)?; + + let result = if let Variable::String(_, Some(value)) = source_var { + value.as_bytes()[0] + } else if let Variable::Char(_, Some(value)) = source_var { + value + } else if let Variable::Integer(_, Some(value)) = source_var { + value as u8 + } else { + return Err(ScriptError::TypeMismatchError); + }; + + self.set_var( + result_var, + Variable::from_char(Some(result)), + global, + false, + locals, + )?; + } + CommandType::GetSymbol => { + let str_var = command.args[0].clone(); + let index_var = command.args[1].clone(); + let result_var = command.args[2].clone(); + + let str_var = self.get_var(str_var, locals)?; + let index_var = self.get_var(index_var, locals)?; + + let index = index_var.as_int()?; + + let result = if let Variable::String(_, Some(value)) = str_var { + value.as_bytes()[index as usize] + } else { + return Err(ScriptError::TypeMismatchError); + }; + + self.set_var( + result_var, + Variable::from_char(Some(result)), + global, + false, + locals, + )?; + } + CommandType::GetItem => { + let list_var = command.args[0].clone(); + let index_var = command.args[1].clone(); + let result_var = command.args[2].clone(); + + let list_var = self.get_var(list_var, locals)?; + let index_var = self.get_var(index_var, locals)?; + + let index = index_var.as_int()?; + + let result = if let Variable::List(_, Some(value)) = list_var { + value[index as usize].clone() + } else { + return Err(ScriptError::TypeMismatchError); + }; + + self.set_var(result_var, result, global, false, locals)?; + } + CommandType::GetValue => { + let map_var = command.args[0].clone(); + let key_var = command.args[1].clone(); + let result_var = command.args[2].clone(); + + let map_var = self.get_var(map_var, locals)?; + let key_var = self.get_var(key_var, locals)?; + + let result = if let Variable::Map(_, Some(value)) = map_var { + value[&key_var].clone() + } else { + return Err(ScriptError::TypeMismatchError); + }; + + self.set_var(result_var, result, global, false, locals)?; + } + CommandType::ListSize => { + let list_var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let list_var = self.get_var(list_var, locals)?; + let list_size = list_var.as_list()?.len(); + + self.set_var( + result_var, + Variable::from_int(Some(list_size as isize)), + global, + false, + locals, + )?; + } + CommandType::MapSize => { + let map_var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let map_var = self.get_var(map_var, locals)?; + let map_size = map_var.as_list()?.len(); + + self.set_var( + result_var, + Variable::from_int(Some(map_size as isize)), + global, + false, + locals, + )?; + } + CommandType::StringSize => { + let string_var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let string_var = self.get_var(string_var, locals)?; + let string_size = string_var.as_list()?.len(); + + self.set_var( + result_var, + Variable::from_int(Some(string_size as isize)), + global, + false, + locals, + )?; + } + CommandType::ForMap => { + let func_name = command.args[0].clone(); + let map_var = command.args[1].clone(); + + let map_var = self.get_var(map_var, locals)?; + let map_var = map_var.as_map()?; + + let func = self.get_function(func_name).unwrap(); + + for (k, v) in map_var { + self.exec_function(func.clone(), "null".to_string(), vec![k, v])?; + } + } + CommandType::ForList => { + let func_name = command.args[0].clone(); + let list_var = command.args[1].clone(); + + let list_var = self.get_var(list_var, locals)?; + let list_var = list_var.as_list()?; + + let func = self.get_function(func_name).unwrap(); + + for i in list_var { + self.exec_function(func.clone(), "null".to_string(), vec![i])?; + } + } + CommandType::ForString => { + let func_name = command.args[0].clone(); + let string_var = command.args[1].clone(); + + let string_var = self.get_var(string_var, locals)?; + let string_var = string_var.as_str()?; + + let func = self.get_function(func_name).unwrap(); + + for c in string_var.as_bytes() { + self.exec_function( + func.clone(), + "null".to_string(), + vec![Variable::from_char(Some(*c))], + )?; + } + } + CommandType::While => { + let func_name = command.args[0].clone(); + + let func = self.get_function(func_name).unwrap(); + + self.set_var( + "while".to_string(), + Variable::from_bool(Some(true)), + global, + false, + locals, + )?; + + while self.get_var("while".to_string(), locals)?.as_bool()? { + self.exec_function(func.clone(), "while".to_string(), vec![])?; + } + } + CommandType::Equals => { + let var = command.args[0].clone(); + let other_var = command.args[1].clone(); + let result_var = command.args[2].clone(); + + let var = self.get_var(var, locals)?; + let other_var = self.get_var(other_var, locals)?; + + self.set_var( + result_var, + Variable::from_bool(Some(var == other_var)), + global, + false, + locals, + )?; + } + CommandType::More => { + let var = command.args[0].clone(); + let other_var = command.args[1].clone(); + let result_var = command.args[2].clone(); + + let var = self.get_var(var, locals)?; + let other_var = self.get_var(other_var, locals)?; + + let result = if let Variable::Float(_, Some(v1)) = var { + if let Variable::Float(_, Some(v2)) = other_var { + v1 > v2 + } else if let Variable::Integer(_, Some(v2)) = other_var { + v1 > v2 as f64 + } else if let Variable::Char(_, Some(v2)) = other_var { + v1 > v2 as f64 + } else { + return Err(ScriptError::TypeMismatchError); + } + } else if let Variable::Integer(_, Some(v1)) = var { + if let Variable::Float(_, Some(v2)) = other_var { + v1 as f64 > v2 + } else if let Variable::Integer(_, Some(v2)) = other_var { + v1 > v2 + } else if let Variable::Char(_, Some(v2)) = other_var { + v1 > v2 as isize + } else { + return Err(ScriptError::TypeMismatchError); + } + } else if let Variable::Char(_, Some(v1)) = var { + if let Variable::Float(_, Some(v2)) = other_var { + v1 as f64 > v2 + } else if let Variable::Integer(_, Some(v2)) = other_var { + v1 as isize > v2 + } else if let Variable::Char(_, Some(v2)) = other_var { + v1 > v2 + } else { + return Err(ScriptError::TypeMismatchError); + } + } else { + return Err(ScriptError::TypeMismatchError); + }; + + self.set_var( + result_var, + Variable::from_bool(Some(result)), + global, + false, + locals, + )?; + } + CommandType::Less => { + let var = command.args[0].clone(); + let other_var = command.args[1].clone(); + let result_var = command.args[2].clone(); + + let var = self.get_var(var, locals)?; + let other_var = self.get_var(other_var, locals)?; + + let result = if let Variable::Float(_, Some(v1)) = var { + if let Variable::Float(_, Some(v2)) = other_var { + v1 < v2 + } else if let Variable::Integer(_, Some(v2)) = other_var { + v1 < v2 as f64 + } else if let Variable::Char(_, Some(v2)) = other_var { + v1 < v2 as f64 + } else { + return Err(ScriptError::TypeMismatchError); + } + } else if let Variable::Integer(_, Some(v1)) = var { + if let Variable::Float(_, Some(v2)) = other_var { + (v1 as f64) < v2 + } else if let Variable::Integer(_, Some(v2)) = other_var { + v1 < v2 + } else if let Variable::Char(_, Some(v2)) = other_var { + v1 < v2 as isize + } else { + return Err(ScriptError::TypeMismatchError); + } + } else if let Variable::Char(_, Some(v1)) = var { + if let Variable::Float(_, Some(v2)) = other_var { + (v1 as f64) < v2 + } else if let Variable::Integer(_, Some(v2)) = other_var { + (v1 as isize) < v2 + } else if let Variable::Char(_, Some(v2)) = other_var { + v1 < v2 + } else { + return Err(ScriptError::TypeMismatchError); + } + } else { + return Err(ScriptError::TypeMismatchError); + }; + + self.set_var( + result_var, + Variable::from_bool(Some(result)), + global, + false, + locals, + )?; + } + CommandType::And => { + let var = command.args[0].clone(); + let other_var = command.args[1].clone(); + let result_var = command.args[2].clone(); + + let var = self.get_var(var, locals)?.as_bool()?; + let other_var = self.get_var(other_var, locals)?.as_bool()?; + + self.set_var( + result_var, + Variable::from_bool(Some(var && other_var)), + global, + false, + locals, + )?; + } + CommandType::Or => { + let var = command.args[0].clone(); + let other_var = command.args[1].clone(); + let result_var = command.args[2].clone(); + + let var = self.get_var(var, locals)?.as_bool()?; + let other_var = self.get_var(other_var, locals)?.as_bool()?; + + self.set_var( + result_var, + Variable::from_bool(Some(var || other_var)), + global, + false, + locals, + )?; + } + CommandType::Not => { + let var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let var = self.get_var(var, locals)?.as_bool()?; + + self.set_var( + result_var, + Variable::from_bool(Some(!var)), + global, + false, + locals, + )?; + } + CommandType::If => { + let bool_var = command.args[0].clone(); + let func_name = command.args[1].clone(); + + let func = self.get_function(func_name).unwrap(); + + let bool_var = self.get_var(bool_var, locals)?.as_bool()?; + + if bool_var { + self.exec_function(func, "null".to_string(), vec![])?; + } + } + CommandType::HasStr => { + let string_var = command.args[0].clone(); + let substring = command.args[1].clone(); + let result_var = command.args[2].clone(); + + let string_var = self.get_var(string_var, locals)?.as_str()?; + let substring = self.get_var(substring, locals)?.as_str()?; + + self.set_var( + result_var, + Variable::from_bool(Some(string_var.contains(&substring))), + global, + false, + locals, + )?; + } + CommandType::HasItem => { + let list_var = command.args[0].clone(); + let item_var = command.args[1].clone(); + let result_var = command.args[2].clone(); + + let list_var = self.get_var(list_var, locals)?.as_list()?; + let item_var = self.get_var(item_var, locals)?; + + self.set_var( + result_var, + Variable::from_bool(Some(list_var.contains(&item_var))), + global, + false, + locals, + )?; + } + CommandType::HasEntry => { + let map_var = command.args[0].clone(); + let key_var = command.args[1].clone(); + let value_var = command.args[2].clone(); + let result_var = command.args[3].clone(); + + let map_var = self.get_var(map_var, locals)?.as_map()?; + let key_var = self.get_var(key_var, locals)?; + let value_var = self.get_var(value_var, locals)?; + + let mut has = false; + + for (k, v) in map_var { + if k == key_var && v == value_var { + has = true; + break; + } + } + + self.set_var( + result_var, + Variable::from_bool(Some(has)), + global, + false, + locals, + )?; + } + CommandType::HasKey => { + let map_var = command.args[0].clone(); + let key_var = command.args[1].clone(); + let result_var = command.args[2].clone(); + + let map_var = self.get_var(map_var, locals)?.as_map()?; + let key_var = self.get_var(key_var, locals)?; + + let mut has = false; + + for (k, _) in map_var { + if k == key_var { + has = true; + break; + } + } + + self.set_var( + result_var, + Variable::from_bool(Some(has)), + global, + false, + locals, + )?; + } + CommandType::HasValue => { + let map_var = command.args[0].clone(); + let value_var = command.args[1].clone(); + let result_var = command.args[2].clone(); + + let map_var = self.get_var(map_var, locals)?.as_map()?; + let value_var = self.get_var(value_var, locals)?; + + let mut has = false; + + for (_, v) in map_var { + if v == value_var { + has = true; + break; + } + } + + self.set_var( + result_var, + Variable::from_bool(Some(has)), + global, + false, + locals, + )?; + } + CommandType::HasOptional => { + let optional_var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let optional_var = self.get_var(optional_var, locals)?.as_option()?; + + self.set_var( + result_var, + Variable::from_bool(Some(optional_var.is_some())), + global, + false, + locals, + )?; + } + CommandType::UnpackOptional => { + let optional_var = command.args[0].clone(); + let result_var = command.args[1].clone(); + + let optional_var = self.get_var(optional_var, locals)?.as_option()?; + + self.set_var( + result_var, + optional_var + .ok_or(ScriptError::ParseVarError)? + .as_mut() + .clone(), + global, + false, + locals, + )?; + } + CommandType::Sleep => { + let time_var = command.args[0].clone(); + + let time_var = match self.get_var(time_var, locals)? { + Variable::Integer(_, Some(v)) => Duration::from_millis(v as u64), + Variable::Float(_, Some(v)) => Duration::from_millis(v as u64), + _ => { + return Err(ScriptError::TypeMismatchError); + } + }; + + thread::sleep(time_var); + } + CommandType::AddInt => { + let var_name = command.args[0].clone(); + let other_var = command.args[1].clone(); + + let other_var = self.get_var(other_var, locals)?.as_int()?; + let var = self.get_var(var_name.clone(), locals)?.as_int()?; + + self.set_var( + var_name, + Variable::from_int(Some(var + other_var)), + global, + false, + locals, + )?; + } + CommandType::AddFloat => { + let var_name = command.args[0].clone(); + let other_var = command.args[1].clone(); + + let other_var = self.get_var(other_var, locals)?.as_float()?; + let var = self.get_var(var_name.clone(), locals)?.as_float()?; + + self.set_var( + var_name, + Variable::from_float(Some(var + other_var)), + global, + false, + locals, + )?; + } + CommandType::SubStr => { + let str_var_name = command.args[0].clone(); + let start_index = command.args[1].clone(); + let end_index = command.args[1].clone(); + + let str_var = self.get_var(str_var_name.clone(), locals)?.as_str()?; + let start_index = self.get_var(start_index, locals)?.as_int()? as usize; + let end_index = self.get_var(end_index, locals)?.as_int()? as usize; + + self.set_var( + str_var_name, + Variable::from_str(Some(str_var[start_index..end_index].to_string())), + global, + false, + locals, + )?; + } + CommandType::SubList => { + let list_var_name = command.args[0].clone(); + let start_index = command.args[1].clone(); + let end_index = command.args[1].clone(); + + let list_var = self.get_var(list_var_name.clone(), locals)?; + let start_index = self.get_var(start_index, locals)?.as_int()? as usize; + let end_index = self.get_var(end_index, locals)?.as_int()? as usize; + + self.set_var( + list_var_name, + Variable::from_list( + Some(list_var.as_list()?[start_index..end_index].to_vec()), + list_var.get_type(), + ), + global, + false, + locals, + )?; + } + CommandType::Read => { + let name_var = command.args[0].clone(); + let size_var = command.args[1].clone(); + let stream_var = command.args[2].clone(); + + let var = self.get_var(name_var.clone(), locals)?; + let size_var = self.get_var(size_var.clone(), locals)?.as_int()?; + let stream = self.get_var(stream_var.clone(), locals)?.as_in_stream()?; + + let mut buffer: Vec = Vec::with_capacity(size_var as usize); + stream.lock().unwrap().read_exact(&mut buffer).unwrap(); + + self.set_var( + name_var, + match var { + Variable::List(VarType::Char, _) => Variable::from_list( + Some( + buffer + .iter() + .map(|f| Variable::from_char(Some(*f))) + .collect(), + ), + VarType::List(Box::new(VarType::Char)), + ), + Variable::String(_, _) => Variable::from_str(Some( + String::from_utf8(buffer).or(Err(ScriptError::StringUTF8Error))?, + )), + _ => { + return Err(ScriptError::TypeMismatchError); + } + }, + global, + false, + locals, + )?; + } + CommandType::ReadAll => { + let name_var = command.args[0].clone(); + let stream_var = command.args[1].clone(); + + let var = self.get_var(name_var.clone(), locals)?; + let stream = self.get_var(stream_var.clone(), locals)?.as_in_stream()?; + + let mut buffer: Vec = Vec::new(); + stream.lock().unwrap().read_to_end(&mut buffer).unwrap(); + + self.set_var( + name_var, + match var { + Variable::List(VarType::Char, _) => Variable::from_list( + Some( + buffer + .iter() + .map(|f| Variable::from_char(Some(*f))) + .collect(), + ), + VarType::List(Box::new(VarType::Char)), + ), + Variable::String(_, _) => Variable::from_str(Some( + String::from_utf8(buffer).or(Err(ScriptError::StringUTF8Error))?, + )), + _ => { + return Err(ScriptError::TypeMismatchError); + } + }, + global, + false, + locals, + )?; + } + CommandType::OpenFileIn => { + let path_var = command.args[0].clone(); + let stream_var = command.args[1].clone(); + + // TODO: write logic + } + CommandType::OpenFileOut => { + let path_var = command.args[0].clone(); + let stream_var = command.args[1].clone(); + + // TODO: write logic + } + CommandType::OpenTcpConnection => { + let addr_var = command.args[0].clone(); + let port_var = command.args[1].clone(); + let in_stream = command.args[2].clone(); + let out_stream = command.args[3].clone(); + + // TODO: write logic + } + CommandType::OpenTcpListener => { + let addr_var = command.args[0].clone(); + let port_var = command.args[1].clone(); + let accept_func = command.args[2].clone(); + + // TODO: write logic + } + CommandType::NewThread => { + let func_name = command.args[0].clone(); + + // TODO: write logic + } + _ => {} + } + + Ok(()) + } + pub fn exec_commands( &mut self, commands: Vec, global: bool, locals: &mut HashMap, - ) -> Result<(), ScriptError> { + ) -> Result<(), (ScriptError, Command)> { let mut temp_vars: Vec = Vec::new(); for command in commands { - match command.command_type { - CommandType::InitVar => { - let type_var = command.args[0].clone(); - let type_var = VarType::from_name(&type_var)?; - let name_var = command.args[1].clone(); + if let CommandType::Return = command.command_type { + return Ok(()); + } - self.set_var(name_var, Variable::empty_var(type_var)?, global, locals)?; - } - CommandType::SetVar => { - let name_var = command.args[0].clone(); - let value_var = command.args[1..].join(" "); + match self.exec_command(command.clone(), global, locals, &mut temp_vars) { + Ok(_) => {} + Err(e) => return Err((e, command.clone())), + }; - let type_var = self - .get_var(name_var.clone(), &mut locals.clone())? - .get_type(); - let var = Variable::parse_var(type_var, value_var)?; - - self.set_var(name_var, var, global, locals)?; - } - CommandType::TempVar => { - let type_var = command.args[0].clone(); - let name_var = command.args[1].clone(); - let value_var = command.args[2..].join(" "); - - self.set_var( - name_var.clone(), - Variable::parse_var(VarType::from_name(&type_var)?, value_var)?, - global, - locals, - )?; - - temp_vars.push(name_var); - - continue; - } - CommandType::MoveVar => { - let source_var = command.args[0].clone(); - let target_var = command.args[1].clone(); - - let var = self.get_var(source_var.clone(), locals)?; - - self.set_var(target_var, var, global, locals)?; - self.drop_var(source_var, locals)?; - } - CommandType::CopyVar => { - let source_var = command.args[0].clone(); - let target_var = command.args[1].clone(); - - let var = self.get_var(source_var.clone(), locals)?; - - self.set_var(target_var, var, global, locals)?; - } - CommandType::DropVar => { - let name_var = command.args[0].clone(); - - self.drop_var(name_var, locals)?; - } - CommandType::HasVar => { - let name_var = command.args[0].clone(); - let result_var = command.args[1].clone(); - - let result = self.get_var(name_var, locals).is_ok(); - - self.set_var( - result_var, - Variable::from_bool(Some(result)), - global, - locals, - )?; - } - CommandType::AddStr => { - let var_name = command.args[0].clone(); - let other_var = command.args[1].clone(); - - let other_var = self.get_var(other_var.clone(), locals)?; - let other_var: String = if let Variable::List(VarType::Char, Some(list)) = - other_var - { - let mut bytes = Vec::new(); - for ele in list { - bytes.push(ele.as_char()?); - } - String::from_utf8(bytes).or(Err(ScriptError::TypeMismatchError))? - } else if let Variable::String(_, Some(string)) = other_var { - string - } else if let Variable::Char(_, Some(value)) = other_var { - String::from_utf8(vec![value]).or(Err(ScriptError::TypeMismatchError))? - } else { - return Err(ScriptError::TypeMismatchError); - }; - - let var = self.get_var(var_name.clone(), locals)?.as_str()?; - - self.set_var( - var_name, - Variable::from_str(Some(var + &other_var)), - global, - locals, - )?; - } - CommandType::Write => { - let name_var = command.args[0].clone(); - let stream_var = command.args[1].clone(); - - let text = self.get_var(name_var.clone(), locals)?; - let text: Vec = if let Variable::List(VarType::Char, Some(list)) = text { - let mut bytes = Vec::new(); - for ele in list { - bytes.push(ele.as_char()?); - } - bytes - } else if let Variable::String(_, Some(string)) = text { - string.as_bytes().to_vec() - } else if let Variable::Char(_, Some(value)) = text { - vec![value] - } else { - return Err(ScriptError::TypeMismatchError); - }; - - let stream = self.get_var(stream_var.clone(), locals)?.as_out_stream()?; - stream.lock().unwrap().write_all(&text).unwrap(); - } - CommandType::UseFunc => { - let func_name = command.args[0].clone(); - let result_name = command.args[1].clone(); - let args_names = command.args[2..].to_vec(); - - let func = self.get_function(func_name).unwrap(); - - let mut args = Vec::new(); - for name in args_names { - args.push(self.get_var(name, locals)?); - } - - self.exec_function(func, result_name, args)?; - } - CommandType::Return => { - return Ok(()); - } - CommandType::For => { - let func_name = command.args[0].clone(); - let start_index = self.get_var(command.args[1].clone(), locals)?.as_int()?; - let end_index = self.get_var(command.args[2].clone(), locals)?.as_int()?; - - let func = self.get_function(func_name).unwrap(); - - for index in start_index..=end_index { - self.exec_function( - func.clone(), - "null".to_string(), - vec![Variable::from_int(Some(index))], - )?; - } - } - CommandType::ToString => { - let source_var = command.args[0].clone(); - let result_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::ToChars => { - let source_var = command.args[0].clone(); - let result_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::ToInteger => { - let source_var = command.args[0].clone(); - let result_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::ToFloat => { - let source_var = command.args[0].clone(); - let result_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::ToBool => { - let source_var = command.args[0].clone(); - let result_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::ToChar => { - let source_var = command.args[0].clone(); - let result_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::GetSymbol => { - let str_var = command.args[0].clone(); - let index_var = command.args[1].clone(); - let result_var = command.args[2].clone(); - - // TODO: write logic - } - CommandType::AddInt => { - let var = command.args[0].clone(); - let other_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::AddFloat => { - let var = command.args[0].clone(); - let other_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::SubStr => { - let str_var = command.args[0].clone(); - let start_index = command.args[1].clone(); - let end_index = command.args[1].clone(); - - // TODO: write logic - } - CommandType::SubList => { - let list_var = command.args[0].clone(); - let start_index = command.args[1].clone(); - let end_index = command.args[1].clone(); - - // TODO: write logic - } - CommandType::ListSize => { - let list_var = command.args[0].clone(); - let result_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::MapSize => { - let map_var = command.args[0].clone(); - let result_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::StringSize => { - let string_var = command.args[0].clone(); - let result_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::Read => { - let name_var = command.args[0].clone(); - let size_var = command.args[1].clone(); - let stream_var = command.args[2].clone(); - - // TODO: write logic - } - CommandType::ReadAll => { - let name_var = command.args[0].clone(); - let stream_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::ForMap => { - let func_name = command.args[0].clone(); - let map_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::ForList => { - let func_name = command.args[0].clone(); - let list_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::ForString => { - let func_name = command.args[0].clone(); - let string_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::While => { - let func_name = command.args[0].clone(); - - // TODO: write logic - } - CommandType::OpenFileIn => { - let path_var = command.args[0].clone(); - let stream_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::OpenFileOut => { - let path_var = command.args[0].clone(); - let stream_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::OpenTcpConnection => { - let addr_var = command.args[0].clone(); - let port_var = command.args[1].clone(); - let in_stream = command.args[2].clone(); - let out_stream = command.args[3].clone(); - - // TODO: write logic - } - CommandType::OpenTcpListener => { - let addr_var = command.args[0].clone(); - let port_var = command.args[1].clone(); - let accept_func = command.args[2].clone(); - - // TODO: write logic - } - CommandType::Sleep => { - let time_var = command.args[0].clone(); - - // TODO: write logic - } - CommandType::NewThread => { - let func_name = command.args[0].clone(); - - // TODO: write logic - } - CommandType::Equals => { - let var = command.args[0].clone(); - let other_var = command.args[1].clone(); - let result_var = command.args[2].clone(); - - // TODO: write logic - } - CommandType::More => { - let var = command.args[0].clone(); - let other_var = command.args[1].clone(); - let result_var = command.args[2].clone(); - - // TODO: write logic - } - CommandType::Less => { - let var = command.args[0].clone(); - let other_var = command.args[1].clone(); - let result_var = command.args[2].clone(); - - // TODO: write logic - } - CommandType::And => { - let var = command.args[0].clone(); - let other_var = command.args[1].clone(); - let result_var = command.args[2].clone(); - - // TODO: write logic - } - CommandType::Or => { - let var = command.args[0].clone(); - let other_var = command.args[1].clone(); - let result_var = command.args[2].clone(); - - // TODO: write logic - } - CommandType::If => { - let bool_var = command.args[0].clone(); - let func_name = command.args[1].clone(); - - // TODO: write logic - } - CommandType::HasStr => { - let string_var = command.args[0].clone(); - let substring = command.args[1].clone(); - let result_var = command.args[2].clone(); - - // TODO: write logic - } - CommandType::HasItem => { - let list_var = command.args[0].clone(); - let item_var = command.args[1].clone(); - let result_var = command.args[2].clone(); - - // TODO: write logic - } - CommandType::HasEntry => { - let map_var = command.args[0].clone(); - let key_var = command.args[1].clone(); - let value_var = command.args[2].clone(); - let result_var = command.args[3].clone(); - - // TODO: write logic - } - CommandType::HasKey => { - let map_var = command.args[0].clone(); - let key_var = command.args[1].clone(); - let result_var = command.args[2].clone(); - - // TODO: write logic - } - CommandType::HasValue => { - let map_var = command.args[0].clone(); - let value_var = command.args[1].clone(); - let result_var = command.args[2].clone(); - - // TODO: write logic - } - CommandType::HasOptional => { - let optional_var = command.args[0].clone(); - let result_var = command.args[1].clone(); - - // TODO: write logic - } - CommandType::UnpackOptional => { - let optional_var = command.args[0].clone(); - let result_var = command.args[1].clone(); - - // TODO: write logic - } - _ => {} + if let CommandType::TempVar = command.command_type { + continue; } for ele in temp_vars.clone() { @@ -1771,7 +2437,23 @@ impl RunningScript { Variable::empty_var(function.result_type)?, ); - self.exec_commands(function.commands, false, &mut locals)?; + let mut temp_vars: Vec = Vec::new(); + + for command in function.commands { + if let CommandType::Return = command.command_type { + return Ok(()); + } + + self.exec_command(command.clone(), false, &mut locals, &mut temp_vars)?; + + if let CommandType::TempVar = command.command_type { + continue; + } + + for ele in temp_vars.clone() { + self.variables.remove(&ele); + } + } if result_var != "null" { self.variables @@ -1781,7 +2463,7 @@ impl RunningScript { Ok(()) } - pub fn run(&mut self) -> Result<(), ScriptError> { + pub fn run(&mut self) -> Result<(), (ScriptError, Command)> { self.exec_commands(self.commands.clone(), true, &mut HashMap::new()) } } diff --git a/src/main.rs b/src/main.rs index f38638b..6c2c23e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,5 +18,10 @@ fn main() { running_script .set_standard_vars(args, Box::new(stdout()), Box::new(stdin())) .unwrap(); - running_script.run().unwrap(); + match running_script.run() { + Ok(_) => {} + Err((e, c)) => { + println!("error ({:?}) command: {:?}", e, c); + } + }; } diff --git a/test.sus b/test.sus index 21bf2da..fafcc71 100644 --- a/test.sus +++ b/test.sus @@ -1,19 +1,72 @@ +INIT_VAR char space +SET_VAR space 32 + +INIT_VAR char new_line +SET_VAR new_line 10 + FUNC null println text string # println function - TEMP_VAR char br 10 # line break var - ADD_STR text br # add line break to text var + ADD_STR text new_line # add line break to text var WRITE text cout # write text var to console FUNC_END # end println function -FUNC null hello_world index integer - USE_FUNC println null text + +# write hello world + +TEMP_VAR string text Hello World! +USE_FUNC println null text + + + + +# write args length + +INIT_VAR integer args_size + LIST_SIZE args args_size + + TEMP_VAR integer add -1 + ADD_INT args_size add + + INIT_VAR string args_size_str + TO_STRING args_size args_size_str + + INIT_VAR string args_size_str_formatted # create var + SET_VAR args_size_str_formatted # init var with value + + INIT_VAR string prefix + SET_VAR prefix Args length: + + ADD_STR args_size_str_formatted prefix + ADD_STR args_size_str_formatted space + ADD_STR args_size_str_formatted args_size_str + + USE_FUNC println null args_size_str_formatted + DROP_VAR prefix + + DROP_VAR args_size_str_formatted + DROP_VAR args_size_str +DROP_VAR args_size + + +FUNC null print_arg_finally + USE_FUNC println null now_arg FUNC_END -INIT_VAR string text -SET_VAR text Hello World! +FUNC null print_arg index integer + INIT_VAR bool is_first + SET_VAR is_first false + TEMP_VAR int first 0 + MORE index first is_first + GET_ITEM args index now_arg + IF is_first print_arg_finally +FUNC_END -TEMP_VAR integer start_index 0 # temp vars can stack -TEMP_VAR integer end_index 9 +TEMP_VAR string text Args: +USE_FUNC println null text -FOR hello_world start_index end_index - -DROP_VAR text +INIT_VAR string now_arg +INIT_VAR integer end_index +LIST_SIZE args end_index +TEMP_VAR integer add -1 +ADD_INT end_index add +TEMP_VAR integer start_index 0 +FOR print_arg start_index end_index