mirror of
https://github.com/MeexReay/sustlang.git
synced 2025-06-24 10:33:01 +03:00
writing wow ezezez
This commit is contained in:
parent
28ed2c1b54
commit
b29952bec8
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sustlang"
|
||||||
|
version = "0.1.0"
|
17
README.md
17
README.md
@ -28,9 +28,9 @@ WRITE text cout
|
|||||||
| `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` |
|
| `MOVE_VAR` | `source_var`, `target_var` | Переместить значение переменной с `source_var` в `target_var` |
|
||||||
| `COPY_VAR` | `source_var`, `target_var` | Скопировать значение переменной с `source_var` в `target_var` |
|
| `COPY_VAR` | `source_var`, `target_var` | Скопировать значение переменной с `source_var` в `target_var` |
|
||||||
| `TO_STR_VAR` | `source_var`, `target_var` | Скопировать значение переменной с `source_var` в `target_var`, переводя в строку |
|
|
||||||
| `DROP_VAR` | `name_var` | Дропнуть переменную `name_var` |
|
| `DROP_VAR` | `name_var` | Дропнуть переменную `name_var` |
|
||||||
| `HAS_VAR` | `name_var`, `result_var` | В переменную `result_var` записывается `bool` существует ли переменная `name_var` |
|
| `HAS_VAR` | `name_var`, `result_var` | В переменную `result_var` записывается `bool` существует ли переменная `name_var` |
|
||||||
|
| `TO_STRING` | `source_var`, `target_var` | Скопировать значение переменной с `source_var` в `target_var`, переводя в строку |
|
||||||
| `ADD_INT` | `int_var1`, `int_var2` | Прибавить к числу `int_var1` значение `int_var2` |
|
| `ADD_INT` | `int_var1`, `int_var2` | Прибавить к числу `int_var1` значение `int_var2` |
|
||||||
| `ADD_FLOAT` | `float_var1`, `float_var2` | Прибавить к числу `float_var1` значение `float_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]`) |
|
| `ADD_STR` | `str_var`, `value_var` | Прибавить к строке `str_var` значение `value_var` (может быть типа `string/char/list[char]`) |
|
||||||
@ -42,17 +42,18 @@ WRITE text cout
|
|||||||
| `READ_ALL` | `name_var`, `stream_var` | Прочитать с `stream_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` | `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` |
|
| `READ_STR_ALL` | `name_var`, `stream_var` | Прочитать с `stream_var` все имеющиеся байты в переменную `name_var` типа `string` |
|
||||||
| `FOR` | `func`, `start_index`, `end_index` | Функция `func` (с единственным аргументом с типом `int`) вызывается с `start_index` до `end_index` включительно, `start_index` и `end_index` это названия переменных |
|
| `FOR` | `func(int)`, `start_index`, `end_index` | Функция `func` (с единственным аргументом с типом `int`) вызывается с `start_index` до `end_index` включительно, `start_index` и `end_index` это названия переменных |
|
||||||
| `FOR_MAP` | `func`, `map_var` | Функция `func` (с двумя аргументами с типами мапы) вызывается для каждого `key`, `value` переменной `map_var` |
|
| `FOR_MAP` | `func(any, any)`, `map_var` | Функция `func` вызывается для каждого `key`, `value` переменной `map_var` |
|
||||||
| `FOR_LIST` | `func`, `list_var` | Функция `func` (с единственным аргументом с типом списка) вызывается для каждого предмета переменной `list_var` |
|
| `FOR_LIST` | `func(any)`, `list_var` | Функция `func` вызывается для каждого предмета переменной `list_var` |
|
||||||
| `WHILE` | `func` | Функция `func` (с результатом `bool`) вызывается, пока функция выдает `true` |
|
| `WHILE` | `func -> bool` | Функция `func` (с результатом `bool`) вызывается, пока функция выдает `true` |
|
||||||
| `USE_FUNC` | `func`, `result_var`, `[arg_var1] ... [arg_varN]` | Функция `func` вызывается с переданными аргументами и устанавливает результат в переменную `result_var` |
|
| `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_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_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_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` | Ожидание подключений с `addr_var:port_var` (`addr_var: string`, `port_var: int` - переменные), при подключениях вызывается функция `accept_func` с четырьмя аргументами `in_stream: in_stream` и `out_stream: out_stream` и `addr_var: string` и `port_var: int` |
|
| `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` |
|
| `HAS_OPTIONAL` | `optional_var`, `result_var` | Узнать, имеет ли данные опшнл `optional_var` и записать результат в `result_var: bool` |
|
||||||
| `WHEN_OPTIONAL` | `optional_var`, `func` | Когда опшнл `optional_var` имеет данные, вызывается `func` с единственным аргументом типа опшнла |
|
| `WHEN_OPTIONAL` | `optional_var`, `func(option[any])` | Когда опшнл `optional_var` имеет данные, вызывается `func` |
|
||||||
|
| `SLEEP` | `time_var` | Ждать миллисекунд из переменной `time_var` (тип переменной: int) |
|
||||||
|
|
||||||
## Типы переменных
|
## Типы переменных
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ WRITE text cout
|
|||||||
| `float` | `SET_VAR var 14.48` | `14.48` |
|
| `float` | `SET_VAR var 14.48` | `14.48` |
|
||||||
| `char` | `SET_VAR var 255` | `0 - 255` |
|
| `char` | `SET_VAR var 255` | `0 - 255` |
|
||||||
| `list[type]` | `SET_VAR var.0 value` | `value` |
|
| `list[type]` | `SET_VAR var.0 value` | `value` |
|
||||||
| `map[key_type value_type]` | `SET_VAR var.key value` | `value` |
|
| `map[key_type,value_type]` | `SET_VAR var.key value` | `value` |
|
||||||
| `optional[type]` | `SET_VAR var (value)` | `(value)` / `null` |
|
| `optional[type]` | `SET_VAR var (value)` | `(value)` / `null` |
|
||||||
| `in_stream` | `OPEN_FILE_IN path var` | |
|
| `in_stream` | `OPEN_FILE_IN path var` | |
|
||||||
| `out_stream` | `OPEN_FILE_OUT path var` | |
|
| `out_stream` | `OPEN_FILE_OUT path var` | |
|
||||||
|
717
src/lib.rs
Normal file
717
src/lib.rs
Normal file
@ -0,0 +1,717 @@
|
|||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
hash::Hash,
|
||||||
|
io::{Read, Write},
|
||||||
|
ptr::hash,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Debug, Hash)]
|
||||||
|
pub enum VarType {
|
||||||
|
Bool,
|
||||||
|
String,
|
||||||
|
Integer,
|
||||||
|
Float,
|
||||||
|
Char,
|
||||||
|
List(Box<VarType>),
|
||||||
|
Map(Box<VarType>, Box<VarType>),
|
||||||
|
Optional(Box<VarType>),
|
||||||
|
InStream,
|
||||||
|
OutStream,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VarType {
|
||||||
|
pub fn from_name(name: &str) -> Option<VarType> {
|
||||||
|
if name.starts_with("map[") {
|
||||||
|
let value_type = name[9..name.len() - 1].to_string();
|
||||||
|
|
||||||
|
let mut key_type = String::new();
|
||||||
|
let mut val_type = String::new();
|
||||||
|
|
||||||
|
let mut val_tree = 0;
|
||||||
|
let mut val_stat = 0;
|
||||||
|
for char in value_type.chars() {
|
||||||
|
if val_stat == 0 {
|
||||||
|
key_type.push(char);
|
||||||
|
} else if val_stat == 1 {
|
||||||
|
val_type.push(char);
|
||||||
|
}
|
||||||
|
if char == ',' && val_tree == 0 {
|
||||||
|
val_stat += 1;
|
||||||
|
}
|
||||||
|
if char == '[' {
|
||||||
|
val_tree += 1;
|
||||||
|
}
|
||||||
|
if char == ']' {
|
||||||
|
val_tree -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Variable {
|
||||||
|
Bool(VarType, Option<bool>),
|
||||||
|
String(VarType, Option<String>),
|
||||||
|
Integer(VarType, Option<isize>),
|
||||||
|
Float(VarType, Option<f64>),
|
||||||
|
Char(VarType, Option<u8>),
|
||||||
|
List(VarType, Option<Vec<Variable>>),
|
||||||
|
Map(VarType, Option<HashMap<Variable, Variable>>),
|
||||||
|
Optional(VarType, Option<Option<Box<Variable>>>),
|
||||||
|
InStream(VarType, Option<Arc<Mutex<dyn Read>>>),
|
||||||
|
OutStream(VarType, Option<Arc<Mutex<dyn Write>>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Variable {
|
||||||
|
pub fn empty_var(var_type: VarType) -> Option<Variable> {
|
||||||
|
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::Optional(optional_type) => {
|
||||||
|
Some(Variable::Optional(VarType::Optional(optional_type), None))
|
||||||
|
}
|
||||||
|
VarType::List(value_type) => Some(Variable::List(VarType::List(value_type), None)),
|
||||||
|
VarType::Map(key_type, value_type) => {
|
||||||
|
Some(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)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_var(var_type: VarType, text: String) -> Option<Variable> {
|
||||||
|
match var_type {
|
||||||
|
VarType::Bool => Some(Variable::Bool(
|
||||||
|
VarType::Bool,
|
||||||
|
Some(match text.as_str() {
|
||||||
|
"true" => true,
|
||||||
|
"false" => false,
|
||||||
|
"1" => true,
|
||||||
|
"0" => false,
|
||||||
|
_ => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
VarType::String => Some(Variable::String(VarType::String, Some(text))),
|
||||||
|
VarType::Integer => Some(Variable::Integer(
|
||||||
|
VarType::Integer,
|
||||||
|
Some(match text.parse() {
|
||||||
|
Ok(i) => i,
|
||||||
|
Err(_) => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
VarType::Float => Some(Variable::Float(
|
||||||
|
VarType::Float,
|
||||||
|
Some(match text.parse() {
|
||||||
|
Ok(i) => i,
|
||||||
|
Err(_) => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
VarType::Char => Some(Variable::Char(
|
||||||
|
VarType::Char,
|
||||||
|
Some(match text.parse() {
|
||||||
|
Ok(i) => i,
|
||||||
|
Err(_) => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
VarType::Optional(optional_type) => {
|
||||||
|
if text.starts_with("[") && text.ends_with("]") {
|
||||||
|
let text = text[1..text.len() - 1].to_string();
|
||||||
|
Some(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,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
} else if text.as_str() == "none" {
|
||||||
|
Some(Variable::Optional(
|
||||||
|
VarType::Optional(optional_type),
|
||||||
|
Some(None),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Variable {}
|
||||||
|
impl Hash for Variable {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
match self {
|
||||||
|
Variable::Bool(_, value) => {
|
||||||
|
value.hash(state);
|
||||||
|
}
|
||||||
|
Variable::String(_, value) => {
|
||||||
|
value.hash(state);
|
||||||
|
}
|
||||||
|
Variable::Integer(_, value) => {
|
||||||
|
value.hash(state);
|
||||||
|
}
|
||||||
|
Variable::Float(_, value) => {
|
||||||
|
hash(value, state);
|
||||||
|
}
|
||||||
|
Variable::Char(_, value) => {
|
||||||
|
value.hash(state);
|
||||||
|
}
|
||||||
|
Variable::List(_, value) => {
|
||||||
|
value.hash(state);
|
||||||
|
}
|
||||||
|
Variable::Map(_, value) => {
|
||||||
|
hash(value, state);
|
||||||
|
}
|
||||||
|
Variable::Optional(_, value) => {
|
||||||
|
value.hash(state);
|
||||||
|
}
|
||||||
|
Variable::InStream(_, value) => {
|
||||||
|
hash(value, state);
|
||||||
|
}
|
||||||
|
Variable::OutStream(_, value) => {
|
||||||
|
hash(value, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PartialEq for Variable {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match self {
|
||||||
|
Variable::Bool(_, value) => match other {
|
||||||
|
Variable::Bool(_, other_value) => value == other_value,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
Variable::String(_, value) => match other {
|
||||||
|
Variable::String(_, other_value) => value == other_value,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
Variable::Integer(_, value) => match other {
|
||||||
|
Variable::Integer(_, other_value) => value == other_value,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
Variable::Float(_, value) => match other {
|
||||||
|
Variable::Float(_, other_value) => value == other_value,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
Variable::Char(_, value) => match other {
|
||||||
|
Variable::Char(_, other_value) => value == other_value,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
Variable::List(_, value) => match other {
|
||||||
|
Variable::List(_, other_value) => value == other_value,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
Variable::Map(_, value) => match other {
|
||||||
|
Variable::Map(_, other_value) => match value {
|
||||||
|
Some(value) => match other_value {
|
||||||
|
Some(other_value) => {
|
||||||
|
if other_value.len() == value.len() {
|
||||||
|
let mut ovi = other_value.iter();
|
||||||
|
let mut vi = value.iter();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let Some((ok, ov)) = ovi.next() else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
let Some((k, v)) = vi.next() else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if k != ok || v != ov {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => false,
|
||||||
|
},
|
||||||
|
None => match other_value {
|
||||||
|
Some(_) => false,
|
||||||
|
None => true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
Variable::Optional(_, value) => match other {
|
||||||
|
Variable::Optional(_, other_value) => other_value == value,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
Variable::InStream(_, value) => match other {
|
||||||
|
Variable::InStream(_, other_value) => match value {
|
||||||
|
Some(value) => match other_value {
|
||||||
|
Some(other_value) => Arc::ptr_eq(value, other_value),
|
||||||
|
None => false,
|
||||||
|
},
|
||||||
|
None => match other_value {
|
||||||
|
Some(_) => false,
|
||||||
|
None => true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
Variable::OutStream(_, value) => match other {
|
||||||
|
Variable::OutStream(_, other_value) => match value {
|
||||||
|
Some(value) => match other_value {
|
||||||
|
Some(other_value) => Arc::ptr_eq(value, other_value),
|
||||||
|
None => false,
|
||||||
|
},
|
||||||
|
None => match other_value {
|
||||||
|
Some(_) => false,
|
||||||
|
None => true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Debug, Copy, Hash)]
|
||||||
|
pub enum CommandType {
|
||||||
|
InitVar,
|
||||||
|
SetVar,
|
||||||
|
TempVar,
|
||||||
|
MoveVar,
|
||||||
|
CopyVar,
|
||||||
|
DropVar,
|
||||||
|
HasVar,
|
||||||
|
ToString,
|
||||||
|
AddInt,
|
||||||
|
AddFloat,
|
||||||
|
SubStr,
|
||||||
|
SubList,
|
||||||
|
ListSize,
|
||||||
|
Write,
|
||||||
|
Read,
|
||||||
|
ReadAll,
|
||||||
|
ReadStr,
|
||||||
|
ReadStrAll,
|
||||||
|
For,
|
||||||
|
ForMap,
|
||||||
|
ForList,
|
||||||
|
While,
|
||||||
|
UseFunc,
|
||||||
|
OpenFileIn,
|
||||||
|
OpenFileOut,
|
||||||
|
OpenTcpConnection,
|
||||||
|
OpenTcpListener,
|
||||||
|
HasOptional,
|
||||||
|
WhenOptional,
|
||||||
|
Sleep,
|
||||||
|
Func,
|
||||||
|
FuncEnd,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandType {
|
||||||
|
pub fn from_name(name: &str) -> Option<CommandType> {
|
||||||
|
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),
|
||||||
|
"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),
|
||||||
|
"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),
|
||||||
|
"FUNC" => Some(CommandType::Func),
|
||||||
|
"FUNC_END" => Some(CommandType::FuncEnd),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
|
pub struct Command {
|
||||||
|
command_type: CommandType,
|
||||||
|
args: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command {
|
||||||
|
pub fn new(command_type: CommandType, args: Vec<String>) -> Command {
|
||||||
|
Command { command_type, args }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
|
pub struct Function {
|
||||||
|
name: String,
|
||||||
|
result_type: VarType,
|
||||||
|
parameters: HashMap<String, VarType>,
|
||||||
|
commands: Vec<Command>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
pub fn new(
|
||||||
|
name: String,
|
||||||
|
result_type: VarType,
|
||||||
|
parameters: HashMap<String, VarType>,
|
||||||
|
commands: Vec<Command>,
|
||||||
|
) -> Function {
|
||||||
|
Function {
|
||||||
|
name,
|
||||||
|
result_type,
|
||||||
|
parameters,
|
||||||
|
commands,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_script(text: String) -> Vec<String> {
|
||||||
|
text.lines()
|
||||||
|
.map(|s| match s.split_once("#") {
|
||||||
|
Some(s) => s.0,
|
||||||
|
None => s,
|
||||||
|
})
|
||||||
|
.filter(|s| !s.trim().is_empty())
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_commands(lines: Vec<String>) -> Vec<Command> {
|
||||||
|
let mut commands = Vec::new();
|
||||||
|
|
||||||
|
for line in lines {
|
||||||
|
let params: Vec<String> = line.split(" ").map(|v| v.to_string()).collect();
|
||||||
|
|
||||||
|
let command_type = match CommandType::from_name(¶ms[0]) {
|
||||||
|
Some(i) => i,
|
||||||
|
None => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let args = if params.is_empty() {
|
||||||
|
Vec::new()
|
||||||
|
} else {
|
||||||
|
params[1..].to_vec()
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.push(Command::new(command_type, args))
|
||||||
|
}
|
||||||
|
|
||||||
|
commands
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cut_funcs(commands: &mut Vec<Command>) -> Vec<Function> {
|
||||||
|
let mut functions: Vec<Function> = Vec::new();
|
||||||
|
|
||||||
|
let mut now_func = None;
|
||||||
|
|
||||||
|
let mut index = 0;
|
||||||
|
for command in commands.clone() {
|
||||||
|
match now_func.clone() {
|
||||||
|
Some(mut func) => {
|
||||||
|
if command.command_type == CommandType::FuncEnd {
|
||||||
|
commands.remove(index);
|
||||||
|
index -= 1;
|
||||||
|
|
||||||
|
functions.push(func);
|
||||||
|
now_func = None;
|
||||||
|
} else {
|
||||||
|
commands.remove(index);
|
||||||
|
index -= 1;
|
||||||
|
|
||||||
|
func.commands.push(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if command.command_type == CommandType::Func {
|
||||||
|
commands.remove(index);
|
||||||
|
index -= 1;
|
||||||
|
|
||||||
|
let name = command.args[0].clone();
|
||||||
|
let result_type = match VarType::from_name(&command.args[1]) {
|
||||||
|
Some(i) => i,
|
||||||
|
None => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut parameters = HashMap::new();
|
||||||
|
|
||||||
|
let mut param_key: Option<String> = 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;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
param_key = None;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
param_key = Some(i.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
now_func = Some(Function::new(name, result_type, parameters, Vec::new()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
functions
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Script {
|
||||||
|
commands: Vec<Command>,
|
||||||
|
functions: Vec<Function>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Script {
|
||||||
|
pub fn parse(text: String) -> Script {
|
||||||
|
let lines = prepare_script(text);
|
||||||
|
let mut commands = parse_commands(lines);
|
||||||
|
let functions = cut_funcs(&mut commands);
|
||||||
|
Script {
|
||||||
|
commands,
|
||||||
|
functions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RunningScript {
|
||||||
|
commands: Vec<Command>,
|
||||||
|
functions: Vec<Function>,
|
||||||
|
variables: HashMap<String, Variable>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunningScript {
|
||||||
|
pub fn new(script: Script) -> RunningScript {
|
||||||
|
RunningScript {
|
||||||
|
commands: script.commands,
|
||||||
|
functions: script.functions,
|
||||||
|
variables: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_standard_vars(
|
||||||
|
&mut self,
|
||||||
|
args: Vec<String>,
|
||||||
|
cout: Box<dyn Write>,
|
||||||
|
cin: Box<dyn Read>,
|
||||||
|
) {
|
||||||
|
self.variables.insert(
|
||||||
|
String::from("args"),
|
||||||
|
Variable::List(
|
||||||
|
VarType::List(Box::new(VarType::String)),
|
||||||
|
Some(
|
||||||
|
args.iter()
|
||||||
|
.map(|s| Variable::String(VarType::String, Some(s.to_string())))
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
self.variables.insert(
|
||||||
|
String::from("cout"),
|
||||||
|
Variable::OutStream(VarType::OutStream, Some(Arc::new(Mutex::new(cout)))),
|
||||||
|
);
|
||||||
|
self.variables.insert(
|
||||||
|
String::from("cin"),
|
||||||
|
Variable::InStream(VarType::InStream, Some(Arc::new(Mutex::new(cin)))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_var(
|
||||||
|
&mut self,
|
||||||
|
name: String,
|
||||||
|
locals: &mut HashMap<String, Variable>,
|
||||||
|
) -> Option<Variable> {
|
||||||
|
let mut var: Option<Variable> = None;
|
||||||
|
|
||||||
|
for part in name.split(".") {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exec_command(
|
||||||
|
&mut self,
|
||||||
|
command: Command,
|
||||||
|
global: bool,
|
||||||
|
locals: &mut HashMap<String, Variable>,
|
||||||
|
) {
|
||||||
|
match command.command_type {
|
||||||
|
CommandType::InitVar => {
|
||||||
|
// TODO: for hello world
|
||||||
|
}
|
||||||
|
CommandType::SetVar => {
|
||||||
|
// TODO: for hello world
|
||||||
|
}
|
||||||
|
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 => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exec_function(&mut self, function: Function, result_var: String, args: Vec<Variable>) {
|
||||||
|
let mut locals: HashMap<String, Variable> = HashMap::new();
|
||||||
|
let mut index = 0;
|
||||||
|
for (k, _) in function.parameters {
|
||||||
|
locals.insert(k, args[index].clone());
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
locals.insert(
|
||||||
|
"result".to_string(),
|
||||||
|
Variable::empty_var(function.result_type).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
for command in function.commands.clone() {
|
||||||
|
self.exec_command(command, 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1 @@
|
|||||||
fn main() {
|
fn main() {}
|
||||||
println!("Hello, world!");
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user