mirror of
https://github.com/MeexReay/sustlang.git
synced 2025-06-24 10:33:01 +03:00
cleanup (without imports)
This commit is contained in:
parent
f0857049cb
commit
cc4b5bc6c9
2508
src/lib.rs
2508
src/lib.rs
File diff suppressed because it is too large
Load Diff
973
src/sustlang/command/command.rs
Normal file
973
src/sustlang/command/command.rs
Normal file
@ -0,0 +1,973 @@
|
|||||||
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
|
pub struct Command {
|
||||||
|
command_type: CommandType,
|
||||||
|
args: Vec<String>,
|
||||||
|
line: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command {
|
||||||
|
pub fn new(command_type: CommandType, line: usize, args: Vec<String>) -> Command {
|
||||||
|
Command {
|
||||||
|
command_type,
|
||||||
|
args,
|
||||||
|
line,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(
|
||||||
|
&self,
|
||||||
|
global: bool,
|
||||||
|
locals: &mut HashMap<String, Variable>,
|
||||||
|
globals: &mut HashMap<String, Variable>,
|
||||||
|
temp_vars: &mut Vec<String>,
|
||||||
|
) -> Result<(), ScriptError> {
|
||||||
|
match command.command_type {
|
||||||
|
CommandType::InitVar => {
|
||||||
|
let type_var = command.args[0].clone();
|
||||||
|
let type_var = VarType::from_name(&type_var)?;
|
||||||
|
let name_var = command.args[1].clone();
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
name_var,
|
||||||
|
Variable::empty_var(type_var)?,
|
||||||
|
global,
|
||||||
|
true,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::SetVar => {
|
||||||
|
let name_var = command.args[0].clone();
|
||||||
|
let value_var = command.args[1..].join(" ");
|
||||||
|
|
||||||
|
let type_var = self
|
||||||
|
.get_var(name_var.clone(), &mut locals.clone())?
|
||||||
|
.get_type();
|
||||||
|
let var = Variable::parse_var(type_var, value_var)?;
|
||||||
|
|
||||||
|
self.set_var(name_var, var, global, false, locals)?;
|
||||||
|
}
|
||||||
|
CommandType::TempVar => {
|
||||||
|
let type_var = command.args[0].clone();
|
||||||
|
let name_var = command.args[1].clone();
|
||||||
|
let value_var = command.args[2..].join(" ");
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
name_var.clone(),
|
||||||
|
Variable::parse_var(VarType::from_name(&type_var)?, value_var)?,
|
||||||
|
global,
|
||||||
|
true,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
temp_vars.push(name_var);
|
||||||
|
}
|
||||||
|
CommandType::MoveVar => {
|
||||||
|
let source_var = command.args[0].clone();
|
||||||
|
let target_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let var = self.get_var(source_var.clone(), locals)?;
|
||||||
|
|
||||||
|
self.set_var(target_var, var, global, false, locals)?;
|
||||||
|
self.drop_var(source_var, locals)?;
|
||||||
|
}
|
||||||
|
CommandType::CopyVar => {
|
||||||
|
let source_var = command.args[0].clone();
|
||||||
|
let target_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let var = self.get_var(source_var.clone(), locals)?;
|
||||||
|
|
||||||
|
self.set_var(target_var, var, global, false, locals)?;
|
||||||
|
}
|
||||||
|
CommandType::DropVar => {
|
||||||
|
let name_var = command.args[0].clone();
|
||||||
|
|
||||||
|
self.drop_var(name_var, locals)?;
|
||||||
|
}
|
||||||
|
CommandType::HasVar => {
|
||||||
|
let name_var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let result = self.get_var(name_var, locals).is_ok();
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(result)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::AddStr => {
|
||||||
|
let var_name = command.args[0].clone();
|
||||||
|
let other_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let other_var = self.get_var(other_var.clone(), locals)?;
|
||||||
|
let other_var: String = if let Variable::List(VarType::Char, Some(list)) = other_var
|
||||||
|
{
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
for ele in list {
|
||||||
|
bytes.push(ele.as_char()?);
|
||||||
|
}
|
||||||
|
String::from_utf8(bytes).or(Err(ScriptError::StringUTF8Error))?
|
||||||
|
} else if let Variable::String(_, Some(string)) = other_var {
|
||||||
|
string
|
||||||
|
} else if let Variable::Char(_, Some(value)) = other_var {
|
||||||
|
String::from_utf8(vec![value]).or(Err(ScriptError::StringUTF8Error))?
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
};
|
||||||
|
|
||||||
|
let var = self.get_var(var_name.clone(), locals)?.as_str()?;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
var_name,
|
||||||
|
Variable::from_str(Some(var + &other_var)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::Write => {
|
||||||
|
let name_var = command.args[0].clone();
|
||||||
|
let stream_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let text = self.get_var(name_var.clone(), locals)?;
|
||||||
|
let text: Vec<u8> = if let Variable::List(VarType::Char, Some(list)) = text {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
for ele in list {
|
||||||
|
bytes.push(ele.as_char()?);
|
||||||
|
}
|
||||||
|
bytes
|
||||||
|
} else if let Variable::String(_, Some(string)) = text {
|
||||||
|
string.as_bytes().to_vec()
|
||||||
|
} else if let Variable::Char(_, Some(value)) = text {
|
||||||
|
vec![value]
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
};
|
||||||
|
|
||||||
|
let stream = self.get_var(stream_var.clone(), locals)?.as_out_stream()?;
|
||||||
|
stream.lock().unwrap().write_all(&text).unwrap();
|
||||||
|
}
|
||||||
|
CommandType::UseFunc => {
|
||||||
|
let func_name = command.args[0].clone();
|
||||||
|
let result_name = command.args[1].clone();
|
||||||
|
let args_names = command.args[2..].to_vec();
|
||||||
|
|
||||||
|
let func = self.get_function(func_name).unwrap();
|
||||||
|
|
||||||
|
let mut args = Vec::new();
|
||||||
|
for name in args_names {
|
||||||
|
args.push(self.get_var(name, locals)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.exec_function(func, result_name, args)?;
|
||||||
|
}
|
||||||
|
CommandType::Return => {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
CommandType::For => {
|
||||||
|
let func_name = command.args[0].clone();
|
||||||
|
let start_index = self.get_var(command.args[1].clone(), locals)?.as_int()?;
|
||||||
|
let end_index = self.get_var(command.args[2].clone(), locals)?.as_int()?;
|
||||||
|
|
||||||
|
let func = self.get_function(func_name).unwrap();
|
||||||
|
|
||||||
|
for index in start_index..=end_index {
|
||||||
|
self.exec_function(
|
||||||
|
func.clone(),
|
||||||
|
"null".to_string(),
|
||||||
|
vec![Variable::from_int(Some(index))],
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CommandType::ToString => {
|
||||||
|
let source_var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let source_var = self.get_var(source_var, locals)?;
|
||||||
|
|
||||||
|
let result = source_var.to_string()?;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_str(Some(result)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::ToChars => {
|
||||||
|
let source_var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let source_var = self.get_var(source_var, locals)?;
|
||||||
|
|
||||||
|
let result = source_var
|
||||||
|
.as_str()?
|
||||||
|
.as_bytes()
|
||||||
|
.iter()
|
||||||
|
.map(|f| Variable::from_char(Some(*f)))
|
||||||
|
.collect();
|
||||||
|
let result =
|
||||||
|
Variable::from_list(Some(result), VarType::List(Box::new(VarType::Char)));
|
||||||
|
|
||||||
|
self.set_var(result_var, result, global, false, locals)?;
|
||||||
|
}
|
||||||
|
CommandType::ToInteger => {
|
||||||
|
let source_var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let source_var = self.get_var(source_var, locals)?;
|
||||||
|
|
||||||
|
let result = source_var
|
||||||
|
.as_str()?
|
||||||
|
.parse::<isize>()
|
||||||
|
.or(Err(ScriptError::ParseVarError))?;
|
||||||
|
let result = Variable::from_int(Some(result));
|
||||||
|
|
||||||
|
self.set_var(result_var, result, global, false, locals)?;
|
||||||
|
}
|
||||||
|
CommandType::ToFloat => {
|
||||||
|
let source_var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let source_var = self.get_var(source_var, locals)?;
|
||||||
|
|
||||||
|
let result = source_var
|
||||||
|
.as_str()?
|
||||||
|
.parse::<f64>()
|
||||||
|
.or(Err(ScriptError::ParseVarError))?;
|
||||||
|
let result = Variable::from_float(Some(result));
|
||||||
|
|
||||||
|
self.set_var(result_var, result, global, false, locals)?;
|
||||||
|
}
|
||||||
|
CommandType::ToBool => {
|
||||||
|
let source_var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let source_var = self.get_var(source_var, locals)?;
|
||||||
|
|
||||||
|
let result = if let Variable::List(_, Some(value)) = source_var {
|
||||||
|
!value.is_empty()
|
||||||
|
} else if let Variable::String(_, Some(value)) = source_var {
|
||||||
|
value == "true" || value == "1"
|
||||||
|
} else if let Variable::Char(_, Some(value)) = source_var {
|
||||||
|
value != 0
|
||||||
|
} else if let Variable::Integer(_, Some(value)) = source_var {
|
||||||
|
value != 0
|
||||||
|
} else if let Variable::Float(_, Some(value)) = source_var {
|
||||||
|
value != 0.0
|
||||||
|
} else if let Variable::Bool(_, Some(value)) = source_var {
|
||||||
|
value
|
||||||
|
} else if let Variable::Map(_, Some(value)) = source_var {
|
||||||
|
!value.is_empty()
|
||||||
|
} else if let Variable::Optional(_, Some(value)) = source_var {
|
||||||
|
value.is_some()
|
||||||
|
} else if let Variable::Null(_) = source_var {
|
||||||
|
false
|
||||||
|
} else if let Variable::OutStream(_, Some(_)) = source_var {
|
||||||
|
true
|
||||||
|
} else if let Variable::InStream(_, Some(_)) = source_var {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(result)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::ToChar => {
|
||||||
|
let source_var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let source_var = self.get_var(source_var, locals)?;
|
||||||
|
|
||||||
|
let result = if let Variable::String(_, Some(value)) = source_var {
|
||||||
|
value.as_bytes()[0]
|
||||||
|
} else if let Variable::Char(_, Some(value)) = source_var {
|
||||||
|
value
|
||||||
|
} else if let Variable::Integer(_, Some(value)) = source_var {
|
||||||
|
value as u8
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_char(Some(result)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::GetSymbol => {
|
||||||
|
let str_var = command.args[0].clone();
|
||||||
|
let index_var = command.args[1].clone();
|
||||||
|
let result_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let str_var = self.get_var(str_var, locals)?;
|
||||||
|
let index_var = self.get_var(index_var, locals)?;
|
||||||
|
|
||||||
|
let index = index_var.as_int()?;
|
||||||
|
|
||||||
|
let result = if let Variable::String(_, Some(value)) = str_var {
|
||||||
|
value.as_bytes()[index as usize]
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_char(Some(result)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::GetItem => {
|
||||||
|
let list_var = command.args[0].clone();
|
||||||
|
let index_var = command.args[1].clone();
|
||||||
|
let result_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let list_var = self.get_var(list_var, locals)?;
|
||||||
|
let index_var = self.get_var(index_var, locals)?;
|
||||||
|
|
||||||
|
let index = index_var.as_int()?;
|
||||||
|
|
||||||
|
let result = if let Variable::List(_, Some(value)) = list_var {
|
||||||
|
value[index as usize].clone()
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.set_var(result_var, result, global, false, locals)?;
|
||||||
|
}
|
||||||
|
CommandType::GetValue => {
|
||||||
|
let map_var = command.args[0].clone();
|
||||||
|
let key_var = command.args[1].clone();
|
||||||
|
let result_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let map_var = self.get_var(map_var, locals)?;
|
||||||
|
let key_var = self.get_var(key_var, locals)?;
|
||||||
|
|
||||||
|
let result = if let Variable::Map(_, Some(value)) = map_var {
|
||||||
|
value[&key_var].clone()
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.set_var(result_var, result, global, false, locals)?;
|
||||||
|
}
|
||||||
|
CommandType::ListSize => {
|
||||||
|
let list_var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let list_var = self.get_var(list_var, locals)?;
|
||||||
|
let list_size = list_var.as_list()?.len();
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_int(Some(list_size as isize)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::MapSize => {
|
||||||
|
let map_var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let map_var = self.get_var(map_var, locals)?;
|
||||||
|
let map_size = map_var.as_list()?.len();
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_int(Some(map_size as isize)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::StringSize => {
|
||||||
|
let string_var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let string_var = self.get_var(string_var, locals)?;
|
||||||
|
let string_size = string_var.as_list()?.len();
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_int(Some(string_size as isize)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::ForMap => {
|
||||||
|
let func_name = command.args[0].clone();
|
||||||
|
let map_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let map_var = self.get_var(map_var, locals)?;
|
||||||
|
let map_var = map_var.as_map()?;
|
||||||
|
|
||||||
|
let func = self.get_function(func_name).unwrap();
|
||||||
|
|
||||||
|
for (k, v) in map_var {
|
||||||
|
self.exec_function(func.clone(), "null".to_string(), vec![k, v])?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CommandType::ForList => {
|
||||||
|
let func_name = command.args[0].clone();
|
||||||
|
let list_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let list_var = self.get_var(list_var, locals)?;
|
||||||
|
let list_var = list_var.as_list()?;
|
||||||
|
|
||||||
|
let func = self.get_function(func_name).unwrap();
|
||||||
|
|
||||||
|
for i in list_var {
|
||||||
|
self.exec_function(func.clone(), "null".to_string(), vec![i])?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CommandType::ForString => {
|
||||||
|
let func_name = command.args[0].clone();
|
||||||
|
let string_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let string_var = self.get_var(string_var, locals)?;
|
||||||
|
let string_var = string_var.as_str()?;
|
||||||
|
|
||||||
|
let func = self.get_function(func_name).unwrap();
|
||||||
|
|
||||||
|
for c in string_var.as_bytes() {
|
||||||
|
self.exec_function(
|
||||||
|
func.clone(),
|
||||||
|
"null".to_string(),
|
||||||
|
vec![Variable::from_char(Some(*c))],
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CommandType::While => {
|
||||||
|
let func_name = command.args[0].clone();
|
||||||
|
|
||||||
|
let func = self.get_function(func_name).unwrap();
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
"while".to_string(),
|
||||||
|
Variable::from_bool(Some(true)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
while self.get_var("while".to_string(), locals)?.as_bool()? {
|
||||||
|
self.exec_function(func.clone(), "while".to_string(), vec![])?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CommandType::Equals => {
|
||||||
|
let var = command.args[0].clone();
|
||||||
|
let other_var = command.args[1].clone();
|
||||||
|
let result_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let var = self.get_var(var, locals)?;
|
||||||
|
let other_var = self.get_var(other_var, locals)?;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(var == other_var)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::More => {
|
||||||
|
let var = command.args[0].clone();
|
||||||
|
let other_var = command.args[1].clone();
|
||||||
|
let result_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let var = self.get_var(var, locals)?;
|
||||||
|
let other_var = self.get_var(other_var, locals)?;
|
||||||
|
|
||||||
|
let result = if let Variable::Float(_, Some(v1)) = var {
|
||||||
|
if let Variable::Float(_, Some(v2)) = other_var {
|
||||||
|
v1 > v2
|
||||||
|
} else if let Variable::Integer(_, Some(v2)) = other_var {
|
||||||
|
v1 > v2 as f64
|
||||||
|
} else if let Variable::Char(_, Some(v2)) = other_var {
|
||||||
|
v1 > v2 as f64
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
}
|
||||||
|
} else if let Variable::Integer(_, Some(v1)) = var {
|
||||||
|
if let Variable::Float(_, Some(v2)) = other_var {
|
||||||
|
v1 as f64 > v2
|
||||||
|
} else if let Variable::Integer(_, Some(v2)) = other_var {
|
||||||
|
v1 > v2
|
||||||
|
} else if let Variable::Char(_, Some(v2)) = other_var {
|
||||||
|
v1 > v2 as isize
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
}
|
||||||
|
} else if let Variable::Char(_, Some(v1)) = var {
|
||||||
|
if let Variable::Float(_, Some(v2)) = other_var {
|
||||||
|
v1 as f64 > v2
|
||||||
|
} else if let Variable::Integer(_, Some(v2)) = other_var {
|
||||||
|
v1 as isize > v2
|
||||||
|
} else if let Variable::Char(_, Some(v2)) = other_var {
|
||||||
|
v1 > v2
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(result)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::Less => {
|
||||||
|
let var = command.args[0].clone();
|
||||||
|
let other_var = command.args[1].clone();
|
||||||
|
let result_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let var = self.get_var(var, locals)?;
|
||||||
|
let other_var = self.get_var(other_var, locals)?;
|
||||||
|
|
||||||
|
let result = if let Variable::Float(_, Some(v1)) = var {
|
||||||
|
if let Variable::Float(_, Some(v2)) = other_var {
|
||||||
|
v1 < v2
|
||||||
|
} else if let Variable::Integer(_, Some(v2)) = other_var {
|
||||||
|
v1 < v2 as f64
|
||||||
|
} else if let Variable::Char(_, Some(v2)) = other_var {
|
||||||
|
v1 < v2 as f64
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
}
|
||||||
|
} else if let Variable::Integer(_, Some(v1)) = var {
|
||||||
|
if let Variable::Float(_, Some(v2)) = other_var {
|
||||||
|
(v1 as f64) < v2
|
||||||
|
} else if let Variable::Integer(_, Some(v2)) = other_var {
|
||||||
|
v1 < v2
|
||||||
|
} else if let Variable::Char(_, Some(v2)) = other_var {
|
||||||
|
v1 < v2 as isize
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
}
|
||||||
|
} else if let Variable::Char(_, Some(v1)) = var {
|
||||||
|
if let Variable::Float(_, Some(v2)) = other_var {
|
||||||
|
(v1 as f64) < v2
|
||||||
|
} else if let Variable::Integer(_, Some(v2)) = other_var {
|
||||||
|
(v1 as isize) < v2
|
||||||
|
} else if let Variable::Char(_, Some(v2)) = other_var {
|
||||||
|
v1 < v2
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(result)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::And => {
|
||||||
|
let var = command.args[0].clone();
|
||||||
|
let other_var = command.args[1].clone();
|
||||||
|
let result_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let var = self.get_var(var, locals)?.as_bool()?;
|
||||||
|
let other_var = self.get_var(other_var, locals)?.as_bool()?;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(var && other_var)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::Or => {
|
||||||
|
let var = command.args[0].clone();
|
||||||
|
let other_var = command.args[1].clone();
|
||||||
|
let result_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let var = self.get_var(var, locals)?.as_bool()?;
|
||||||
|
let other_var = self.get_var(other_var, locals)?.as_bool()?;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(var || other_var)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::Not => {
|
||||||
|
let var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let var = self.get_var(var, locals)?.as_bool()?;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(!var)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::If => {
|
||||||
|
let bool_var = command.args[0].clone();
|
||||||
|
let func_name = command.args[1].clone();
|
||||||
|
|
||||||
|
let func = self.get_function(func_name).unwrap();
|
||||||
|
|
||||||
|
let bool_var = self.get_var(bool_var, locals)?.as_bool()?;
|
||||||
|
|
||||||
|
if bool_var {
|
||||||
|
self.exec_function(func, "null".to_string(), vec![])?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CommandType::HasStr => {
|
||||||
|
let string_var = command.args[0].clone();
|
||||||
|
let substring = command.args[1].clone();
|
||||||
|
let result_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let string_var = self.get_var(string_var, locals)?.as_str()?;
|
||||||
|
let substring = self.get_var(substring, locals)?.as_str()?;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(string_var.contains(&substring))),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::HasItem => {
|
||||||
|
let list_var = command.args[0].clone();
|
||||||
|
let item_var = command.args[1].clone();
|
||||||
|
let result_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let list_var = self.get_var(list_var, locals)?.as_list()?;
|
||||||
|
let item_var = self.get_var(item_var, locals)?;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(list_var.contains(&item_var))),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::HasEntry => {
|
||||||
|
let map_var = command.args[0].clone();
|
||||||
|
let key_var = command.args[1].clone();
|
||||||
|
let value_var = command.args[2].clone();
|
||||||
|
let result_var = command.args[3].clone();
|
||||||
|
|
||||||
|
let map_var = self.get_var(map_var, locals)?.as_map()?;
|
||||||
|
let key_var = self.get_var(key_var, locals)?;
|
||||||
|
let value_var = self.get_var(value_var, locals)?;
|
||||||
|
|
||||||
|
let mut has = false;
|
||||||
|
|
||||||
|
for (k, v) in map_var {
|
||||||
|
if k == key_var && v == value_var {
|
||||||
|
has = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(has)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::HasKey => {
|
||||||
|
let map_var = command.args[0].clone();
|
||||||
|
let key_var = command.args[1].clone();
|
||||||
|
let result_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let map_var = self.get_var(map_var, locals)?.as_map()?;
|
||||||
|
let key_var = self.get_var(key_var, locals)?;
|
||||||
|
|
||||||
|
let mut has = false;
|
||||||
|
|
||||||
|
for (k, _) in map_var {
|
||||||
|
if k == key_var {
|
||||||
|
has = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(has)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::HasValue => {
|
||||||
|
let map_var = command.args[0].clone();
|
||||||
|
let value_var = command.args[1].clone();
|
||||||
|
let result_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let map_var = self.get_var(map_var, locals)?.as_map()?;
|
||||||
|
let value_var = self.get_var(value_var, locals)?;
|
||||||
|
|
||||||
|
let mut has = false;
|
||||||
|
|
||||||
|
for (_, v) in map_var {
|
||||||
|
if v == value_var {
|
||||||
|
has = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(has)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::HasOptional => {
|
||||||
|
let optional_var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let optional_var = self.get_var(optional_var, locals)?.as_option()?;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
Variable::from_bool(Some(optional_var.is_some())),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::UnpackOptional => {
|
||||||
|
let optional_var = command.args[0].clone();
|
||||||
|
let result_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let optional_var = self.get_var(optional_var, locals)?.as_option()?;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
result_var,
|
||||||
|
optional_var
|
||||||
|
.ok_or(ScriptError::ParseVarError)?
|
||||||
|
.as_mut()
|
||||||
|
.clone(),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::Sleep => {
|
||||||
|
let time_var = command.args[0].clone();
|
||||||
|
|
||||||
|
let time_var = match self.get_var(time_var, locals)? {
|
||||||
|
Variable::Integer(_, Some(v)) => Duration::from_millis(v as u64),
|
||||||
|
Variable::Float(_, Some(v)) => Duration::from_millis(v as u64),
|
||||||
|
_ => {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
thread::sleep(time_var);
|
||||||
|
}
|
||||||
|
CommandType::AddInt => {
|
||||||
|
let var_name = command.args[0].clone();
|
||||||
|
let other_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let other_var = self.get_var(other_var, locals)?.as_int()?;
|
||||||
|
let var = self.get_var(var_name.clone(), locals)?.as_int()?;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
var_name,
|
||||||
|
Variable::from_int(Some(var + other_var)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::AddFloat => {
|
||||||
|
let var_name = command.args[0].clone();
|
||||||
|
let other_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let other_var = self.get_var(other_var, locals)?.as_float()?;
|
||||||
|
let var = self.get_var(var_name.clone(), locals)?.as_float()?;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
var_name,
|
||||||
|
Variable::from_float(Some(var + other_var)),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::SubStr => {
|
||||||
|
let str_var_name = command.args[0].clone();
|
||||||
|
let start_index = command.args[1].clone();
|
||||||
|
let end_index = command.args[1].clone();
|
||||||
|
|
||||||
|
let str_var = self.get_var(str_var_name.clone(), locals)?.as_str()?;
|
||||||
|
let start_index = self.get_var(start_index, locals)?.as_int()? as usize;
|
||||||
|
let end_index = self.get_var(end_index, locals)?.as_int()? as usize;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
str_var_name,
|
||||||
|
Variable::from_str(Some(str_var[start_index..end_index].to_string())),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::SubList => {
|
||||||
|
let list_var_name = command.args[0].clone();
|
||||||
|
let start_index = command.args[1].clone();
|
||||||
|
let end_index = command.args[1].clone();
|
||||||
|
|
||||||
|
let list_var = self.get_var(list_var_name.clone(), locals)?;
|
||||||
|
let start_index = self.get_var(start_index, locals)?.as_int()? as usize;
|
||||||
|
let end_index = self.get_var(end_index, locals)?.as_int()? as usize;
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
list_var_name,
|
||||||
|
Variable::from_list(
|
||||||
|
Some(list_var.as_list()?[start_index..end_index].to_vec()),
|
||||||
|
list_var.get_type(),
|
||||||
|
),
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::Read => {
|
||||||
|
let name_var = command.args[0].clone();
|
||||||
|
let size_var = command.args[1].clone();
|
||||||
|
let stream_var = command.args[2].clone();
|
||||||
|
|
||||||
|
let var = self.get_var(name_var.clone(), locals)?;
|
||||||
|
let size_var = self.get_var(size_var.clone(), locals)?.as_int()?;
|
||||||
|
let stream = self.get_var(stream_var.clone(), locals)?.as_in_stream()?;
|
||||||
|
|
||||||
|
let mut buffer: Vec<u8> = Vec::with_capacity(size_var as usize);
|
||||||
|
stream.lock().unwrap().read_exact(&mut buffer).unwrap();
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
name_var,
|
||||||
|
match var {
|
||||||
|
Variable::List(VarType::Char, _) => Variable::from_list(
|
||||||
|
Some(
|
||||||
|
buffer
|
||||||
|
.iter()
|
||||||
|
.map(|f| Variable::from_char(Some(*f)))
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
VarType::List(Box::new(VarType::Char)),
|
||||||
|
),
|
||||||
|
Variable::String(_, _) => Variable::from_str(Some(
|
||||||
|
String::from_utf8(buffer).or(Err(ScriptError::StringUTF8Error))?,
|
||||||
|
)),
|
||||||
|
_ => {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::ReadAll => {
|
||||||
|
let name_var = command.args[0].clone();
|
||||||
|
let stream_var = command.args[1].clone();
|
||||||
|
|
||||||
|
let var = self.get_var(name_var.clone(), locals)?;
|
||||||
|
let stream = self.get_var(stream_var.clone(), locals)?.as_in_stream()?;
|
||||||
|
|
||||||
|
let mut buffer: Vec<u8> = Vec::new();
|
||||||
|
stream.lock().unwrap().read_to_end(&mut buffer).unwrap();
|
||||||
|
|
||||||
|
self.set_var(
|
||||||
|
name_var,
|
||||||
|
match var {
|
||||||
|
Variable::List(VarType::Char, _) => Variable::from_list(
|
||||||
|
Some(
|
||||||
|
buffer
|
||||||
|
.iter()
|
||||||
|
.map(|f| Variable::from_char(Some(*f)))
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
VarType::List(Box::new(VarType::Char)),
|
||||||
|
),
|
||||||
|
Variable::String(_, _) => Variable::from_str(Some(
|
||||||
|
String::from_utf8(buffer).or(Err(ScriptError::StringUTF8Error))?,
|
||||||
|
)),
|
||||||
|
_ => {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
global,
|
||||||
|
false,
|
||||||
|
locals,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
CommandType::OpenFileIn => {
|
||||||
|
let path_var = command.args[0].clone();
|
||||||
|
let stream_var = command.args[1].clone();
|
||||||
|
|
||||||
|
// TODO: write logic
|
||||||
|
}
|
||||||
|
CommandType::OpenFileOut => {
|
||||||
|
let path_var = command.args[0].clone();
|
||||||
|
let stream_var = command.args[1].clone();
|
||||||
|
|
||||||
|
// TODO: write logic
|
||||||
|
}
|
||||||
|
CommandType::OpenTcpConnection => {
|
||||||
|
let addr_var = command.args[0].clone();
|
||||||
|
let port_var = command.args[1].clone();
|
||||||
|
let in_stream = command.args[2].clone();
|
||||||
|
let out_stream = command.args[3].clone();
|
||||||
|
|
||||||
|
// TODO: write logic
|
||||||
|
}
|
||||||
|
CommandType::OpenTcpListener => {
|
||||||
|
let addr_var = command.args[0].clone();
|
||||||
|
let port_var = command.args[1].clone();
|
||||||
|
let accept_func = command.args[2].clone();
|
||||||
|
|
||||||
|
// TODO: write logic
|
||||||
|
}
|
||||||
|
CommandType::NewThread => {
|
||||||
|
let func_name = command.args[0].clone();
|
||||||
|
|
||||||
|
// TODO: write logic
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
400
src/sustlang/command/command_type.rs
Normal file
400
src/sustlang/command/command_type.rs
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
#[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` в `result_var`, переводя в `string`
|
||||||
|
///
|
||||||
|
/// Название: TO_STRING \
|
||||||
|
/// Параметры: `source_var`, `result_var`
|
||||||
|
ToString,
|
||||||
|
|
||||||
|
/// Скопировать строку `str_var` в `result_var`, переводя в `list[char]`
|
||||||
|
///
|
||||||
|
/// Название: TO_CHARS \
|
||||||
|
/// Параметры: `source_var`, `result_var`
|
||||||
|
ToChars,
|
||||||
|
|
||||||
|
/// Скопировать строку `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,
|
||||||
|
|
||||||
|
/// Скопировать предмет из списка `str_var` по индексу `index_var` и записать в `result_var`
|
||||||
|
///
|
||||||
|
/// Название: GET_ITEM \
|
||||||
|
/// Параметры: `list_var`, `index_var`, `result_var`
|
||||||
|
GetItem,
|
||||||
|
|
||||||
|
/// Скопировать предмет из мапы `map_var` по ключу `key_var` и записать в `result_var`
|
||||||
|
///
|
||||||
|
/// Название: GET_VALUE \
|
||||||
|
/// Параметры: `map_var`, key_var`, `result_var`
|
||||||
|
GetValue,
|
||||||
|
|
||||||
|
/// Прибавить к числу `var` значение `other_var`
|
||||||
|
///
|
||||||
|
/// Название: ADD_INT \
|
||||||
|
/// Параметры: `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,
|
||||||
|
|
||||||
|
/// Вывести переменную `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,
|
||||||
|
|
||||||
|
/// Функция `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,
|
||||||
|
|
||||||
|
/// Открыть файл по пути `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,
|
||||||
|
|
||||||
|
/// Ждать миллисекунд из переменной `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`, то результат `false`, иначе `true`, записать результат в `result_var`
|
||||||
|
///
|
||||||
|
/// Название: NOT \
|
||||||
|
/// Параметры: `var`, `result_var`
|
||||||
|
Not,
|
||||||
|
|
||||||
|
/// Если `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,
|
||||||
|
|
||||||
|
/// Достать данные из `optional_var` и установить в `result_var`
|
||||||
|
///
|
||||||
|
/// Название: UNPACK_OPTIONAL \
|
||||||
|
/// Параметры: `optional_var`, `result_var`
|
||||||
|
UnpackOptional,
|
||||||
|
|
||||||
|
/// Получить размер списка и записать в переменную `result_var` типа `int`
|
||||||
|
///
|
||||||
|
/// Название: LIST_SIZE \
|
||||||
|
/// Параметры: `list_var`, `result_var`
|
||||||
|
ListSize,
|
||||||
|
|
||||||
|
/// Получить размер строки и записать в переменную `result_var` типа `int`
|
||||||
|
///
|
||||||
|
/// Название: MAP_SIZE \
|
||||||
|
/// Параметры: `map_var`, `result_var`
|
||||||
|
MapSize,
|
||||||
|
|
||||||
|
/// Получить размер мапы и записать в переменную `result_var` типа `int`
|
||||||
|
///
|
||||||
|
/// Название: STRING_SIZE \
|
||||||
|
/// Параметры: `string_var`, `result_var`
|
||||||
|
StringSize,
|
||||||
|
|
||||||
|
/// Функция `func` вызывается для каждого символа строки `string_var`
|
||||||
|
///
|
||||||
|
/// Название: FOR_STRING \
|
||||||
|
/// Параметры: `func(char)`, `string_var`
|
||||||
|
ForString,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandType {
|
||||||
|
pub fn from_name(name: &str) -> Result<CommandType, ScriptError> {
|
||||||
|
match name {
|
||||||
|
"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_CHARS" => Ok(CommandType::ToChars),
|
||||||
|
"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),
|
||||||
|
"GET_ITEM" => Ok(CommandType::GetItem),
|
||||||
|
"GET_VALUE" => Ok(CommandType::GetValue),
|
||||||
|
"ADD_INT" => Ok(CommandType::AddInt),
|
||||||
|
"ADD_FLOAT" => Ok(CommandType::AddFloat),
|
||||||
|
"ADD_STR" => Ok(CommandType::AddStr),
|
||||||
|
"SUB_STR" => Ok(CommandType::SubStr),
|
||||||
|
"SUB_LIST" => Ok(CommandType::SubList),
|
||||||
|
"LIST_SIZE" => Ok(CommandType::ListSize),
|
||||||
|
"MAP_SIZE" => Ok(CommandType::MapSize),
|
||||||
|
"STRING_SIZE" => Ok(CommandType::StringSize),
|
||||||
|
"WRITE" => Ok(CommandType::Write),
|
||||||
|
"READ" => Ok(CommandType::Read),
|
||||||
|
"READ_ALL" => Ok(CommandType::ReadAll),
|
||||||
|
"FOR" => Ok(CommandType::For),
|
||||||
|
"FOR_MAP" => Ok(CommandType::ForMap),
|
||||||
|
"FOR_LIST" => Ok(CommandType::ForList),
|
||||||
|
"FOR_STRING" => Ok(CommandType::ForString),
|
||||||
|
"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),
|
||||||
|
"NOT" => Ok(CommandType::Not),
|
||||||
|
"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),
|
||||||
|
"UNPACK_OPTIONAL" => Ok(CommandType::UnpackOptional),
|
||||||
|
_ => Err(ScriptError::CommandUnknownError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
src/sustlang/command/mod.rs
Normal file
2
src/sustlang/command/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
mod command;
|
||||||
|
mod command_type;
|
3
src/sustlang/mod.rs
Normal file
3
src/sustlang/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
mod command;
|
||||||
|
mod script;
|
||||||
|
mod var;
|
20
src/sustlang/script/error.rs
Normal file
20
src/sustlang/script/error.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ScriptError {
|
||||||
|
ParseVarError,
|
||||||
|
TypeUnknownError,
|
||||||
|
CommandUnknownError,
|
||||||
|
CommandArgsInvalidError,
|
||||||
|
UnknownVarError,
|
||||||
|
TypeMismatchError,
|
||||||
|
VarNotInitedError,
|
||||||
|
StringUTF8Error,
|
||||||
|
VarInitedError,
|
||||||
|
FunctionUnknownError,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {}
|
68
src/sustlang/script/function.rs
Normal file
68
src/sustlang/script/function.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#[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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute_function(
|
||||||
|
&self,
|
||||||
|
function: Function,
|
||||||
|
result_var: String,
|
||||||
|
args: Vec<Variable>,
|
||||||
|
globals: &mut HashMap<String, Variable>,
|
||||||
|
is_global: bool,
|
||||||
|
) -> Result<(), ScriptError> {
|
||||||
|
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)?,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut temp_vars: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
for command in function.commands {
|
||||||
|
if let CommandType::Return = command.command_type {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.exec_command(command.clone(), false, &mut locals, &mut temp_vars)?;
|
||||||
|
|
||||||
|
if let CommandType::TempVar = command.command_type {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ele in temp_vars.clone() {
|
||||||
|
self.variables.remove(&ele);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result_var != "null" {
|
||||||
|
self.variables
|
||||||
|
.insert(result_var, locals.get("result").unwrap().clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
4
src/sustlang/script/mod.rs
Normal file
4
src/sustlang/script/mod.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
mod error;
|
||||||
|
mod function;
|
||||||
|
mod running_script;
|
||||||
|
mod script;
|
285
src/sustlang/script/running_script.rs
Normal file
285
src/sustlang/script/running_script.rs
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
pub struct RunningScript {
|
||||||
|
main_function: Function,
|
||||||
|
functions: Vec<Function>,
|
||||||
|
variables: HashMap<String, Variable>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunningScript {
|
||||||
|
pub fn new(script: Script) -> RunningScript {
|
||||||
|
RunningScript {
|
||||||
|
functions: script.functions,
|
||||||
|
variables: HashMap::new(),
|
||||||
|
main_function: Function::new(
|
||||||
|
"main".to_string(),
|
||||||
|
"null".to_string(),
|
||||||
|
HashMap::new(),
|
||||||
|
script.commands,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_standard_vars(
|
||||||
|
&mut self,
|
||||||
|
args: Vec<String>,
|
||||||
|
cout: Box<dyn Write>,
|
||||||
|
cin: Box<dyn Read>,
|
||||||
|
) -> Result<(), ScriptError> {
|
||||||
|
self.set_var(
|
||||||
|
String::from("args"),
|
||||||
|
Variable::from_list(
|
||||||
|
Some(
|
||||||
|
args.iter()
|
||||||
|
.map(|s| Variable::from_str(Some(s.to_string())))
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
VarType::String,
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
&mut HashMap::new(),
|
||||||
|
)?;
|
||||||
|
self.set_var(
|
||||||
|
String::from("cout"),
|
||||||
|
Variable::from_out_stream(Some(Arc::new(Mutex::new(cout)))),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
&mut HashMap::new(),
|
||||||
|
)?;
|
||||||
|
self.set_var(
|
||||||
|
String::from("cin"),
|
||||||
|
Variable::from_in_stream(Some(Arc::new(Mutex::new(cin)))),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
&mut HashMap::new(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_var(
|
||||||
|
&mut self,
|
||||||
|
name: String,
|
||||||
|
locals: &mut HashMap<String, Variable>,
|
||||||
|
) -> Result<Variable, ScriptError> {
|
||||||
|
let mut var: Option<Variable> = None;
|
||||||
|
|
||||||
|
for part in name.split('.') {
|
||||||
|
var = match &var {
|
||||||
|
Some(v) => match v {
|
||||||
|
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<String, Variable>,
|
||||||
|
) -> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_var(
|
||||||
|
&mut self,
|
||||||
|
name: String,
|
||||||
|
value: Variable,
|
||||||
|
global: bool,
|
||||||
|
init: bool,
|
||||||
|
locals: &mut HashMap<String, Variable>,
|
||||||
|
) -> Result<(), ScriptError> {
|
||||||
|
let var_type = value.get_type();
|
||||||
|
let mut var: Option<&mut Variable> = None;
|
||||||
|
let parts: Vec<&str> = (&name).split('.').collect();
|
||||||
|
|
||||||
|
match self.get_var(name.clone(), locals) {
|
||||||
|
Ok(i) => {
|
||||||
|
if init {
|
||||||
|
return Err(ScriptError::VarInitedError);
|
||||||
|
} else if i.get_type() != var_type {
|
||||||
|
return Err(ScriptError::TypeMismatchError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
if !init {
|
||||||
|
return Err(ScriptError::UnknownVarError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let global =
|
||||||
|
global || (self.variables.contains_key(parts[0]) && !locals.contains_key(parts[0]));
|
||||||
|
|
||||||
|
if parts.len() == 1 {
|
||||||
|
if global {
|
||||||
|
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) -> Result<Function, ScriptError> {
|
||||||
|
for func in &self.functions {
|
||||||
|
if func.name == name {
|
||||||
|
return Ok(func.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(ScriptError::FunctionUnknownError)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) -> Result<(), (ScriptError, Command)> {
|
||||||
|
self.exec_commands(self.commands.clone(), true, &mut HashMap::new())
|
||||||
|
}
|
||||||
|
}
|
115
src/sustlang/script/script.rs
Normal file
115
src/sustlang/script/script.rs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
fn prepare_script(text: String) -> Vec<String> {
|
||||||
|
text.lines()
|
||||||
|
.map(|s| match s.split_once("#") {
|
||||||
|
Some(s) => s.0,
|
||||||
|
None => s,
|
||||||
|
})
|
||||||
|
.map(|s| {
|
||||||
|
s.trim_end_matches(" ")
|
||||||
|
.trim_end_matches("\t")
|
||||||
|
.trim_start_matches(" ")
|
||||||
|
.trim_start_matches("\t")
|
||||||
|
.to_string()
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_commands(lines: Vec<String>) -> Result<Vec<Command>, (ScriptError, usize)> {
|
||||||
|
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<String> = line.split(" ").map(|v| v.to_string()).collect();
|
||||||
|
|
||||||
|
let command_type = CommandType::from_name(¶ms[0]).map_err(|f| (f, line_num))?;
|
||||||
|
|
||||||
|
let args = if params.is_empty() {
|
||||||
|
Vec::new()
|
||||||
|
} else {
|
||||||
|
params[1..].to_vec()
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.push(Command::new(command_type, line_num, args))
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(commands)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cut_funcs(commands: &mut Vec<Command>) -> Result<Vec<Function>, (ScriptError, usize)> {
|
||||||
|
let mut functions: Vec<Function> = Vec::new();
|
||||||
|
|
||||||
|
let mut now_func: Option<Function> = None;
|
||||||
|
|
||||||
|
let mut index = 0;
|
||||||
|
for command in commands.clone() {
|
||||||
|
index += 1;
|
||||||
|
|
||||||
|
match now_func.clone() {
|
||||||
|
Some(func) => {
|
||||||
|
index -= 1;
|
||||||
|
commands.remove(index);
|
||||||
|
|
||||||
|
if let CommandType::FuncEnd = command.command_type {
|
||||||
|
functions.push(func.clone());
|
||||||
|
now_func = None;
|
||||||
|
} else {
|
||||||
|
now_func.as_mut().unwrap().commands.push(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if let CommandType::Func = command.command_type {
|
||||||
|
index -= 1;
|
||||||
|
commands.remove(index);
|
||||||
|
|
||||||
|
let name = command.args[1].clone();
|
||||||
|
let result_type =
|
||||||
|
VarType::from_name(&command.args[0]).map_err(|f| (f, command.line))?;
|
||||||
|
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(),
|
||||||
|
VarType::from_name(i).map_err(|f| (f, command.line))?,
|
||||||
|
);
|
||||||
|
param_key = None;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
param_key = Some(i.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
now_func = Some(Function::new(name, result_type, parameters, Vec::new()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(functions)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Script {
|
||||||
|
commands: Vec<Command>,
|
||||||
|
functions: Vec<Function>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Script {
|
||||||
|
pub fn parse(text: String) -> Result<Script, (ScriptError, usize)> {
|
||||||
|
let lines = prepare_script(text);
|
||||||
|
let mut commands = parse_commands(lines)?;
|
||||||
|
let functions = cut_funcs(&mut commands)?;
|
||||||
|
Ok(Script {
|
||||||
|
commands,
|
||||||
|
functions,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
2
src/sustlang/var/mod.rs
Normal file
2
src/sustlang/var/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
mod var_type;
|
||||||
|
mod variable;
|
80
src/sustlang/var/var_type.rs
Normal file
80
src/sustlang/var/var_type.rs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#[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,
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VarType {
|
||||||
|
pub fn from_name(name: &str) -> Result<VarType, ScriptError> {
|
||||||
|
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 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 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 Ok(VarType::Optional(value_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
match name {
|
||||||
|
"bool" => Ok(VarType::Bool),
|
||||||
|
"b" => Ok(VarType::Bool),
|
||||||
|
"string" => Ok(VarType::String),
|
||||||
|
"str" => Ok(VarType::String),
|
||||||
|
"s" => Ok(VarType::String),
|
||||||
|
"integer" => Ok(VarType::Integer),
|
||||||
|
"int" => Ok(VarType::Integer),
|
||||||
|
"i" => Ok(VarType::Integer),
|
||||||
|
"float" => Ok(VarType::Float),
|
||||||
|
"f" => Ok(VarType::Float),
|
||||||
|
"char" => Ok(VarType::Char),
|
||||||
|
"c" => Ok(VarType::Char),
|
||||||
|
"in_stream" => Ok(VarType::InStream),
|
||||||
|
"in" => Ok(VarType::InStream),
|
||||||
|
"out_stream" => Ok(VarType::OutStream),
|
||||||
|
"out" => Ok(VarType::OutStream),
|
||||||
|
"null" => Ok(VarType::Null),
|
||||||
|
_ => Err(ScriptError::TypeUnknownError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
522
src/sustlang/var/variable.rs
Normal file
522
src/sustlang/var/variable.rs
Normal file
@ -0,0 +1,522 @@
|
|||||||
|
#[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>>>),
|
||||||
|
Null(VarType),
|
||||||
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
Variable::Null(t) => t.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_string(&self) -> Result<String, ScriptError> {
|
||||||
|
Ok(match self.clone() {
|
||||||
|
Variable::Bool(_, Some(v)) => if v { "true" } else { "false" }.to_string(),
|
||||||
|
Variable::String(_, Some(v)) => v,
|
||||||
|
Variable::Integer(_, Some(v)) => v.to_string(),
|
||||||
|
Variable::Float(_, Some(v)) => v.to_string(),
|
||||||
|
Variable::Char(_, Some(v)) => {
|
||||||
|
String::from_utf8(vec![v]).or(Err(ScriptError::StringUTF8Error))?
|
||||||
|
}
|
||||||
|
Variable::List(VarType::Char, Some(v)) => {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
for ele in v {
|
||||||
|
bytes.push(ele.as_char()?);
|
||||||
|
}
|
||||||
|
String::from_utf8(bytes).or(Err(ScriptError::StringUTF8Error))?
|
||||||
|
}
|
||||||
|
Variable::List(_, Some(v)) => {
|
||||||
|
let mut text = String::from("[");
|
||||||
|
for i in 0..v.len() {
|
||||||
|
let item = &v[i];
|
||||||
|
text.push_str(&item.to_string()?);
|
||||||
|
if i != v.len() - 1 {
|
||||||
|
text.push_str(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text.push(']');
|
||||||
|
text
|
||||||
|
}
|
||||||
|
Variable::Map(_, Some(v)) => {
|
||||||
|
let mut text = String::from("{");
|
||||||
|
let mut i = 0;
|
||||||
|
for (key, value) in &v {
|
||||||
|
text.push_str(&key.to_string()?);
|
||||||
|
text.push_str(": ");
|
||||||
|
text.push_str(&value.to_string()?);
|
||||||
|
if i != v.len() - 1 {
|
||||||
|
text.push_str(", ");
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
text.push('}');
|
||||||
|
text
|
||||||
|
}
|
||||||
|
Variable::Optional(_, Some(v)) => match v {
|
||||||
|
Some(v) => format!("({})", v.to_string()?),
|
||||||
|
None => String::from("none"),
|
||||||
|
},
|
||||||
|
Variable::InStream(_, Some(_)) => String::from("IN_STREAM"),
|
||||||
|
Variable::OutStream(_, Some(_)) => String::from("OUT_STREAM"),
|
||||||
|
Variable::Null(_) => String::from("null"),
|
||||||
|
_ => return Err(ScriptError::VarNotInitedError),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_null(&self) -> bool {
|
||||||
|
if let Variable::Null(_) = self {
|
||||||
|
true
|
||||||
|
} 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<bool>) -> Variable {
|
||||||
|
Variable::Bool(VarType::Bool, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_str(value: Option<String>) -> Variable {
|
||||||
|
Variable::String(VarType::String, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_int(value: Option<isize>) -> Variable {
|
||||||
|
Variable::Integer(VarType::Integer, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_float(value: Option<f64>) -> Variable {
|
||||||
|
Variable::Float(VarType::Float, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_char(value: Option<u8>) -> Variable {
|
||||||
|
Variable::Char(VarType::Char, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_list(value: Option<Vec<Variable>>, value_type: VarType) -> Variable {
|
||||||
|
Variable::List(VarType::List(Box::new(value_type)), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_map(
|
||||||
|
value: Option<HashMap<Variable, Variable>>,
|
||||||
|
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<Option<Variable>>, 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<Arc<Mutex<dyn Write>>>) -> Variable {
|
||||||
|
Variable::OutStream(VarType::OutStream, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_in_stream(value: Option<Arc<Mutex<dyn Read>>>) -> Variable {
|
||||||
|
Variable::InStream(VarType::InStream, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_out_stream(&self) -> Result<Arc<Mutex<dyn Write>>, ScriptError> {
|
||||||
|
if let Variable::OutStream(_, Some(b)) = self {
|
||||||
|
Ok(b.clone())
|
||||||
|
} else {
|
||||||
|
Err(ScriptError::TypeMismatchError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_in_stream(&self) -> Result<Arc<Mutex<dyn Read>>, ScriptError> {
|
||||||
|
if let Variable::InStream(_, Some(b)) = self {
|
||||||
|
Ok(b.clone())
|
||||||
|
} else {
|
||||||
|
Err(ScriptError::TypeMismatchError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_option_type(&self) -> Result<VarType, ScriptError> {
|
||||||
|
if let Variable::Optional(VarType::Optional(v), _) = self {
|
||||||
|
Ok(v.as_ref().clone())
|
||||||
|
} else {
|
||||||
|
Err(ScriptError::TypeMismatchError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_option(&self) -> Result<Option<Box<Variable>>, 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<HashMap<Variable, Variable>, ScriptError> {
|
||||||
|
if let Variable::Map(_, Some(b)) = self {
|
||||||
|
Ok(b.clone())
|
||||||
|
} else {
|
||||||
|
Err(ScriptError::TypeMismatchError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_list_type(&self) -> Result<VarType, ScriptError> {
|
||||||
|
if let Variable::List(VarType::List(v), _) = self {
|
||||||
|
Ok(v.as_ref().clone())
|
||||||
|
} else {
|
||||||
|
Err(ScriptError::TypeMismatchError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_list(&self) -> Result<Vec<Variable>, ScriptError> {
|
||||||
|
if let Variable::List(_, Some(b)) = self {
|
||||||
|
Ok(b.clone())
|
||||||
|
} else {
|
||||||
|
Err(ScriptError::TypeMismatchError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_char(&self) -> Result<u8, ScriptError> {
|
||||||
|
if let Variable::Char(_, Some(b)) = self {
|
||||||
|
Ok(*b)
|
||||||
|
} else {
|
||||||
|
Err(ScriptError::TypeMismatchError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_float(&self) -> Result<f64, ScriptError> {
|
||||||
|
if let Variable::Float(_, Some(b)) = self {
|
||||||
|
Ok(*b)
|
||||||
|
} else {
|
||||||
|
Err(ScriptError::TypeMismatchError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_int(&self) -> Result<isize, ScriptError> {
|
||||||
|
if let Variable::Integer(_, Some(b)) = self {
|
||||||
|
Ok(*b)
|
||||||
|
} else {
|
||||||
|
Err(ScriptError::TypeMismatchError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> Result<String, ScriptError> {
|
||||||
|
if let Variable::String(_, Some(b)) = self {
|
||||||
|
Ok(b.to_string())
|
||||||
|
} else {
|
||||||
|
Err(ScriptError::TypeMismatchError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_bool(&self) -> Result<bool, ScriptError> {
|
||||||
|
if let Variable::Bool(_, Some(b)) = self {
|
||||||
|
Ok(*b)
|
||||||
|
} else {
|
||||||
|
Err(ScriptError::TypeMismatchError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn not_inited_var(var_type: VarType) -> Result<Variable, ScriptError> {
|
||||||
|
match var_type {
|
||||||
|
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) => {
|
||||||
|
Ok(Variable::Optional(VarType::Optional(optional_type), None))
|
||||||
|
}
|
||||||
|
VarType::List(value_type) => Ok(Variable::List(VarType::List(value_type), None)),
|
||||||
|
VarType::Map(key_type, value_type) => {
|
||||||
|
Ok(Variable::Map(VarType::Map(key_type, value_type), 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 empty_var(var_type: VarType) -> Result<Variable, ScriptError> {
|
||||||
|
match var_type {
|
||||||
|
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) => Ok(Variable::Optional(
|
||||||
|
VarType::Optional(optional_type),
|
||||||
|
Some(None),
|
||||||
|
)),
|
||||||
|
VarType::List(value_type) => {
|
||||||
|
Ok(Variable::List(VarType::List(value_type), Some(Vec::new())))
|
||||||
|
}
|
||||||
|
VarType::Map(key_type, value_type) => Ok(Variable::Map(
|
||||||
|
VarType::Map(key_type, value_type),
|
||||||
|
Some(HashMap::new()),
|
||||||
|
)),
|
||||||
|
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) -> Result<Variable, ScriptError> {
|
||||||
|
match var_type {
|
||||||
|
VarType::Bool => Ok(Variable::Bool(
|
||||||
|
VarType::Bool,
|
||||||
|
Some(match text.as_str() {
|
||||||
|
"true" => true,
|
||||||
|
"false" => false,
|
||||||
|
"1" => true,
|
||||||
|
"0" => false,
|
||||||
|
_ => {
|
||||||
|
return Err(ScriptError::ParseVarError);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
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 Err(ScriptError::ParseVarError);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
VarType::Float => Ok(Variable::Float(
|
||||||
|
VarType::Float,
|
||||||
|
Some(match text.parse() {
|
||||||
|
Ok(i) => i,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(ScriptError::ParseVarError);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
VarType::Char => Ok(Variable::Char(
|
||||||
|
VarType::Char,
|
||||||
|
Some(match text.parse() {
|
||||||
|
Ok(i) => i,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(ScriptError::ParseVarError);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
VarType::Optional(optional_type) => {
|
||||||
|
if text.starts_with("[") && text.ends_with("]") {
|
||||||
|
let text = text[1..text.len() - 1].to_string();
|
||||||
|
Ok(Variable::Optional(
|
||||||
|
VarType::Optional(optional_type.clone()),
|
||||||
|
Some(Some(Box::new(Self::parse_var(
|
||||||
|
optional_type.clone().as_mut().clone(),
|
||||||
|
text,
|
||||||
|
)?))),
|
||||||
|
))
|
||||||
|
} else if text.as_str() == "none" {
|
||||||
|
Ok(Variable::Optional(
|
||||||
|
VarType::Optional(optional_type),
|
||||||
|
Some(None),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err(ScriptError::ParseVarError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(ScriptError::ParseVarError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
Variable::Null(t) => {
|
||||||
|
hash(t, 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::Null(o) => match other {
|
||||||
|
Variable::Null(t) => o == t,
|
||||||
|
_ => 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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user