From e02528b2f130ad92ddb8b75edd180a538aae1ba1 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 27 Jul 2024 21:04:48 +0300 Subject: [PATCH] refactor --- README.md | 9 +- src/lib.rs | 1120 +++++++++++++++++++++++++++++++++------------------ src/main.rs | 4 +- test.sus | 15 +- 4 files changed, 749 insertions(+), 399 deletions(-) diff --git a/README.md b/README.md index 3f427a9..e06124a 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,13 @@ WRITE text cout | Команда | Параметры | Описание | |--------------------------|------------|-------------| -| `TO_STRING` | `source_var`, `target_var` | Скопировать значение переменной с `source_var` в `target_var`, переводя в строку | +| `TO_STRING` | `source_var`, `result_var` | Скопировать значение переменной с `source_var` в `result_var`, переводя в `string` | +| `TO_BYTES` | `str_var`, `result_var` | Скопировать строку `str_var` в `result_var`, переводя в `list[char]` | +| `TO_INTEGER` | `source_var`, `result_var` | Скопировать строку `source_var` (тип переменной: `string`/`char`) в `result_var`, переводя в `integer` | +| `TO_CHAR` | `source_var`, `result_var` | Скопировать строку `source_var` (тип переменной: `string`/`integer`) в `result_var`, переводя в `char` | +| `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` | | `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]`) | @@ -79,6 +85,7 @@ WRITE text cout | `LESS` | `var`, `other_var`, `result_var` | Узнать, меньше ли в `var` чем в `other_var` записать результат в `result_var` | | `AND` | `var`, `other_var`, `result_var` | Если `var` и `other_var` равны `true`, то результат `true`, иначе `false`, записать результат в `result_var` | | `OR` | `var`, `other_var`, `result_var` | Если `var` или `other_var` равен `true`, то результат `true`, иначе `false`, записать результат в `result_var` | +| `NOT` | `var`, `result_var` | Если `var` равен `true`, то результат `false`, иначе `true`, записать результат в `result_var` | | `IF` | `bool_var`, `func` | Если `var` равен `true` то вызвать функцию `func` | | `HAS_STR` | `string_var`, `substring`, `result_var` | Узнать, имеет ли строка `var` в себе подстроку `substring` и записать результат в `result_var` | | `HAS_ITEM` | `list_var`, `item_var`, `result_var` | Узнать, имеет ли список `list_var` значение `item_var` и записать результат в `result_var` | diff --git a/src/lib.rs b/src/lib.rs index 8d82660..506cc9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,31 @@ use std::{ char::EscapeDebug, collections::HashMap, + error::Error, + fmt::Display, hash::Hash, io::{Read, Write}, ptr::hash, sync::{Arc, Mutex}, }; +#[derive(Debug)] +pub enum ScriptError { + ParseVarError, + TypeUnknownError, + CommandUnknownError(usize), + CommandArgsInvalidError(usize), + UnknownVarError, + TypeMismatchError, +} + +impl Display for ScriptError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("some error ez") + } +} +impl Error for ScriptError {} + #[derive(PartialEq, Clone, Debug, Hash)] pub enum VarType { Bool, @@ -19,10 +38,11 @@ pub enum VarType { Optional(Box), InStream, OutStream, + Null, } impl VarType { - pub fn from_name(name: &str) -> Option { + pub fn from_name(name: &str) -> Result { if name.starts_with("map[") { let value_type = name[9..name.len() - 1].to_string(); @@ -51,28 +71,29 @@ impl VarType { let key_type = Box::new(VarType::from_name(&key_type)?); let val_type = Box::new(VarType::from_name(&val_type)?); - return Some(VarType::Map(key_type, val_type)); + return Ok(VarType::Map(key_type, val_type)); } if name.starts_with("list[") { let value_type = name[5..name.len() - 1].to_string(); let value_type = Box::new(VarType::from_name(&value_type)?); - return Some(VarType::List(value_type)); + return Ok(VarType::List(value_type)); } if name.starts_with("optional[") { let value_type = name[9..name.len() - 1].to_string(); let value_type = Box::new(VarType::from_name(&value_type)?); - return Some(VarType::Optional(value_type)); + return Ok(VarType::Optional(value_type)); } match name { - "bool" => Some(VarType::Bool), - "string" => Some(VarType::String), - "integer" => Some(VarType::Integer), - "float" => Some(VarType::Float), - "char" => Some(VarType::Char), - "in_stream" => Some(VarType::InStream), - "out_stream" => Some(VarType::OutStream), - _ => None, + "bool" => Ok(VarType::Bool), + "string" => Ok(VarType::String), + "integer" => Ok(VarType::Integer), + "float" => Ok(VarType::Float), + "char" => Ok(VarType::Char), + "in_stream" => Ok(VarType::InStream), + "out_stream" => Ok(VarType::OutStream), + "null" => Ok(VarType::Null), + _ => Err(ScriptError::TypeUnknownError), } } } @@ -89,6 +110,7 @@ pub enum Variable { Optional(VarType, Option>>), InStream(VarType, Option>>), OutStream(VarType, Option>>), + Null(VarType), } impl Variable { @@ -104,31 +126,221 @@ impl Variable { Variable::Optional(t, _) => t.clone(), Variable::InStream(t, _) => t.clone(), Variable::OutStream(t, _) => t.clone(), + Variable::Null(t) => t.clone(), } } - pub fn empty_var(var_type: VarType) -> Option { + pub fn is_null(&self) -> bool { + if let Variable::Null(_) = self { + true + } else { + false + } + } + + pub fn is_initialized(&self) -> bool { + match self { + Variable::Bool(_, b) => b.is_some(), + Variable::String(_, b) => b.is_some(), + Variable::Integer(_, b) => b.is_some(), + Variable::Float(_, b) => b.is_some(), + Variable::Char(_, b) => b.is_some(), + Variable::List(_, b) => b.is_some(), + Variable::Map(_, b) => b.is_some(), + Variable::Optional(_, b) => b.is_some(), + Variable::InStream(_, b) => b.is_some(), + Variable::OutStream(_, b) => b.is_some(), + Variable::Null(_) => true, + } + } + + pub fn from_bool(value: Option) -> Variable { + Variable::Bool(VarType::Bool, value) + } + + pub fn from_str(value: Option) -> Variable { + Variable::String(VarType::String, value) + } + + pub fn from_int(value: Option) -> Variable { + Variable::Integer(VarType::Integer, value) + } + + pub fn from_float(value: Option) -> Variable { + Variable::Float(VarType::Float, value) + } + + pub fn from_char(value: Option) -> Variable { + Variable::Char(VarType::Char, value) + } + + pub fn from_list(value: Option>, value_type: VarType) -> Variable { + Variable::List(VarType::List(Box::new(value_type)), value) + } + + pub fn from_map( + value: Option>, + key_type: VarType, + value_type: VarType, + ) -> Variable { + Variable::Map( + VarType::Map(Box::new(key_type), Box::new(value_type)), + value, + ) + } + + pub fn from_optional(value: Option>, var_type: VarType) -> Variable { + Variable::Optional( + VarType::Optional(Box::new(var_type)), + match value { + Some(value) => match value { + Some(value) => Some(Some(Box::new(value))), + None => Some(None), + }, + None => None, + }, + ) + } + + pub fn from_null() -> Variable { + Variable::Null(VarType::Null) + } + + pub fn from_out_stream(value: Option>>) -> Variable { + Variable::OutStream(VarType::OutStream, value) + } + + pub fn from_in_stream(value: Option>>) -> Variable { + Variable::InStream(VarType::InStream, value) + } + + pub fn as_out_stream(&self) -> Result>, ScriptError> { + if let Variable::OutStream(_, Some(b)) = self { + Ok(b.clone()) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn as_in_stream(&self) -> Result>, ScriptError> { + if let Variable::InStream(_, Some(b)) = self { + Ok(b.clone()) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn get_option_type(&self) -> Result { + if let Variable::Optional(VarType::Optional(v), _) = self { + Ok(v.as_ref().clone()) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn as_option(&self) -> Result>, ScriptError> { + if let Variable::Optional(_, Some(b)) = self { + Ok(b.clone()) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn get_map_types(&self) -> Result<(VarType, VarType), ScriptError> { + if let Variable::Map(VarType::Map(k, v), _) = self { + Ok((k.as_ref().clone(), v.as_ref().clone())) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn as_map(&self) -> Result, ScriptError> { + if let Variable::Map(_, Some(b)) = self { + Ok(b.clone()) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn get_list_type(&self) -> Result { + if let Variable::List(VarType::List(v), _) = self { + Ok(v.as_ref().clone()) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn as_list(&self) -> Result, ScriptError> { + if let Variable::List(_, Some(b)) = self { + Ok(b.clone()) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn as_char(&self) -> Result { + if let Variable::Char(_, Some(b)) = self { + Ok(*b) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn as_float(&self) -> Result { + if let Variable::Float(_, Some(b)) = self { + Ok(*b) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn as_int(&self) -> Result { + if let Variable::Integer(_, Some(b)) = self { + Ok(*b) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn as_str(&self) -> Result { + if let Variable::String(_, Some(b)) = self { + Ok(b.to_string()) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn as_bool(&self) -> Result { + if let Variable::Bool(_, Some(b)) = self { + Ok(*b) + } else { + Err(ScriptError::TypeMismatchError) + } + } + + pub fn empty_var(var_type: VarType) -> Result { match var_type { - VarType::Bool => Some(Variable::Bool(VarType::Bool, None)), - VarType::String => Some(Variable::String(VarType::String, None)), - VarType::Integer => Some(Variable::Integer(VarType::Integer, None)), - VarType::Float => Some(Variable::Float(VarType::Float, None)), - VarType::Char => Some(Variable::Char(VarType::Char, None)), + VarType::Bool => Ok(Variable::Bool(VarType::Bool, None)), + VarType::String => Ok(Variable::String(VarType::String, None)), + VarType::Integer => Ok(Variable::Integer(VarType::Integer, None)), + VarType::Float => Ok(Variable::Float(VarType::Float, None)), + VarType::Char => Ok(Variable::Char(VarType::Char, None)), VarType::Optional(optional_type) => { - Some(Variable::Optional(VarType::Optional(optional_type), None)) + Ok(Variable::Optional(VarType::Optional(optional_type), None)) } - VarType::List(value_type) => Some(Variable::List(VarType::List(value_type), None)), + VarType::List(value_type) => Ok(Variable::List(VarType::List(value_type), None)), VarType::Map(key_type, value_type) => { - Some(Variable::Map(VarType::Map(key_type, value_type), None)) + Ok(Variable::Map(VarType::Map(key_type, value_type), None)) } - VarType::InStream => Some(Variable::InStream(VarType::InStream, None)), - VarType::OutStream => Some(Variable::OutStream(VarType::OutStream, None)), + VarType::InStream => Ok(Variable::InStream(VarType::InStream, None)), + VarType::OutStream => Ok(Variable::OutStream(VarType::OutStream, None)), + VarType::Null => Ok(Variable::Null(VarType::Null)), } } - pub fn parse_var(var_type: VarType, text: String) -> Option { + pub fn parse_var(var_type: VarType, text: String) -> Result { match var_type { - VarType::Bool => Some(Variable::Bool( + VarType::Bool => Ok(Variable::Bool( VarType::Bool, Some(match text.as_str() { "true" => true, @@ -136,58 +348,59 @@ impl Variable { "1" => true, "0" => false, _ => { - return None; + return Err(ScriptError::ParseVarError); } }), )), - VarType::String => Some(Variable::String(VarType::String, Some(text))), - VarType::Integer => Some(Variable::Integer( + VarType::Null => Ok(Variable::Null(VarType::Null)), + VarType::String => Ok(Variable::String(VarType::String, Some(text))), + VarType::Integer => Ok(Variable::Integer( VarType::Integer, Some(match text.parse() { Ok(i) => i, Err(_) => { - return None; + return Err(ScriptError::ParseVarError); } }), )), - VarType::Float => Some(Variable::Float( + VarType::Float => Ok(Variable::Float( VarType::Float, Some(match text.parse() { Ok(i) => i, Err(_) => { - return None; + return Err(ScriptError::ParseVarError); } }), )), - VarType::Char => Some(Variable::Char( + VarType::Char => Ok(Variable::Char( VarType::Char, Some(match text.parse() { Ok(i) => i, Err(_) => { - return None; + return Err(ScriptError::ParseVarError); } }), )), VarType::Optional(optional_type) => { if text.starts_with("[") && text.ends_with("]") { let text = text[1..text.len() - 1].to_string(); - Some(Variable::Optional( + Ok(Variable::Optional( VarType::Optional(optional_type.clone()), - match Self::parse_var(optional_type.clone().as_mut().clone(), text) { - Some(i) => Some(Some(Box::new(i))), - None => None, - }, + Some(Some(Box::new(Self::parse_var( + optional_type.clone().as_mut().clone(), + text, + )?))), )) } else if text.as_str() == "none" { - Some(Variable::Optional( + Ok(Variable::Optional( VarType::Optional(optional_type), Some(None), )) } else { - None + Err(ScriptError::ParseVarError) } } - _ => None, + _ => Err(ScriptError::ParseVarError), } } } @@ -226,6 +439,9 @@ impl Hash for Variable { Variable::OutStream(_, value) => { hash(value, state); } + Variable::Null(t) => { + hash(t, state); + } } } } @@ -236,6 +452,10 @@ impl PartialEq for Variable { Variable::Bool(_, other_value) => value == other_value, _ => false, }, + Variable::Null(o) => match other { + Variable::Null(t) => o == t, + _ => false, + }, Variable::String(_, value) => match other { Variable::String(_, other_value) => value == other_value, _ => false, @@ -327,187 +547,223 @@ impl PartialEq for Variable { pub enum CommandType { /// Инициализировать переменную `name_var` с типом `type_var` /// - /// Название: INIT_VAR + /// Название: INIT_VAR \ /// Параметры: `type_var`, `name_var` InitVar, /// Установить значение переменной в `name_var` /// - /// Название: SET_VAR + /// Название: SET_VAR \ /// Параметры: `name_var`, `value_var` SetVar, /// Переменная `name_var` инициализируется с типом `type_var` и присваивается `value_var`, переменная дропается через одну команду /// - /// Название: TEMP_VAR + /// Название: TEMP_VAR \ /// Параметры: `type_var`, `name_var`, `value_var` TempVar, /// Переместить значение переменной с `source_var` в `target_var` /// - /// Название: MOVE_VAR + /// Название: MOVE_VAR \ /// Параметры: `source_var`, `target_var` MoveVar, /// Скопировать значение переменной с `source_var` в `target_var` /// - /// Название: COPY_VAR + /// Название: COPY_VAR \ /// Параметры: `source_var`, `target_var` CopyVar, /// Дропнуть переменную `name_var` /// - /// Название: DROP_VAR + /// Название: DROP_VAR \ /// Параметры: `name_var` DropVar, /// В переменную `result_var` записывается `bool` существует ли переменная `name_var` /// - /// Название: HAS_VAR + /// Название: HAS_VAR \ /// Параметры: `name_var`, `result_var` HasVar, - /// Скопировать значение переменной с `source_var` в `target_var`, переводя в строку + /// Скопировать значение переменной с `source_var` в `result_var`, переводя в `string` /// - /// Название: TO_STRING - /// Параметры: `source_var`, `target_var` + /// Название: TO_STRING \ + /// Параметры: `source_var`, `result_var` ToString, + /// Скопировать строку `str_var` в `result_var`, переводя в `list[char]` + /// + /// Название: TO_BYTES \ + /// Параметры: `source_var`, `result_var` + ToBytes, + + /// Скопировать строку `source_var` (тип переменной: `string`/`integer`) в `result_var`, переводя в `char` + /// + /// Название: TO_CHAR \ + /// Параметры: `source_var`, `result_var` + ToChar, + + /// Скопировать строку `source_var` (тип переменной: `string`/`char`) в `result_var`, переводя в `integer` + /// + /// Название: TO_INTEGER \ + /// Параметры: `source_var`, `result_var` + ToInteger, + + /// Скопировать строку `source_var` в `result_var`, переводя в `float` + /// + /// Название: TO_FLOAT \ + /// Параметры: `source_var`, `result_var` + ToFloat, + + /// Скопировать строку `source_var` (тип переменной: `string`/`integer`) в `result_var`, переводя в `bool` + /// + /// Название: TO_BOOL \ + /// Параметры: `source_var`, `result_var` + ToBool, + + /// Скопировать символ из строки `str_var` по индексу `index_var` и записать в `result_var` + /// + /// Название: GET_SYMBOL \ + /// Параметры: `str_var`, `index_var`, `result_var` + GetSymbol, + /// Прибавить к числу `var` значение `other_var` /// - /// Название: ADD_INT + /// Название: ADD_INT \ /// Параметры: `var`, `other_var` AddInt, /// Прибавить к числу `var` значение `other_var` /// - /// Название: ADD_FLOAT + /// Название: ADD_FLOAT \ /// Параметры: `var`, `other_var` AddFloat, /// Прибавить к числу `var` значение `other_var` /// - /// Название: ADD_STR + /// Название: ADD_STR \ /// Параметры: `var`, `other_var` AddStr, /// Сделать подстроку из строки `str_var` и сохранить туда же /// - /// Название: SUB_STR + /// Название: SUB_STR \ /// Параметры: `str_var`, `start_index`, `end_index` SubStr, /// Сделать подсписок из списка `list_var` и сохранить туда же /// - /// Название: SUB_LIST + /// Название: SUB_LIST \ /// Параметры: `list_var`, `start_index`, `end_index` SubList, /// Получить размер списка и записать в переменную `result_var` типа `int` /// - /// Название: LIST_SIZE + /// Название: LIST_SIZE \ /// Параметры: `list_var`, `result_var` ListSize, /// Вывести переменную `name_var` в `stream_var` /// - /// Название: WRITE + /// Название: WRITE \ /// Параметры: `name_var`, `stream_var` Write, /// Прочитать с `stream_var` ровно `size_var` байтов в переменную `name_var` типа `list[char]` /// - /// Название: READ + /// Название: READ \ /// Параметры: `name_var`, `size_var`, `stream_var` Read, /// Прочитать с `stream_var` все имеющиеся байты в переменную `name_var` типа `list[char]` /// - /// Название: READ_ALL + /// Название: READ_ALL \ /// Параметры: `name_var`, `stream_var` ReadAll, /// Прочитать с `stream_var` ровно `size_var` байтов в переменную `name_var` типа `string` /// - /// Название: READ_STR + /// Название: READ_STR \ /// Параметры: `name_var`, `size_var`, `stream_var` ReadStr, /// Прочитать с `stream_var` все имеющиеся байты в переменную `name_var` типа `string` /// - /// Название: READ_STR_ALL + /// Название: READ_STR_ALL \ /// Параметры: `name_var`, `stream_var` ReadStrAll, /// Функция `func` (с единственным аргументом с типом `int`) вызывается с `start_index` до `end_index` включительно, `start_index` и `end_index` это названия переменных /// - /// Название: FOR + /// Название: FOR \ /// Параметры: `func(int)`, `start_index`, `end_index` For, /// Функция `func` вызывается для каждого `key`, `value` переменной `map_var` /// - /// Название: FOR_MAP + /// Название: FOR_MAP \ /// Параметры: `func(any, any)`, `map_var` ForMap, /// Функция `func` вызывается для каждого предмета переменной `list_var` /// - /// Название: FOR_LIST + /// Название: FOR_LIST \ /// Параметры: `func(any)`, `list_var` ForList, /// Функция `func` (с результатом `bool`) вызывается, пока функция выдает `true` /// - /// Название: WHILE + /// Название: WHILE \ /// Параметры: `func -> bool` While, /// Открыть файл по пути `path_var` (`path_var`, `stream_var` - переменные) для чтения и записать стрим для чтения в переменную `stream_var` /// - /// Название: OPEN_FILE_IN + /// Название: OPEN_FILE_IN \ /// Параметры: `path_var`, `stream_var` OpenFileIn, /// Открыть файл по пути `path_var` (`path_var`, `stream_var` - переменные) для записи и записать стрим для записи в переменную `stream_var` /// - /// Название: OPEN_FILE_OUT + /// Название: OPEN_FILE_OUT \ /// Параметры: `path_var`, `stream_var` OpenFileOut, /// Подключиться по `addr_var:port_var` (`addr_var: string`, `port_var: int`, `in_stream: in_stream`, `out_stream: out_stream` - переменные) и записать стримы для чтения и записи в `in_stream` и `out_stream` /// - /// Название: OPEN_TCP_CONNECTION + /// Название: OPEN_TCP_CONNECTION \ /// Параметры: `addr_var`, `port_var`, `in_stream`, `out_stream` OpenTcpConnection, /// Ожидание подключений с `addr_var:port_var` (`addr_var: string`, `port_var: int` - переменные), при подключениях вызывается функция `accept_func` /// - /// Название: OPEN_TCP_LISTENER + /// Название: OPEN_TCP_LISTENER \ /// Параметры: `addr_var`, `port_var`, `accept_func(string,int,in_stream,out_stream)` OpenTcpListener, /// Ждать миллисекунд из переменной `time_var` (тип переменной: int) /// - /// Название: SLEEP + /// Название: SLEEP \ /// Параметры: `time_var` Sleep, /// Вызвать функцию `func` в новом потоке /// - /// Название: NEW_THREAD + /// Название: NEW_THREAD \ /// Параметры: `func` NewThread, /// Функция `func` вызывается с переданными аргументами и устанавливает результат в переменную `result_var` /// - /// Название: USE_FUNC + /// Название: USE_FUNC \ /// Параметры: `func_name`, `result_var`, `[arg_var1] ... [arg_varN]` UseFunc, /// Создать функцию с типом результата `result_type`, названием `func_name` и аргументами `[arg_name_1 arg_type] ... [arg_name_N arg_type]`. Установить результат переменной можно изменив переменную `result` внутри функции. Все команды после этой и до `FUNC_END` будут командами функции. Функции внутри функций не могут быть. /// - /// Название: FUNC + /// Название: FUNC \ /// Параметры: `result_type`, `func_name`, `[arg_name_1 arg_type] ... [arg_name_N arg_type]` Func, @@ -523,126 +779,132 @@ pub enum CommandType { /// Узнать, равен ли `var` и `other_var` записать результат в `result_var` /// - /// Название: EQUALS + /// Название: EQUALS \ /// Параметры: `var`, `other_var`, `result_var` Equals, /// Узнать, больше ли в `var` чем в `other_var` записать результат в `result_var` /// - /// Название: MORE + /// Название: MORE \ /// Параметры: `var`, `other_var`, `result_var` More, /// Узнать, меньше ли в `var` чем в `other_var` записать результат в `result_var` /// - /// Название: LESS + /// Название: LESS \ /// Параметры: `var`, `other_var`, `result_var` Less, /// Если `var` и `other_var` равны `true`, то результат `true`, иначе `false`, записать результат в `result_var` /// - /// Название: AND + /// Название: AND \ /// Параметры: `var`, `other_var`, `result_var` And, /// Если `var` или `other_var` равен `true`, то результат `true`, иначе `false`, записать результат в `result_var` /// - /// Название: OR + /// Название: OR \ /// Параметры: `var`, `other_var`, `result_var` Or, /// Если `var` равен `true` то вызвать функцию `func` /// - /// Название: IF + /// Название: IF \ /// Параметры: `bool_var`, `func` If, /// Узнать, имеет ли строка `var` в себе подстроку `substring` и записать результат в `result_var` /// - /// Название: HAS_STR + /// Название: HAS_STR \ /// Параметры: `string_var`, `substring`, `result_var` HasStr, /// Узнать, имеет ли список `list_var` значение `item_var` и записать результат в `result_var` /// - /// Название: HAS_ITEM + /// Название: HAS_ITEM \ /// Параметры: `list_var`, `item_var`, `result_var` HasItem, /// Узнать, имеет ли мап `map_var` поле с ключом `key_var` и значением `value_var` и записать результат в `result_var` /// - /// Название: HAS_ENTRY + /// Название: HAS_ENTRY \ /// Параметры: `map_var`, `key_var`, `value_var`, `result_var` HasEntry, /// Узнать, имеет ли мап `map_var` поле с ключом `key_var` и записать результат в `result_var` /// - /// Название: HAS_KEY + /// Название: HAS_KEY \ /// Параметры: `map_var`, `key_var`, `result_var` HasKey, /// Узнать, имеет ли мап `map_var` поле с значением `value_var` и записать результат в `result_var` /// - /// Название: HAS_VALUE + /// Название: HAS_VALUE \ /// Параметры: `map_var`, `value_var`, `result_var` HasValue, /// Узнать, имеет ли данные опшнл `optional_var` и записать результат в `result_var` /// - /// Название: HAS_OPTIONAL + /// Название: HAS_OPTIONAL \ /// Параметры: `optional_var`, `result_var` HasOptional, } impl CommandType { - pub fn from_name(name: &str) -> Option { + pub fn from_name(name: &str, line: usize) -> Result { match name { - "INIT_VAR" => Some(CommandType::InitVar), - "SET_VAR" => Some(CommandType::SetVar), - "TEMP_VAR" => Some(CommandType::TempVar), - "MOVE_VAR" => Some(CommandType::MoveVar), - "COPY_VAR" => Some(CommandType::CopyVar), - "DROP_VAR" => Some(CommandType::DropVar), - "HAS_VAR" => Some(CommandType::HasVar), - "TO_STRING" => Some(CommandType::ToString), - "ADD_INT" => Some(CommandType::AddInt), - "ADD_FLOAT" => Some(CommandType::AddFloat), - "ADD_STR" => Some(CommandType::AddStr), - "SUB_STR" => Some(CommandType::SubStr), - "SUB_LIST" => Some(CommandType::SubList), - "LIST_SIZE" => Some(CommandType::ListSize), - "WRITE" => Some(CommandType::Write), - "READ" => Some(CommandType::Read), - "READ_ALL" => Some(CommandType::ReadAll), - "READ_STR" => Some(CommandType::ReadStr), - "READ_STR_ALL" => Some(CommandType::ReadStrAll), - "FOR" => Some(CommandType::For), - "FOR_MAP" => Some(CommandType::ForMap), - "FOR_LIST" => Some(CommandType::ForList), - "WHILE" => Some(CommandType::While), - "OPEN_FILE_IN" => Some(CommandType::OpenFileIn), - "OPEN_FILE_OUT" => Some(CommandType::OpenFileOut), - "OPEN_TCP_CONNECTION" => Some(CommandType::OpenTcpConnection), - "OPEN_TCP_LISTENER" => Some(CommandType::OpenTcpListener), - "SLEEP" => Some(CommandType::Sleep), - "NEW_THREAD" => Some(CommandType::NewThread), - "USE_FUNC" => Some(CommandType::UseFunc), - "FUNC" => Some(CommandType::Func), - "FUNC_END" => Some(CommandType::FuncEnd), - "RETURN" => Some(CommandType::Return), - "EQUALS" => Some(CommandType::Equals), - "MORE" => Some(CommandType::More), - "LESS" => Some(CommandType::Less), - "AND" => Some(CommandType::And), - "OR" => Some(CommandType::Or), - "IF" => Some(CommandType::If), - "HAS_STR" => Some(CommandType::HasStr), - "HAS_ITEM" => Some(CommandType::HasItem), - "HAS_ENTRY" => Some(CommandType::HasEntry), - "HAS_KEY" => Some(CommandType::HasKey), - "HAS_VALUE" => Some(CommandType::HasValue), - "HAS_OPTIONAL" => Some(CommandType::HasOptional), - _ => None, + "INIT_VAR" => Ok(CommandType::InitVar), + "SET_VAR" => Ok(CommandType::SetVar), + "TEMP_VAR" => Ok(CommandType::TempVar), + "MOVE_VAR" => Ok(CommandType::MoveVar), + "COPY_VAR" => Ok(CommandType::CopyVar), + "DROP_VAR" => Ok(CommandType::DropVar), + "HAS_VAR" => Ok(CommandType::HasVar), + "TO_STRING" => Ok(CommandType::ToString), + "TO_BYTES" => Ok(CommandType::ToBytes), + "TO_INTEGER" => Ok(CommandType::ToInteger), + "TO_FLOAT" => Ok(CommandType::ToFloat), + "TO_CHAR" => Ok(CommandType::ToChar), + "TO_BOOL" => Ok(CommandType::ToBool), + "GET_SYMBOL" => Ok(CommandType::GetSymbol), + "ADD_INT" => Ok(CommandType::AddInt), + "ADD_FLOAT" => Ok(CommandType::AddFloat), + "ADD_STR" => Ok(CommandType::AddStr), + "SUB_STR" => Ok(CommandType::SubStr), + "SUB_LIST" => Ok(CommandType::SubList), + "LIST_SIZE" => Ok(CommandType::ListSize), + "WRITE" => Ok(CommandType::Write), + "READ" => Ok(CommandType::Read), + "READ_ALL" => Ok(CommandType::ReadAll), + "READ_STR" => Ok(CommandType::ReadStr), + "READ_STR_ALL" => Ok(CommandType::ReadStrAll), + "FOR" => Ok(CommandType::For), + "FOR_MAP" => Ok(CommandType::ForMap), + "FOR_LIST" => Ok(CommandType::ForList), + "WHILE" => Ok(CommandType::While), + "OPEN_FILE_IN" => Ok(CommandType::OpenFileIn), + "OPEN_FILE_OUT" => Ok(CommandType::OpenFileOut), + "OPEN_TCP_CONNECTION" => Ok(CommandType::OpenTcpConnection), + "OPEN_TCP_LISTENER" => Ok(CommandType::OpenTcpListener), + "SLEEP" => Ok(CommandType::Sleep), + "NEW_THREAD" => Ok(CommandType::NewThread), + "USE_FUNC" => Ok(CommandType::UseFunc), + "FUNC" => Ok(CommandType::Func), + "FUNC_END" => Ok(CommandType::FuncEnd), + "RETURN" => Ok(CommandType::Return), + "EQUALS" => Ok(CommandType::Equals), + "MORE" => Ok(CommandType::More), + "LESS" => Ok(CommandType::Less), + "AND" => Ok(CommandType::And), + "OR" => Ok(CommandType::Or), + "IF" => Ok(CommandType::If), + "HAS_STR" => Ok(CommandType::HasStr), + "HAS_ITEM" => Ok(CommandType::HasItem), + "HAS_ENTRY" => Ok(CommandType::HasEntry), + "HAS_KEY" => Ok(CommandType::HasKey), + "HAS_VALUE" => Ok(CommandType::HasValue), + "HAS_OPTIONAL" => Ok(CommandType::HasOptional), + _ => Err(ScriptError::CommandUnknownError(line)), } } } @@ -651,11 +913,16 @@ impl CommandType { pub struct Command { command_type: CommandType, args: Vec, + line: usize, } impl Command { - pub fn new(command_type: CommandType, args: Vec) -> Command { - Command { command_type, args } + pub fn new(command_type: CommandType, line: usize, args: Vec) -> Command { + Command { + command_type, + args, + line, + } } } @@ -689,23 +956,24 @@ fn prepare_script(text: String) -> Vec { Some(s) => s.0, None => s, }) - .filter(|s| !s.trim_matches(' ').is_empty()) .map(|s| s.trim_end_matches(" ").to_string()) .collect() } -fn parse_commands(lines: Vec) -> Vec { +fn parse_commands(lines: Vec) -> Result, ScriptError> { let mut commands = Vec::new(); + let mut line_num = 0; for line in lines { + line_num += 1; + + if line.trim().is_empty() { + continue; + } + let params: Vec = line.split(" ").map(|v| v.to_string()).collect(); - let command_type = match CommandType::from_name(¶ms[0]) { - Some(i) => i, - None => { - continue; - } - }; + let command_type = CommandType::from_name(¶ms[0], line_num)?; let args = if params.is_empty() { Vec::new() @@ -713,13 +981,13 @@ fn parse_commands(lines: Vec) -> Vec { params[1..].to_vec() }; - commands.push(Command::new(command_type, args)) + commands.push(Command::new(command_type, line_num, args)) } - commands + Ok(commands) } -fn cut_funcs(commands: &mut Vec) -> Vec { +fn cut_funcs(commands: &mut Vec) -> Result, ScriptError> { let mut functions: Vec = Vec::new(); let mut now_func: Option = None; @@ -746,27 +1014,14 @@ fn cut_funcs(commands: &mut Vec) -> Vec { commands.remove(index); let name = command.args[1].clone(); - let result_type = match VarType::from_name(&command.args[0]) { - Some(i) => i, - None => { - continue; - } - }; + let result_type = VarType::from_name(&command.args[0])?; let mut parameters = HashMap::new(); let mut param_key: Option = None; for i in &command.args[2..] { match ¶m_key { Some(key) => { - parameters.insert( - key.to_string(), - match VarType::from_name(i) { - Some(i) => i, - None => { - continue; - } - }, - ); + parameters.insert(key.to_string(), VarType::from_name(i)?); param_key = None; } None => { @@ -781,7 +1036,7 @@ fn cut_funcs(commands: &mut Vec) -> Vec { } } - functions + Ok(functions) } pub struct Script { @@ -790,14 +1045,14 @@ pub struct Script { } impl Script { - pub fn parse(text: String) -> Script { + pub fn parse(text: String) -> Result { let lines = prepare_script(text); - let mut commands = parse_commands(lines); - let functions = cut_funcs(&mut commands); - Script { + let mut commands = parse_commands(lines)?; + let functions = cut_funcs(&mut commands)?; + Ok(Script { commands, functions, - } + }) } } @@ -821,84 +1076,228 @@ impl RunningScript { args: Vec, cout: Box, cin: Box, - ) { - self.variables.insert( + ) -> Result<(), ScriptError> { + self.set_var( String::from("args"), - Variable::List( - VarType::List(Box::new(VarType::String)), + Variable::from_list( Some( args.iter() - .map(|s| Variable::String(VarType::String, Some(s.to_string()))) + .map(|s| Variable::from_str(Some(s.to_string()))) .collect(), ), + VarType::String, ), - ); - self.variables.insert( + true, + &mut HashMap::new(), + )?; + self.set_var( String::from("cout"), - Variable::OutStream(VarType::OutStream, Some(Arc::new(Mutex::new(cout)))), - ); - self.variables.insert( + Variable::from_out_stream(Some(Arc::new(Mutex::new(cout)))), + true, + &mut HashMap::new(), + )?; + self.set_var( String::from("cin"), - Variable::InStream(VarType::InStream, Some(Arc::new(Mutex::new(cin)))), - ); + Variable::from_in_stream(Some(Arc::new(Mutex::new(cin)))), + true, + &mut HashMap::new(), + )?; + + Ok(()) } pub fn get_var( &mut self, name: String, locals: &mut HashMap, - ) -> Option { + ) -> Result { let mut var: Option = None; - for part in name.split(".") { - match &var { + for part in name.split('.') { + var = match &var { Some(v) => match v { - Variable::List(_, list) => match list { - Some(list) => { - let index: usize = part.parse().unwrap(); - var = match list.get(index) { - Some(i) => Some(i.clone()), - None => { - return None; - } - } - } - None => { - return None; - } - }, - Variable::Map(map_type, map) => match map { - Some(map) => { - var = map - .get( - &match Variable::parse_var(map_type.clone(), part.to_string()) { - Some(i) => i, - None => { - return None; - } - }, - ) - .cloned(); - } - None => { - return None; - } - }, - _ => {} - }, - None => match self.variables.get(part) { - Some(i) => var = Some(i.clone()), - None => match locals.get(part) { - Some(i) => var = Some(i.clone()), - None => { - return None; - } - }, + Variable::List(_, Some(list)) => { + let index: usize = part.parse().map_err(|_| ScriptError::ParseVarError)?; + Some(list.get(index).ok_or(ScriptError::UnknownVarError)?.clone()) + } + Variable::Map(map_type, Some(map)) => { + let key_var = Variable::parse_var(map_type.clone(), part.to_string())?; + map.get(&key_var).cloned() + } + _ => return Err(ScriptError::TypeMismatchError), }, + None => locals + .get(part) + .or_else(|| self.variables.get(part)) + .cloned(), + }; + } + + var.ok_or(ScriptError::UnknownVarError) + } + + pub fn drop_var( + &mut self, + name: String, + locals: &mut HashMap, + ) -> Result<(), ScriptError> { + let mut var: Option<&mut Variable> = None; + let parts: Vec<&str> = name.split('.').collect(); + + if parts.len() == 1 { + if locals.remove(&name).is_some() || self.variables.remove(&name).is_some() { + return Ok(()); + } else { + return Err(ScriptError::UnknownVarError); } } - var + for (i, part) in parts.iter().enumerate() { + if i == parts.len() - 1 { + match &mut var { + Some(v) => match v { + Variable::List(_, list) => match list { + Some(list) => { + let index: usize = + part.parse().map_err(|_| ScriptError::ParseVarError)?; + if index < list.len() { + list.remove(index); + return Ok(()); + } else { + return Err(ScriptError::UnknownVarError); + } + } + None => return Err(ScriptError::UnknownVarError), + }, + Variable::Map(map_type, map) => match map { + Some(map) => { + let key_var = + Variable::parse_var(map_type.clone(), part.to_string())?; + if map.remove(&key_var).is_some() { + return Ok(()); + } else { + return Err(ScriptError::UnknownVarError); + } + } + None => return Err(ScriptError::UnknownVarError), + }, + _ => return Err(ScriptError::TypeMismatchError), + }, + None => return Err(ScriptError::UnknownVarError), + } + } else { + var = match var { + Some(v) => match v { + Variable::List(_, list) => match list { + Some(list) => { + let index: usize = + part.parse().map_err(|_| ScriptError::ParseVarError)?; + Some(list.get_mut(index).ok_or(ScriptError::UnknownVarError)?) + } + None => return Err(ScriptError::UnknownVarError), + }, + Variable::Map(map_type, map) => match map { + Some(map) => { + let key_var = + Variable::parse_var(map_type.clone(), part.to_string())?; + map.get_mut(&key_var) + } + None => return Err(ScriptError::UnknownVarError), + }, + _ => return Err(ScriptError::TypeMismatchError), + }, + None => locals + .get_mut(*part) + .or_else(|| self.variables.get_mut(*part)), + }; + } + } + + Err(ScriptError::UnknownVarError) + } + + pub fn set_var( + &mut self, + name: String, + value: Variable, + global: bool, + locals: &mut HashMap, + ) -> Result<(), ScriptError> { + let mut var: Option<&mut Variable> = None; + let parts: Vec<&str> = name.split('.').collect(); + + if parts.len() == 1 { + if global { + self.variables.insert(name, value); + } else { + locals.insert(name.clone(), value.clone()); + } + return Ok(()); + } + + for (i, part) in parts.iter().enumerate() { + if i == parts.len() - 1 { + match &mut var { + Some(v) => match v { + Variable::List(_, list) => match list { + Some(list) => { + let index: usize = + part.parse().map_err(|_| ScriptError::ParseVarError)?; + if index < list.len() { + list[index] = value; + return Ok(()); + } else { + return Err(ScriptError::UnknownVarError); + } + } + None => return Err(ScriptError::UnknownVarError), + }, + Variable::Map(map_type, map) => match map { + Some(map) => { + let key_var = + Variable::parse_var(map_type.clone(), part.to_string())?; + map.insert(key_var, value); + return Ok(()); + } + None => return Err(ScriptError::UnknownVarError), + }, + _ => return Err(ScriptError::TypeMismatchError), + }, + None => return Err(ScriptError::UnknownVarError), + } + } else { + var = match var { + Some(v) => match v { + Variable::List(_, list) => match list { + Some(list) => { + let index: usize = + part.parse().map_err(|_| ScriptError::ParseVarError)?; + Some(list.get_mut(index).ok_or(ScriptError::UnknownVarError)?) + } + None => return Err(ScriptError::UnknownVarError), + }, + Variable::Map(map_type, map) => match map { + Some(map) => { + let key_var = + Variable::parse_var(map_type.clone(), part.to_string())?; + map.get_mut(&key_var) + } + None => return Err(ScriptError::UnknownVarError), + }, + _ => return Err(ScriptError::TypeMismatchError), + }, + None => { + if global { + self.variables.get_mut(*part) + } else { + locals.get_mut(*part) + } + } + } + } + } + + Err(ScriptError::UnknownVarError) } pub fn get_function(&self, name: String) -> Option { @@ -915,42 +1314,40 @@ impl RunningScript { commands: Vec, global: bool, locals: &mut HashMap, - ) { + ) -> Result<(), ScriptError> { 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).unwrap(); + let type_var = VarType::from_name(&type_var)?; let name_var = command.args[1].clone(); - self.variables - .insert(name_var, Variable::empty_var(type_var).unwrap()); + 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(" "); - let type_var = self.get_var(name_var.clone(), locals).unwrap().get_type(); - let var = Variable::parse_var(type_var, value_var).unwrap(); + let type_var = self + .get_var(name_var.clone(), &mut locals.clone())? + .get_type(); + let var = Variable::parse_var(type_var, value_var)?; - if self.variables.contains_key(&name_var) { - self.variables.insert(name_var, var); - } else if locals.contains_key(&name_var) { - locals.insert(name_var, 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.variables.insert( + self.set_var( name_var.clone(), - Variable::parse_var(VarType::from_name(&type_var).unwrap(), value_var) - .unwrap(), - ); + Variable::parse_var(VarType::from_name(&type_var)?, value_var)?, + global, + locals, + )?; temp_vars.push(name_var); @@ -960,177 +1357,88 @@ impl RunningScript { let source_var = command.args[0].clone(); let target_var = command.args[1].clone(); - let var = self.get_var(source_var.clone(), locals).unwrap(); + let var = self.get_var(source_var.clone(), locals)?; - if self.variables.contains_key(&source_var) { - self.variables.remove(&source_var); - } else if locals.contains_key(&source_var) { - locals.remove(&source_var); - } - - if self.variables.contains_key(&target_var) { - self.variables.insert(target_var, var); - } else if locals.contains_key(&target_var) { - locals.insert(target_var, var); - } + 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).unwrap(); + let var = self.get_var(source_var.clone(), locals)?; - if self.variables.contains_key(&target_var) { - self.variables.insert(target_var, var); - } else if locals.contains_key(&target_var) { - locals.insert(target_var, var); - } + self.set_var(target_var, var, global, locals)?; } CommandType::DropVar => { let name_var = command.args[0].clone(); - if self.variables.contains_key(&name_var) { - self.variables.remove(&name_var); - } else if locals.contains_key(&name_var) { - locals.remove(&name_var); - } + 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.variables.contains_key(&name_var) || locals.contains_key(&name_var); + let result = self.get_var(name_var, locals).is_ok(); - if self.variables.contains_key(&result_var) { - self.variables - .insert(name_var, Variable::Bool(VarType::Bool, Some(result))); - } else if locals.contains_key(&result_var) { - locals.insert(name_var, Variable::Bool(VarType::Bool, Some(result))); - } + 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).unwrap(); - let other_var = match other_var { - Variable::String(_, s) => match s { - Some(s) => s, - None => { - continue; - } - }, - Variable::Char(_, c) => match c { - Some(c) => String::from_utf8(vec![c]).unwrap(), - None => { - continue; - } - }, - Variable::List(list_type, list) => match list_type { - VarType::List(mut list_type) => match list_type.as_mut() { - VarType::Char => String::from_utf8( - match list { - Some(i) => i, - None => { - continue; - } - } - .iter() - .map(|f| match f { - Variable::Char(_, c) => match c { - Some(c) => *c, - None => 0u8, - }, - _ => 0u8, - }) - .collect(), - ) - .unwrap(), - _ => { - continue; - } - }, - _ => { - continue; - } - }, - _ => { - continue; + 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).unwrap(); - let var = match var { - Variable::String(t, s) => match s { - Some(s) => Variable::String(t, Some(s + &other_var)), - None => { - continue; - } - }, - _ => { - continue; - } - }; + let var = self.get_var(var_name.clone(), locals)?.as_str()?; - if self.variables.contains_key(&var_name) { - self.variables.insert(var_name, var); - } else if locals.contains_key(&var_name) { - locals.insert(var_name, var); - } + 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).unwrap(); - let text: Vec = match text { - Variable::List(list_type, list) => match list_type { - VarType::List(mut list_type) => match list_type.as_mut() { - VarType::Char => match list { - Some(i) => i, - None => { - continue; - } - } - .iter() - .map(|f| match f { - Variable::Char(_, c) => match c { - Some(c) => *c, - None => 0u8, - }, - _ => 0u8, - }) - .collect(), - _ => { - continue; - } - }, - _ => { - continue; - } - }, - Variable::String(_, text) => match text { - Some(i) => i.as_bytes().to_vec(), - None => { - continue; - } - }, - _ => { - continue; + 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).unwrap(); - match stream { - Variable::OutStream(_, stream) => match stream { - Some(stream) => { - stream.lock().unwrap().write_all(&text).unwrap(); - } - None => {} - }, - _ => {} - } + 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(); @@ -1138,17 +1446,24 @@ impl RunningScript { let args_names = command.args[2..].to_vec(); let func = self.get_function(func_name).unwrap(); - let args: Vec = args_names - .iter() - .map(|f| self.get_var(f.to_string(), locals).unwrap()) - .collect(); - self.exec_function(func, result_name, args) + 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; + return Ok(()); } CommandType::ToString => {} + CommandType::ToBytes => {} + CommandType::ToInteger => {} + CommandType::ToFloat => {} + CommandType::ToBool => {} + CommandType::ToChar => {} + CommandType::GetSymbol => {} CommandType::AddInt => {} CommandType::AddFloat => {} CommandType::SubStr => {} @@ -1158,7 +1473,21 @@ impl RunningScript { CommandType::ReadAll => {} CommandType::ReadStr => {} CommandType::ReadStrAll => {} - CommandType::For => {} + 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::ForMap => {} CommandType::ForList => {} CommandType::While => {} @@ -1187,9 +1516,16 @@ impl RunningScript { self.variables.remove(&ele); } } + + Ok(()) } - pub fn exec_function(&mut self, function: Function, result_var: String, args: Vec) { + pub fn exec_function( + &mut self, + function: Function, + result_var: String, + args: Vec, + ) -> Result<(), ScriptError> { let mut locals: HashMap = HashMap::new(); let mut index = 0; for (k, _) in function.parameters { @@ -1198,16 +1534,20 @@ impl RunningScript { } locals.insert( "result".to_string(), - Variable::empty_var(function.result_type).unwrap(), + Variable::empty_var(function.result_type)?, ); - self.exec_commands(function.commands, false, &mut locals); + self.exec_commands(function.commands, false, &mut locals)?; - self.variables - .insert(result_var, locals.get("result").unwrap().clone()); + if result_var != "null" { + self.variables + .insert(result_var, locals.get("result").unwrap().clone()); + } + + Ok(()) } - pub fn run(&mut self) { - self.exec_commands(self.commands.clone(), true, &mut HashMap::new()); + pub fn run(&mut self) -> Result<(), ScriptError> { + self.exec_commands(self.commands.clone(), true, &mut HashMap::new()) } } diff --git a/src/main.rs b/src/main.rs index 75e5e50..a22328e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,8 @@ use std::{ use sustlang::{RunningScript, Script}; fn main() { - let script = Script::parse(fs::read_to_string("test.sus").unwrap()); + let script = Script::parse(fs::read_to_string("test.sus").unwrap()).unwrap(); let mut running_script = RunningScript::new(script); running_script.set_standard_vars(args().collect(), Box::new(stdout()), Box::new(stdin())); - running_script.run() + running_script.run().unwrap(); } diff --git a/test.sus b/test.sus index 54ac7c8..657845d 100644 --- a/test.sus +++ b/test.sus @@ -1,4 +1,4 @@ -FUNC bool println text string # println command +FUNC null println text string # println command TEMP_VAR char br 10 # line break var ADD_STR text br # add line break to text var @@ -6,12 +6,15 @@ WRITE text cout # write text var to console FUNC_END # end println command +INIT_VAR string text +SET_VAR text Hello World! +FUNC null hello_world index integer -INIT_VAR string text # init text var -SET_VAR text Hello World! # set hello world to var +USE_FUNC println null text -TEMP_VAR bool result 0 # init temp result var -USE_FUNC println result text # use println to print text +FUNC_END -DROP_VAR text # drop text var +TEMP_VAR integer start_index 0 +TEMP_VAR integer end_index 9 +FOR hello_world start_index end_index