diff --git a/README.md b/README.md index 50faa88..3f427a9 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,12 @@ код хеллоу ворлда: ``` -INIT_VAR string text -SET_VAR text Hello World! -WRITE text cout -DROP_VAR text +INIT_VAR string text # init text var +SET_VAR text Hello World! # set text to var +TEMP_VAR char br 10 # create temp var with line break +ADD_STR text br # add line break to text +WRITE text cout # write text to console +DROP_VAR text # drop text var ``` @@ -21,39 +23,86 @@ WRITE text cout ## Команды +### Переменные + | Команда | Параметры | Описание | |--------------------------|------------|-------------| | `INIT_VAR` | `type_var`, `name_var` | Инициализировать переменную `name_var` с типом `type_var` | | `SET_VAR` | `name_var`, `value_var` | Установить значение переменной в `name_var` | -| `TEMP_VAR` | `type_var`, `name_var`, `value_var` | Переменная `name_var` инициализируется с типом `type_var` и присваивается `value_var`, переменная дропается после первого же использования | +| `TEMP_VAR` | `type_var`, `name_var`, `value_var` | Переменная `name_var` инициализируется с типом `type_var` и присваивается `value_var`, переменная дропается через одну команду | | `MOVE_VAR` | `source_var`, `target_var` | Переместить значение переменной с `source_var` в `target_var` | | `COPY_VAR` | `source_var`, `target_var` | Скопировать значение переменной с `source_var` в `target_var` | | `DROP_VAR` | `name_var` | Дропнуть переменную `name_var` | | `HAS_VAR` | `name_var`, `result_var` | В переменную `result_var` записывается `bool` существует ли переменная `name_var` | +| `LIST_SIZE` | `list_var`, `result_var` | Получить размер списка и записать в переменную `result_var` типа `int` | + +### Преобразование переменных + +| Команда | Параметры | Описание | +|--------------------------|------------|-------------| | `TO_STRING` | `source_var`, `target_var` | Скопировать значение переменной с `source_var` в `target_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]`) | | `SUB_STR` | `str_var`, `start_index`, `end_index` | Сделать подстроку из строки `str_var` и сохранить туда же | | `SUB_LIST` | `list_var`, `start_index`, `end_index` | Сделать подсписок из списка `list_var` и сохранить туда же | -| `LIST_SIZE` | `list_var`, `result_var` | Получить размер списка и записать в переменную `result_var` типа `int` | + +### Циклы + +| Команда | Параметры | Описание | +|--------------------------|------------|-------------| +| `FOR` | `func(int)`, `start_index`, `end_index` | Функция `func` (с единственным аргументом с типом `int`) вызывается с `start_index` до `end_index` включительно, `start_index` и `end_index` это названия переменных | +| `FOR_MAP` | `func(any, any)`, `map_var` | Функция `func` вызывается для каждого `key`, `value` переменной `map_var` | +| `FOR_LIST` | `func(any)`, `list_var` | Функция `func` вызывается для каждого предмета переменной `list_var` | +| `WHILE` | `func -> bool` | Функция `func` (с результатом `bool`) вызывается, пока функция выдает `true` | + +### Работа со стримами + +| Команда | Параметры | Описание | +|--------------------------|------------|-------------| | `WRITE` | `name_var`, `stream_var` | Вывести переменную `name_var` в `stream_var` | | `READ` | `name_var`, `size_var`, `stream_var` | Прочитать с `stream_var` ровно `size_var` байтов в переменную `name_var` типа `list[char]` | | `READ_ALL` | `name_var`, `stream_var` | Прочитать с `stream_var` все имеющиеся байты в переменную `name_var` типа `list[char]` | | `READ_STR` | `name_var`, `size_var`, `stream_var` | Прочитать с `stream_var` ровно `size_var` байтов в переменную `name_var` типа `string` | | `READ_STR_ALL` | `name_var`, `stream_var` | Прочитать с `stream_var` все имеющиеся байты в переменную `name_var` типа `string` | -| `FOR` | `func(int)`, `start_index`, `end_index` | Функция `func` (с единственным аргументом с типом `int`) вызывается с `start_index` до `end_index` включительно, `start_index` и `end_index` это названия переменных | -| `FOR_MAP` | `func(any, any)`, `map_var` | Функция `func` вызывается для каждого `key`, `value` переменной `map_var` | -| `FOR_LIST` | `func(any)`, `list_var` | Функция `func` вызывается для каждого предмета переменной `list_var` | -| `WHILE` | `func -> bool` | Функция `func` (с результатом `bool`) вызывается, пока функция выдает `true` | -| `USE_FUNC` | `func`, `result_var`, `[arg_var1] ... [arg_varN]` | Функция `func` вызывается с переданными аргументами и устанавливает результат в переменную `result_var` | | `OPEN_FILE_IN` | `path_var`, `stream_var` | Открыть файл по пути `path_var` (`path_var`, `stream_var` - переменные) для чтения и записать стрим для чтения в переменную `stream_var` | | `OPEN_FILE_OUT` | `path_var`, `stream_var` | Открыть файл по пути `path_var` (`path_var`, `stream_var` - переменные) для записи и записать стрим для записи в переменную `stream_var` | | `OPEN_TCP_CONNECTION` | `addr_var`, `port_var`, `in_stream`, `out_stream` | Подключиться по `addr_var:port_var` (`addr_var: string`, `port_var: int`, `in_stream: in_stream`, `out_stream: out_stream` - переменные) и записать стримы для чтения и записи в `in_stream` и `out_stream` | | `OPEN_TCP_LISTENER` | `addr_var`, `port_var`, `accept_func(string,int,in_stream,out_stream)` | Ожидание подключений с `addr_var:port_var` (`addr_var: string`, `port_var: int` - переменные), при подключениях вызывается функция `accept_func` | -| `HAS_OPTIONAL` | `optional_var`, `result_var` | Узнать, имеет ли данные опшнл `optional_var` и записать результат в `result_var: bool` | -| `WHEN_OPTIONAL` | `optional_var`, `func(option[any])` | Когда опшнл `optional_var` имеет данные, вызывается `func` | -| `SLEEP` | `time_var` | Ждать миллисекунд из переменной `time_var` (тип переменной: int) | + +### Логические операции + +| Команда | Параметры | Описание | +|--------------------------|------------|-------------| +| `EQUALS` | `var`, `other_var`, `result_var` | Узнать, равен ли `var` и `other_var` записать результат в `result_var` | +| `MORE` | `var`, `other_var`, `result_var` | Узнать, больше ли в `var` чем в `other_var` записать результат в `result_var` | +| `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` | +| `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` | +| `HAS_ENTRY` | `map_var`, `key_var`, `value_var`, `result_var` | Узнать, имеет ли мап `map_var` поле с ключом `key_var` и значением `value_var` и записать результат в `result_var` | +| `HAS_KEY` | `map_var`, `key_var`, `result_var` | Узнать, имеет ли мап `map_var` поле с ключом `key_var` и записать результат в `result_var` | +| `HAS_VALUE` | `map_var`, `value_var`, `result_var` | Узнать, имеет ли мап `map_var` поле с значением `value_var` и записать результат в `result_var` | +| `HAS_OPTIONAL` | `optional_var`, `result_var` | Узнать, имеет ли данные опшнл `optional_var` и записать результат в `result_var` | + + +### Функции + +| Команда | Параметры | Описание | +|--------------------------|------------|-------------| +| `USE_FUNC` | `func_name`, `result_var`, `[arg_var1] ... [arg_varN]` | Функция `func` вызывается с переданными аргументами и устанавливает результат в переменную `result_var` | +| `FUNC` | `result_type`, `func_name`, `[arg_name_1 arg_type] ... [arg_name_N arg_type]` | Создать функцию с типом результата `result_type`, названием `func_name` и аргументами `[arg_name_1 arg_type] ... [arg_name_N arg_type]`. Установить результат переменной можно изменив переменную `result` внутри функции. Все команды после этой и до `FUNC_END` будут командами функции. Функции внутри функций не могут быть. | +| `RETURN` | | Досрочно выйти из функции, также работает как выход из скрипта | +| `FUNC_END` | | Маркер, что команды функции тут заканчиваются | + +### Прочее + +| Команда | Параметры | Описание | +|--------------------------|------------|-------------| +| `SLEEP` | `time_var` | Ждать миллисекунд из переменной `time_var` (тип переменной: int) | +| `NEW_THREAD` | `func` | Вызвать функцию `func` в новом потоке | ## Типы переменных diff --git a/src/lib.rs b/src/lib.rs index 5214f0d..87465b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,6 +91,21 @@ pub enum Variable { } impl Variable { + pub fn get_type(&self) -> VarType { + match self { + Variable::Bool(t, _) => t.clone(), + Variable::String(t, _) => t.clone(), + Variable::Integer(t, _) => t.clone(), + Variable::Float(t, _) => t.clone(), + Variable::Char(t, _) => t.clone(), + Variable::List(t, _) => t.clone(), + Variable::Map(t, _) => t.clone(), + Variable::Optional(t, _) => t.clone(), + Variable::InStream(t, _) => t.clone(), + Variable::OutStream(t, _) => t.clone(), + } + } + pub fn empty_var(var_type: VarType) -> Option { match var_type { VarType::Bool => Some(Variable::Bool(VarType::Bool, None)), @@ -309,38 +324,273 @@ impl PartialEq for Variable { #[derive(PartialEq, Clone, Debug, Copy, Hash)] pub enum CommandType { + /// Инициализировать переменную `name_var` с типом `type_var` + /// + /// Название: INIT_VAR + /// Параметры: `type_var`, `name_var` InitVar, + + /// Установить значение переменной в `name_var` + /// + /// Название: SET_VAR + /// Параметры: `name_var`, `value_var` SetVar, + + /// Переменная `name_var` инициализируется с типом `type_var` и присваивается `value_var`, переменная дропается через одну команду + /// + /// Название: TEMP_VAR + /// Параметры: `type_var`, `name_var`, `value_var` TempVar, + + /// Переместить значение переменной с `source_var` в `target_var` + /// + /// Название: MOVE_VAR + /// Параметры: `source_var`, `target_var` MoveVar, + + /// Скопировать значение переменной с `source_var` в `target_var` + /// + /// Название: COPY_VAR + /// Параметры: `source_var`, `target_var` CopyVar, + + /// Дропнуть переменную `name_var` + /// + /// Название: DROP_VAR + /// Параметры: `name_var` DropVar, + + /// В переменную `result_var` записывается `bool` существует ли переменная `name_var` + /// + /// Название: HAS_VAR + /// Параметры: `name_var`, `result_var` HasVar, + + /// Скопировать значение переменной с `source_var` в `target_var`, переводя в строку + /// + /// Название: TO_STRING + /// Параметры: `source_var`, `target_var` ToString, + + /// Прибавить к числу `var` значение `other_var` + /// + /// Название: ADD_INT + /// Параметры: `var`, `other_var` AddInt, + + /// Прибавить к числу `var` значение `other_var` + /// + /// Название: ADD_FLOAT + /// Параметры: `var`, `other_var` AddFloat, + + /// Прибавить к числу `var` значение `other_var` + /// + /// Название: ADD_STR + /// Параметры: `var`, `other_var` + AddStr, + + /// Сделать подстроку из строки `str_var` и сохранить туда же + /// + /// Название: SUB_STR + /// Параметры: `str_var`, `start_index`, `end_index` SubStr, + + /// Сделать подсписок из списка `list_var` и сохранить туда же + /// + /// Название: SUB_LIST + /// Параметры: `list_var`, `start_index`, `end_index` SubList, + + /// Получить размер списка и записать в переменную `result_var` типа `int` + /// + /// Название: LIST_SIZE + /// Параметры: `list_var`, `result_var` ListSize, + + /// Вывести переменную `name_var` в `stream_var` + /// + /// Название: WRITE + /// Параметры: `name_var`, `stream_var` Write, + + /// Прочитать с `stream_var` ровно `size_var` байтов в переменную `name_var` типа `list[char]` + /// + /// Название: READ + /// Параметры: `name_var`, `size_var`, `stream_var` Read, + + /// Прочитать с `stream_var` все имеющиеся байты в переменную `name_var` типа `list[char]` + /// + /// Название: READ_ALL + /// Параметры: `name_var`, `stream_var` ReadAll, + + /// Прочитать с `stream_var` ровно `size_var` байтов в переменную `name_var` типа `string` + /// + /// Название: READ_STR + /// Параметры: `name_var`, `size_var`, `stream_var` ReadStr, + + /// Прочитать с `stream_var` все имеющиеся байты в переменную `name_var` типа `string` + /// + /// Название: READ_STR_ALL + /// Параметры: `name_var`, `stream_var` ReadStrAll, + + /// Функция `func` (с единственным аргументом с типом `int`) вызывается с `start_index` до `end_index` включительно, `start_index` и `end_index` это названия переменных + /// + /// Название: FOR + /// Параметры: `func(int)`, `start_index`, `end_index` For, + + /// Функция `func` вызывается для каждого `key`, `value` переменной `map_var` + /// + /// Название: FOR_MAP + /// Параметры: `func(any, any)`, `map_var` ForMap, + + /// Функция `func` вызывается для каждого предмета переменной `list_var` + /// + /// Название: FOR_LIST + /// Параметры: `func(any)`, `list_var` ForList, + + /// Функция `func` (с результатом `bool`) вызывается, пока функция выдает `true` + /// + /// Название: WHILE + /// Параметры: `func -> bool` While, - UseFunc, + + /// Открыть файл по пути `path_var` (`path_var`, `stream_var` - переменные) для чтения и записать стрим для чтения в переменную `stream_var` + /// + /// Название: OPEN_FILE_IN + /// Параметры: `path_var`, `stream_var` OpenFileIn, + + /// Открыть файл по пути `path_var` (`path_var`, `stream_var` - переменные) для записи и записать стрим для записи в переменную `stream_var` + /// + /// Название: 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 + /// Параметры: `addr_var`, `port_var`, `in_stream`, `out_stream` OpenTcpConnection, + + /// Ожидание подключений с `addr_var:port_var` (`addr_var: string`, `port_var: int` - переменные), при подключениях вызывается функция `accept_func` + /// + /// Название: OPEN_TCP_LISTENER + /// Параметры: `addr_var`, `port_var`, `accept_func(string,int,in_stream,out_stream)` OpenTcpListener, - HasOptional, - WhenOptional, + + /// Ждать миллисекунд из переменной `time_var` (тип переменной: int) + /// + /// Название: SLEEP + /// Параметры: `time_var` Sleep, + + /// Вызвать функцию `func` в новом потоке + /// + /// Название: NEW_THREAD + /// Параметры: `func` + NewThread, + + /// Функция `func` вызывается с переданными аргументами и устанавливает результат в переменную `result_var` + /// + /// Название: 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 + /// Параметры: `result_type`, `func_name`, `[arg_name_1 arg_type] ... [arg_name_N arg_type]` Func, + + /// Досрочно выйти из функции, также работает как выход из скрипта + /// + /// Название: RETURN + Return, + + /// Маркер, что команды функции тут заканчиваются + /// + /// Название: FUNC_END FuncEnd, + + /// Узнать, равен ли `var` и `other_var` записать результат в `result_var` + /// + /// Название: EQUALS + /// Параметры: `var`, `other_var`, `result_var` + Equals, + + /// Узнать, больше ли в `var` чем в `other_var` записать результат в `result_var` + /// + /// Название: MORE + /// Параметры: `var`, `other_var`, `result_var` + More, + + /// Узнать, меньше ли в `var` чем в `other_var` записать результат в `result_var` + /// + /// Название: LESS + /// Параметры: `var`, `other_var`, `result_var` + Less, + + /// Если `var` и `other_var` равны `true`, то результат `true`, иначе `false`, записать результат в `result_var` + /// + /// Название: AND + /// Параметры: `var`, `other_var`, `result_var` + And, + + /// Если `var` или `other_var` равен `true`, то результат `true`, иначе `false`, записать результат в `result_var` + /// + /// Название: OR + /// Параметры: `var`, `other_var`, `result_var` + Or, + + /// Если `var` равен `true` то вызвать функцию `func` + /// + /// Название: IF + /// Параметры: `bool_var`, `func` + If, + + /// Узнать, имеет ли строка `var` в себе подстроку `substring` и записать результат в `result_var` + /// + /// Название: HAS_STR + /// Параметры: `string_var`, `substring`, `result_var` + HasStr, + + /// Узнать, имеет ли список `list_var` значение `item_var` и записать результат в `result_var` + /// + /// Название: HAS_ITEM + /// Параметры: `list_var`, `item_var`, `result_var` + HasItem, + + /// Узнать, имеет ли мап `map_var` поле с ключом `key_var` и значением `value_var` и записать результат в `result_var` + /// + /// Название: HAS_ENTRY + /// Параметры: `map_var`, `key_var`, `value_var`, `result_var` + HasEntry, + + /// Узнать, имеет ли мап `map_var` поле с ключом `key_var` и записать результат в `result_var` + /// + /// Название: HAS_KEY + /// Параметры: `map_var`, `key_var`, `result_var` + HasKey, + + /// Узнать, имеет ли мап `map_var` поле с значением `value_var` и записать результат в `result_var` + /// + /// Название: HAS_VALUE + /// Параметры: `map_var`, `value_var`, `result_var` + HasValue, + + /// Узнать, имеет ли данные опшнл `optional_var` и записать результат в `result_var` + /// + /// Название: HAS_OPTIONAL + /// Параметры: `optional_var`, `result_var` + HasOptional, } impl CommandType { @@ -356,6 +606,7 @@ impl CommandType { "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), @@ -368,16 +619,28 @@ impl CommandType { "FOR_MAP" => Some(CommandType::ForMap), "FOR_LIST" => Some(CommandType::ForList), "WHILE" => Some(CommandType::While), - "USE_FUNC" => Some(CommandType::UseFunc), "OPEN_FILE_IN" => Some(CommandType::OpenFileIn), "OPEN_FILE_OUT" => Some(CommandType::OpenFileOut), "OPEN_TCP_CONNECTION" => Some(CommandType::OpenTcpConnection), "OPEN_TCP_LISTENER" => Some(CommandType::OpenTcpListener), - "HAS_OPTIONAL" => Some(CommandType::HasOptional), - "WHEN_OPTIONAL" => Some(CommandType::WhenOptional), "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, } } @@ -426,7 +689,7 @@ fn prepare_script(text: String) -> Vec { None => s, }) .filter(|s| !s.trim().is_empty()) - .map(|s| s.to_string()) + .map(|s| s.trim_end_matches(" ").to_string()) .collect() } @@ -640,52 +903,270 @@ impl RunningScript { var } - pub fn exec_command( + pub fn exec_commands( &mut self, - command: Command, + commands: Vec, global: bool, locals: &mut HashMap, ) { - match command.command_type { - CommandType::InitVar => { - // TODO: for hello world + 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 name_var = command.args[1].clone(); + + self.variables + .insert(name_var, Variable::empty_var(type_var).unwrap()); + } + 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(); + + 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); + } + } + 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( + name_var.clone(), + Variable::parse_var(VarType::from_name(&type_var).unwrap(), value_var) + .unwrap(), + ); + + 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).unwrap(); + + 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); + } + } + 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(); + + 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); + } + } + 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); + } + } + 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); + + 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))); + } + } + CommandType::ToString => {} + CommandType::AddInt => {} + CommandType::AddFloat => {} + 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 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; + } + }; + + 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); + } + } + CommandType::SubStr => {} + CommandType::SubList => {} + CommandType::ListSize => {} + 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 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 => {} + }, + _ => {} + } + } + CommandType::Read => {} + CommandType::ReadAll => {} + CommandType::ReadStr => {} + CommandType::ReadStrAll => {} + CommandType::For => {} + CommandType::ForMap => {} + CommandType::ForList => {} + CommandType::While => {} + CommandType::OpenFileIn => {} + CommandType::OpenFileOut => {} + CommandType::OpenTcpConnection => {} + CommandType::OpenTcpListener => {} + CommandType::Sleep => {} + CommandType::NewThread => {} + CommandType::UseFunc => {} + CommandType::Return => { + return; + } + CommandType::Equals => {} + CommandType::More => {} + CommandType::Less => {} + CommandType::And => {} + CommandType::Or => {} + CommandType::If => {} + CommandType::HasStr => {} + CommandType::HasItem => {} + CommandType::HasEntry => {} + CommandType::HasKey => {} + CommandType::HasValue => {} + CommandType::HasOptional => {} + _ => {} } - CommandType::SetVar => { - // TODO: for hello world + + for ele in temp_vars.clone() { + self.variables.remove(&ele); } - CommandType::TempVar => { - // TODO: for hello world - } - CommandType::MoveVar => {} - CommandType::CopyVar => {} - CommandType::DropVar => {} - CommandType::HasVar => {} - CommandType::ToString => {} - CommandType::AddInt => {} - CommandType::AddFloat => {} - CommandType::SubStr => {} - CommandType::SubList => {} - CommandType::ListSize => {} - CommandType::Write => { - // TODO: for hello world - } - CommandType::Read => {} - CommandType::ReadAll => {} - CommandType::ReadStr => {} - CommandType::ReadStrAll => {} - CommandType::For => {} - CommandType::ForMap => {} - CommandType::ForList => {} - CommandType::While => {} - CommandType::UseFunc => {} - CommandType::OpenFileIn => {} - CommandType::OpenFileOut => {} - CommandType::OpenTcpConnection => {} - CommandType::OpenTcpListener => {} - CommandType::HasOptional => {} - CommandType::WhenOptional => {} - CommandType::Sleep => {} - _ => {} } } @@ -701,17 +1182,13 @@ impl RunningScript { Variable::empty_var(function.result_type).unwrap(), ); - for command in function.commands.clone() { - self.exec_command(command, false, &mut locals); - } + self.exec_commands(function.commands, false, &mut locals); self.variables .insert(result_var, locals.get("result").unwrap().clone()); } pub fn run(&mut self) { - for command in self.commands.clone() { - self.exec_command(command, true, &mut HashMap::new()); - } + self.exec_commands(self.commands.clone(), true, &mut HashMap::new()); } } diff --git a/src/main.rs b/src/main.rs index f328e4d..75e5e50 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1 +1,14 @@ -fn main() {} +use std::{ + env::args, + fs, + io::{stdin, stdout}, +}; + +use sustlang::{RunningScript, Script}; + +fn main() { + let script = Script::parse(fs::read_to_string("test.sus").unwrap()); + let mut running_script = RunningScript::new(script); + running_script.set_standard_vars(args().collect(), Box::new(stdout()), Box::new(stdin())); + running_script.run() +} diff --git a/test.sus b/test.sus index e69de29..67f4929 100644 --- a/test.sus +++ b/test.sus @@ -0,0 +1,6 @@ +INIT_VAR string text # init text var +SET_VAR text Hello World! # set text to var +TEMP_VAR char br 10 # create temp var with line break +ADD_STR text br # add line break to text +WRITE text cout # write text to console +DROP_VAR text # drop text var