mirror of
https://github.com/Dummi26/mers.git
synced 2025-04-28 18:16:05 +02:00
changed get to return [] or [v] instead of [] or v because v might be []. This also matches the 0-or-1-length-tuple patterns for optionals (so it can be unwrap()d using .assume1()).
This commit is contained in:
parent
45186e3803
commit
2ba1ed270d
188
src/libs/mod.rs
188
src/libs/mod.rs
@ -1,36 +1,200 @@
|
||||
use std::{
|
||||
io,
|
||||
process::{Child, ChildStdin, ChildStdout, Command},
|
||||
io::{self, BufRead, BufReader, Read, Write},
|
||||
process::{Child, ChildStdin, ChildStdout, Command, Stdio},
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
parse::{file::File, parse},
|
||||
script::{
|
||||
val_data::{VData, VDataEnum},
|
||||
val_type::VType,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
Libraries are processes that communicate via stdout/stdin.
|
||||
data in stdout is only expected after it was requested via stdin. ignoring this will likely cause issues.
|
||||
requests in stdin can be identified via the first byte (ascii char) and end with a \n newline character.
|
||||
the identifying ascii chars:
|
||||
i init
|
||||
reply format:
|
||||
two bytes, the first for major and the second for minor version number.
|
||||
the utf8-encoded name of the library followed by a newline
|
||||
the number of lines in the description (0 for no description) as a byte. (more than 255 lines aren't supported)
|
||||
a (optionally markdown-formatted [TODO!]) description of the library; all lines (including the last one) must end with a newline
|
||||
the things you would like to register; one line each unless explicitly stated otherwise; the first byte (char) decides what type to register:
|
||||
f a function: followed by the function signature, i.e. "my_func(string int/float [string]) string/[float int]"
|
||||
x end: indicates that you are done registering things
|
||||
I init 2
|
||||
TODO! (currently nothing)
|
||||
reply should be a single line (only the newline char). If there is data before the newline char, it will be reported as an error and the script will not run.
|
||||
f call a function:
|
||||
followed by the function id byte (0 <= id < #funcs; function ids are assigned in ascending order as they were registered in the reply to "i"
|
||||
and the data for each argument, in order.
|
||||
reply: the data for the returned value
|
||||
x exit
|
||||
sending data: (all ints are encoded so that the most significant data is sent FIRST)
|
||||
the first byte (ascii char) identifies the type of data: (exceptions listed first: bools)
|
||||
b false
|
||||
B true
|
||||
1 int
|
||||
2 int as string
|
||||
5 float
|
||||
6 float as string
|
||||
" string (format: ", 64-bit unsigned int indicating string length, so many bytes utf-8)
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Lib {
|
||||
process: Child,
|
||||
stdin: ChildStdin,
|
||||
stdout: ChildStdout,
|
||||
stdin: Arc<Mutex<ChildStdin>>,
|
||||
stdout: Arc<Mutex<BufReader<ChildStdout>>>,
|
||||
pub registered_fns: Vec<(String, Vec<VType>, VType)>,
|
||||
}
|
||||
impl Lib {
|
||||
pub fn launch(mut exec: Command) -> Result<Self, LaunchError> {
|
||||
let mut handle = match exec.spawn() {
|
||||
let mut handle = match exec
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::inherit())
|
||||
.spawn()
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(e) => return Err(LaunchError::CouldNotSpawnProcess(e)),
|
||||
};
|
||||
if let (Some(stdin), Some(stdout), stderr) = (
|
||||
handle.stdin.take(),
|
||||
handle.stdout.take(),
|
||||
handle.stderr.take(),
|
||||
) {
|
||||
if let (Some(mut stdin), Some(stdout)) = (handle.stdin.take(), handle.stdout.take()) {
|
||||
let mut stdout = BufReader::new(stdout);
|
||||
writeln!(stdin, "i").unwrap();
|
||||
let vernum = {
|
||||
let mut vernum = [0, 0];
|
||||
stdout.read_exact(&mut vernum).unwrap();
|
||||
(vernum[0], vernum[1])
|
||||
};
|
||||
let name = stdout.line().unwrap();
|
||||
let name = name.trim();
|
||||
eprintln!("- <<< ADDING LIB: {name} v{}.{} >>> -", vernum.0, vernum.1);
|
||||
let lines_in_desc = stdout.one_byte().unwrap();
|
||||
let mut lines_desc = Vec::with_capacity(lines_in_desc as _);
|
||||
for _ in 0..lines_in_desc {
|
||||
let line = stdout.line().unwrap();
|
||||
let line = line.trim_end_matches('\n');
|
||||
eprintln!("| {line}");
|
||||
lines_desc.push(line.to_string());
|
||||
}
|
||||
let mut registered_fns = vec![];
|
||||
loop {
|
||||
let line = stdout.line().unwrap();
|
||||
match line.chars().next() {
|
||||
Some('f') => {
|
||||
let (name, args) = line[1..]
|
||||
.split_once('(')
|
||||
.expect("function signature didn't include the ( character.");
|
||||
let mut fn_signature = File::new(args.to_string());
|
||||
let mut fn_in = vec![];
|
||||
loop {
|
||||
let t = parse::parse_type_adv(&mut fn_signature, true).unwrap();
|
||||
fn_in.push(t.0);
|
||||
if t.1 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let fn_out = parse::parse_type(&mut fn_signature).unwrap();
|
||||
eprintln!("Registering function \"{name}\" with args \"{}\" and return type \"{fn_out}\"", &fn_in.iter().fold(String::new(), |mut s, v| { s.push_str(format!(" {}", v).as_str()); s })[1..]);
|
||||
registered_fns.push((name.to_string(), fn_in, fn_out));
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
Ok(Self {
|
||||
process: handle,
|
||||
stdin,
|
||||
stdout,
|
||||
stdin: Arc::new(Mutex::new(stdin)),
|
||||
stdout: Arc::new(Mutex::new(stdout)),
|
||||
registered_fns,
|
||||
})
|
||||
} else {
|
||||
return Err(LaunchError::NoStdio);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_fn(&self, fnid: usize, args: &Vec<VData>) -> VData {
|
||||
let mut stdin = self.stdin.lock().unwrap();
|
||||
let mut stdout = self.stdout.lock().unwrap();
|
||||
debug_assert!(args.len() == self.registered_fns[fnid].1.len());
|
||||
write!(stdin, "f").unwrap();
|
||||
stdin.write(&[fnid as _]).unwrap();
|
||||
for (_i, arg) in args.iter().enumerate() {
|
||||
data_to_bytes(arg, &mut stdin);
|
||||
}
|
||||
let o = data_from_bytes(&mut stdout).to();
|
||||
o
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LaunchError {
|
||||
NoStdio,
|
||||
CouldNotSpawnProcess(io::Error),
|
||||
}
|
||||
|
||||
trait DirectReader {
|
||||
fn line(&mut self) -> Result<String, io::Error>;
|
||||
fn one_byte(&mut self) -> Result<u8, io::Error>;
|
||||
}
|
||||
impl<T> DirectReader for T
|
||||
where
|
||||
T: BufRead,
|
||||
{
|
||||
fn line(&mut self) -> Result<String, io::Error> {
|
||||
let mut buf = String::new();
|
||||
self.read_line(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
fn one_byte(&mut self) -> Result<u8, io::Error> {
|
||||
let mut b = [0];
|
||||
self.read(&mut b)?;
|
||||
Ok(b[0])
|
||||
}
|
||||
}
|
||||
|
||||
fn data_to_bytes(data: &VData, stdin: &mut ChildStdin) {
|
||||
match &data.data {
|
||||
VDataEnum::Bool(false) => write!(stdin, "b").unwrap(),
|
||||
VDataEnum::Bool(true) => write!(stdin, "B").unwrap(),
|
||||
VDataEnum::Int(_) => todo!(),
|
||||
VDataEnum::Float(_) => todo!("floats are not yet implemented for LibFunction calls."),
|
||||
VDataEnum::String(s) => {
|
||||
write!(stdin, "\"").unwrap();
|
||||
stdin.write(&(s.len() as u64).to_be_bytes()).unwrap();
|
||||
stdin.write(s.as_bytes()).unwrap();
|
||||
}
|
||||
VDataEnum::Tuple(_) => todo!(),
|
||||
VDataEnum::List(..) => todo!(),
|
||||
VDataEnum::Function(..) | VDataEnum::Reference(..) | VDataEnum::Thread(..) => {
|
||||
panic!("cannot use functions, references or threads in LibFunctions.")
|
||||
}
|
||||
}
|
||||
stdin.flush().unwrap();
|
||||
}
|
||||
fn data_from_bytes(stdout: &mut BufReader<ChildStdout>) -> VDataEnum {
|
||||
match stdout.one_byte().unwrap().into() {
|
||||
'b' => VDataEnum::Bool(false),
|
||||
'B' => VDataEnum::Bool(true),
|
||||
'1' | '2' | '5' | '6' => todo!(),
|
||||
'"' => {
|
||||
let mut len_bytes = 0u64;
|
||||
for _ in 0..8 {
|
||||
len_bytes <<= 8;
|
||||
len_bytes |= stdout.one_byte().unwrap() as u64;
|
||||
}
|
||||
let mut buf = Vec::with_capacity(len_bytes as _);
|
||||
for _ in 0..len_bytes {
|
||||
buf.push(stdout.one_byte().unwrap());
|
||||
}
|
||||
VDataEnum::String(String::from_utf8_lossy(&buf).into_owned())
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ pub struct File {
|
||||
chars: Vec<(usize, char)>,
|
||||
pos: FilePosition,
|
||||
}
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FilePosition {
|
||||
current_char_index: usize,
|
||||
current_line: usize,
|
||||
@ -100,6 +101,17 @@ impl File {
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
pub fn next_line(&mut self) -> String {
|
||||
let mut o = String::new();
|
||||
for ch in self {
|
||||
if ch == '\n' {
|
||||
break;
|
||||
} else {
|
||||
o.push(ch);
|
||||
}
|
||||
}
|
||||
o
|
||||
}
|
||||
pub fn peek(&self) -> Option<char> {
|
||||
match self.chars.get(self.pos.current_char_index) {
|
||||
Some((_, c)) => Some(*c),
|
||||
|
@ -1,10 +1,16 @@
|
||||
use crate::script::{
|
||||
use std::{path::PathBuf, process::Command, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
libs,
|
||||
script::{
|
||||
block::{
|
||||
to_runnable, to_runnable::ToRunnableError, RScript, SBlock, SFunction, SStatement,
|
||||
SStatementEnum,
|
||||
to_runnable::ToRunnableError,
|
||||
to_runnable::{self, GInfo},
|
||||
RScript, SBlock, SFunction, SStatement, SStatementEnum,
|
||||
},
|
||||
val_data::VDataEnum,
|
||||
val_type::{VSingleType, VType},
|
||||
},
|
||||
};
|
||||
|
||||
use super::file::File;
|
||||
@ -28,6 +34,32 @@ impl From<ToRunnableError> for ScriptError {
|
||||
pub enum ParseError {}
|
||||
|
||||
pub fn parse(file: &mut File) -> Result<RScript, ScriptError> {
|
||||
let mut libs = vec![];
|
||||
loop {
|
||||
file.skip_whitespaces();
|
||||
let pos = file.get_pos().clone();
|
||||
let line = file.next_line();
|
||||
if line.starts_with("lib ") {
|
||||
let path_to_executable: PathBuf = line[4..].into();
|
||||
let mut cmd = Command::new(&path_to_executable);
|
||||
if let Some(parent) = path_to_executable.parent() {
|
||||
cmd.current_dir(parent.clone());
|
||||
}
|
||||
match libs::Lib::launch(cmd) {
|
||||
Ok(lib) => {
|
||||
libs.push(lib);
|
||||
eprintln!("Loaded library!");
|
||||
}
|
||||
Err(e) => panic!(
|
||||
"Unable to load library at {}: {e:?}",
|
||||
path_to_executable.to_string_lossy().as_ref(),
|
||||
),
|
||||
}
|
||||
} else {
|
||||
file.set_pos(pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let func = SFunction::new(
|
||||
vec![(
|
||||
"args".to_string(),
|
||||
@ -36,10 +68,11 @@ pub fn parse(file: &mut File) -> Result<RScript, ScriptError> {
|
||||
parse_block_advanced(file, Some(false), true, true, false)?,
|
||||
);
|
||||
eprintln!();
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("Parsed: {func}");
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("Parsed: {func:#?}");
|
||||
let run = to_runnable(func)?;
|
||||
let run = to_runnable::to_runnable(func, GInfo::new(Arc::new(libs)))?;
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("Runnable: {run:#?}");
|
||||
Ok(run)
|
||||
@ -400,13 +433,16 @@ fn parse_function(file: &mut File) -> Result<SFunction, ParseError> {
|
||||
Ok(SFunction::new(args, parse_block(file)?))
|
||||
}
|
||||
|
||||
fn parse_type(file: &mut File) -> Result<VType, ParseError> {
|
||||
pub(crate) fn parse_type(file: &mut File) -> Result<VType, ParseError> {
|
||||
match parse_type_adv(file, false) {
|
||||
Ok((v, _)) => Ok(v),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
fn parse_type_adv(file: &mut File, in_fn_args: bool) -> Result<(VType, bool), ParseError> {
|
||||
pub(crate) fn parse_type_adv(
|
||||
file: &mut File,
|
||||
in_fn_args: bool,
|
||||
) -> Result<(VType, bool), ParseError> {
|
||||
let mut types = vec![];
|
||||
let mut closed_fn_args = false;
|
||||
loop {
|
||||
|
@ -6,7 +6,9 @@ use std::{
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use self::to_runnable::ToRunnableError;
|
||||
use crate::libs;
|
||||
|
||||
use self::to_runnable::{ToRunnableError, GInfo};
|
||||
|
||||
use super::{
|
||||
builtins::BuiltinFunction,
|
||||
@ -84,8 +86,8 @@ fn am<T>(i: T) -> Am<T> {
|
||||
Arc::new(Mutex::new(i))
|
||||
}
|
||||
|
||||
pub fn to_runnable(f: SFunction) -> Result<RScript, ToRunnableError> {
|
||||
to_runnable::to_runnable(f)
|
||||
pub fn to_runnable(f: SFunction, ginfo: GInfo) -> Result<RScript, ToRunnableError> {
|
||||
to_runnable::to_runnable(f, ginfo)
|
||||
}
|
||||
|
||||
pub mod to_runnable {
|
||||
@ -95,10 +97,10 @@ pub mod to_runnable {
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::script::{
|
||||
use crate::{script::{
|
||||
val_data::VDataEnum,
|
||||
val_type::{VSingleType, VType},
|
||||
};
|
||||
}, libs};
|
||||
|
||||
use super::{
|
||||
BuiltinFunction, RBlock, RFunction, RScript, RStatement, RStatementEnum, SBlock, SFunction,
|
||||
@ -151,8 +153,21 @@ pub mod to_runnable {
|
||||
}
|
||||
|
||||
// Global, shared between all
|
||||
struct GInfo {
|
||||
pub struct GInfo {
|
||||
vars: usize,
|
||||
libs: Arc<Vec<libs::Lib>>,
|
||||
lib_fns: HashMap<String, (usize, usize)>,
|
||||
}
|
||||
impl GInfo {
|
||||
pub fn new(libs: Arc<Vec<libs::Lib>>) -> Self {
|
||||
let mut lib_fns = HashMap::new();
|
||||
for (libid, lib) in libs.iter().enumerate() {
|
||||
for (fnid, (name, ..)) in lib.registered_fns.iter().enumerate() {
|
||||
lib_fns.insert(name.to_string(), (libid, fnid));
|
||||
}
|
||||
}
|
||||
Self { vars: 0, libs, lib_fns, }
|
||||
}
|
||||
}
|
||||
// Local, used to keep local variables separated
|
||||
#[derive(Clone)]
|
||||
@ -161,7 +176,7 @@ pub mod to_runnable {
|
||||
fns: HashMap<String, Arc<RFunction>>,
|
||||
}
|
||||
|
||||
pub fn to_runnable(s: SFunction) -> Result<RScript, ToRunnableError> {
|
||||
pub fn to_runnable(s: SFunction, mut ginfo: GInfo) -> Result<RScript, ToRunnableError> {
|
||||
if s.inputs.len() != 1 || s.inputs[0].0 != "args" {
|
||||
return Err(ToRunnableError::MainWrongInput);
|
||||
}
|
||||
@ -172,7 +187,6 @@ pub mod to_runnable {
|
||||
})],
|
||||
})
|
||||
{}
|
||||
let mut ginfo = GInfo { vars: 0 };
|
||||
let func = function(
|
||||
&s,
|
||||
&mut ginfo,
|
||||
@ -181,7 +195,7 @@ pub mod to_runnable {
|
||||
fns: HashMap::new(),
|
||||
},
|
||||
)?;
|
||||
Ok(RScript::new(func, ginfo.vars)?)
|
||||
Ok(RScript::new(func, ginfo.vars, ginfo.libs)?)
|
||||
}
|
||||
|
||||
// go over every possible known-type input for the given function, returning all possible RFunctions.
|
||||
@ -312,11 +326,26 @@ pub mod to_runnable {
|
||||
} else {
|
||||
todo!("ERR: Builtin function \"{v}\" with wrong args - this isn't a proper error yet, sorry.");
|
||||
}
|
||||
} else {
|
||||
// LIBRARY FUNCTION?
|
||||
if let Some((libid, fnid)) = ginfo.lib_fns.get(v) {
|
||||
let (_name, fn_in, fn_out) = &ginfo.libs[*libid].registered_fns[*fnid];
|
||||
if fn_in.len() == rargs.len() && fn_in.iter().zip(rargs.iter()).all(|(fn_in, arg)| arg.out().fits_in(fn_in).is_empty()) {
|
||||
RStatementEnum::LibFunction(*libid, *fnid, rargs, fn_out.clone())
|
||||
} else {
|
||||
// TODO! better error here
|
||||
return Err(if fn_in.len() == rargs.len() {
|
||||
todo!("Err: Wrong args for LibFunction \"{v}\".");
|
||||
} else {
|
||||
ToRunnableError::FunctionWrongArgCount(v.to_string(), fn_in.len(), rargs.len())
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Err(ToRunnableError::UseOfUndefinedFunction(v.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SStatementEnum::FunctionDefinition(name, f) => {
|
||||
if let Some(name) = name {
|
||||
// named function => add to global functions
|
||||
@ -538,10 +567,10 @@ pub struct RBlock {
|
||||
statements: Vec<RStatement>,
|
||||
}
|
||||
impl RBlock {
|
||||
pub fn run(&self, vars: &Vec<Am<VData>>) -> VData {
|
||||
pub fn run(&self, vars: &Vec<Am<VData>>, libs: &Arc<Vec<libs::Lib>>) -> VData {
|
||||
let mut last = None;
|
||||
for statement in &self.statements {
|
||||
last = Some(statement.run(vars));
|
||||
last = Some(statement.run(vars, libs));
|
||||
}
|
||||
if let Some(v) = last {
|
||||
v
|
||||
@ -568,8 +597,8 @@ pub struct RFunction {
|
||||
pub block: RBlock,
|
||||
}
|
||||
impl RFunction {
|
||||
pub fn run(&self, vars: &Vec<Am<VData>>) -> VData {
|
||||
self.block.run(vars)
|
||||
pub fn run(&self, vars: &Vec<Am<VData>>, libs: &Arc<Vec<libs::Lib>>) -> VData {
|
||||
self.block.run(vars, libs)
|
||||
}
|
||||
pub fn out(&self, input_types: &Vec<VSingleType>) -> VType {
|
||||
self.input_output_map
|
||||
@ -610,8 +639,8 @@ pub struct RStatement {
|
||||
statement: Box<RStatementEnum>,
|
||||
}
|
||||
impl RStatement {
|
||||
pub fn run(&self, vars: &Vec<Am<VData>>) -> VData {
|
||||
let out = self.statement.run(vars);
|
||||
pub fn run(&self, vars: &Vec<Am<VData>>, libs: &Arc<Vec<libs::Lib>>) -> VData {
|
||||
let out = self.statement.run(vars, libs);
|
||||
if let Some(v) = self.output_to {
|
||||
*vars[v].lock().unwrap() = out;
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
@ -637,6 +666,7 @@ pub enum RStatementEnum {
|
||||
Variable(usize, VType, bool), // Arc<Mutex<..>> here, because imagine variable in for loop that is used in a different thread -> we need multiple "same" variables
|
||||
FunctionCall(Arc<RFunction>, Vec<RStatement>),
|
||||
BuiltinFunction(BuiltinFunction, Vec<RStatement>),
|
||||
LibFunction(usize, usize, Vec<RStatement>, VType),
|
||||
Block(RBlock),
|
||||
If(RStatement, RStatement, Option<RStatement>),
|
||||
While(RStatement),
|
||||
@ -646,13 +676,13 @@ pub enum RStatementEnum {
|
||||
IndexFixed(RStatement, usize),
|
||||
}
|
||||
impl RStatementEnum {
|
||||
pub fn run(&self, vars: &Vec<Am<VData>>) -> VData {
|
||||
pub fn run(&self, vars: &Vec<Am<VData>>, libs: &Arc<Vec<libs::Lib>>) -> VData {
|
||||
match self {
|
||||
Self::Value(v) => v.clone(),
|
||||
Self::Tuple(v) => {
|
||||
let mut w = vec![];
|
||||
for v in v {
|
||||
w.push(v.run(vars));
|
||||
w.push(v.run(vars, libs));
|
||||
}
|
||||
VDataEnum::Tuple(w).to()
|
||||
}
|
||||
@ -660,7 +690,7 @@ impl RStatementEnum {
|
||||
let mut w = vec![];
|
||||
let mut out = VType { types: vec![] };
|
||||
for v in v {
|
||||
let val = v.run(vars);
|
||||
let val = v.run(vars, libs);
|
||||
out = out | val.out();
|
||||
w.push(val);
|
||||
}
|
||||
@ -675,18 +705,20 @@ impl RStatementEnum {
|
||||
}
|
||||
Self::FunctionCall(func, args) => {
|
||||
for (i, input) in func.inputs.iter().enumerate() {
|
||||
*vars[*input].lock().unwrap() = args[i].run(vars);
|
||||
*vars[*input].lock().unwrap() = args[i].run(vars, libs);
|
||||
}
|
||||
func.run(vars)
|
||||
func.run(vars, libs)
|
||||
}
|
||||
Self::Block(b) => b.run(vars),
|
||||
Self::BuiltinFunction(v, args) => v.run(args, vars, libs),
|
||||
Self::LibFunction(libid, fnid, args, _) => libs[*libid].run_fn(*fnid, &args.iter().map(|arg| arg.run(vars, libs)).collect()),
|
||||
Self::Block(b) => b.run(vars, libs),
|
||||
Self::If(c, t, e) => {
|
||||
if let VDataEnum::Bool(v) = c.run(vars).data {
|
||||
if let VDataEnum::Bool(v) = c.run(vars, libs).data {
|
||||
if v {
|
||||
t.run(vars)
|
||||
t.run(vars, libs)
|
||||
} else {
|
||||
if let Some(e) = e {
|
||||
e.run(vars)
|
||||
e.run(vars, libs)
|
||||
} else {
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
}
|
||||
@ -697,7 +729,7 @@ impl RStatementEnum {
|
||||
}
|
||||
Self::While(c) => loop {
|
||||
// While loops blocks can return a bool (false to break from the loop) or a 0-1 length tuple (0-length => continue, 1-length => break with value)
|
||||
match c.run(vars).data {
|
||||
match c.run(vars, libs).data {
|
||||
VDataEnum::Bool(v) => {
|
||||
if !v {
|
||||
break VDataEnum::Tuple(vec![]).to();
|
||||
@ -709,11 +741,11 @@ impl RStatementEnum {
|
||||
}
|
||||
},
|
||||
Self::For(v, c, b) => {
|
||||
let c = c.run(vars);
|
||||
let c = c.run(vars, libs);
|
||||
let mut vars = vars.clone();
|
||||
let mut in_loop = |c| {
|
||||
vars[*v] = Arc::new(Mutex::new(c));
|
||||
b.run(&vars);
|
||||
b.run(&vars, libs);
|
||||
};
|
||||
|
||||
match c.data {
|
||||
@ -736,14 +768,13 @@ impl RStatementEnum {
|
||||
}
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
}
|
||||
Self::BuiltinFunction(v, args) => v.run(args, vars),
|
||||
Self::Switch(switch_on, cases) => {
|
||||
let switch_on = switch_on.run(vars);
|
||||
let switch_on = switch_on.run(vars, libs);
|
||||
let switch_on_type = switch_on.out();
|
||||
let mut out = VDataEnum::Tuple(vec![]).to();
|
||||
for (case_type, case_action) in cases.iter() {
|
||||
if switch_on_type.fits_in(case_type).is_empty() {
|
||||
out = case_action.run(vars);
|
||||
out = case_action.run(vars, libs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -752,7 +783,7 @@ impl RStatementEnum {
|
||||
Self::Match(match_on, cases) => 'm: {
|
||||
for (case_condition, case_action) in cases {
|
||||
// [t] => Some(t), t => Some(t), [] => None
|
||||
if let Some(v) = match case_condition.run(vars).data {
|
||||
if let Some(v) = match case_condition.run(vars, libs).data {
|
||||
VDataEnum::Tuple(mut tuple) => tuple.pop(),
|
||||
VDataEnum::Bool(v) => if v { Some(VDataEnum::Bool(v).to()) } else { None },
|
||||
other => Some(other.to()),
|
||||
@ -760,14 +791,14 @@ impl RStatementEnum {
|
||||
let og = {
|
||||
std::mem::replace(&mut *vars[*match_on].lock().unwrap(), v)
|
||||
};
|
||||
let res = case_action.run(vars);
|
||||
let res = case_action.run(vars, libs);
|
||||
*vars[*match_on].lock().unwrap() = og;
|
||||
break 'm res;
|
||||
}
|
||||
}
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
}
|
||||
Self::IndexFixed(st, i) => st.run(vars).get(*i).unwrap(),
|
||||
Self::IndexFixed(st, i) => st.run(vars, libs).get(*i).unwrap(),
|
||||
}
|
||||
}
|
||||
pub fn out(&self) -> VType {
|
||||
@ -796,6 +827,7 @@ impl RStatementEnum {
|
||||
}
|
||||
}
|
||||
Self::FunctionCall(f, args) => f.out_vt(&args.iter().map(|v| v.out()).collect()),
|
||||
Self::LibFunction(.., out) => out.clone(),
|
||||
Self::Block(b) => b.out(),
|
||||
Self::If(_, a, b) => {
|
||||
if let Some(b) = b {
|
||||
@ -877,13 +909,14 @@ impl RStatementEnum {
|
||||
pub struct RScript {
|
||||
main: RFunction,
|
||||
vars: usize,
|
||||
libs: Arc<Vec<libs::Lib>>,
|
||||
}
|
||||
impl RScript {
|
||||
fn new(main: RFunction, vars: usize) -> Result<Self, ToRunnableError> {
|
||||
fn new(main: RFunction, vars: usize, libs: Arc<Vec<libs::Lib>>) -> Result<Self, ToRunnableError> {
|
||||
if main.inputs.len() != 1 {
|
||||
return Err(ToRunnableError::MainWrongInput);
|
||||
}
|
||||
Ok(Self { main, vars })
|
||||
Ok(Self { main, vars, libs })
|
||||
}
|
||||
pub fn run(&self, args: Vec<String>) -> VData {
|
||||
let mut vars = Vec::with_capacity(self.vars);
|
||||
@ -897,7 +930,7 @@ impl RScript {
|
||||
for _i in 1..self.vars {
|
||||
vars.push(am(VDataEnum::Tuple(vec![]).to()));
|
||||
}
|
||||
self.main.run(&vars)
|
||||
self.main.run(&vars, &self.libs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::libs;
|
||||
|
||||
use super::{
|
||||
block::RStatement,
|
||||
val_data::{VData, VDataEnum, VDataThreadEnum},
|
||||
@ -505,16 +507,21 @@ impl BuiltinFunction {
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn run(&self, args: &Vec<RStatement>, vars: &Vec<Arc<Mutex<VData>>>) -> VData {
|
||||
pub fn run(
|
||||
&self,
|
||||
args: &Vec<RStatement>,
|
||||
vars: &Vec<Arc<Mutex<VData>>>,
|
||||
libs: &Arc<Vec<libs::Lib>>,
|
||||
) -> VData {
|
||||
match self {
|
||||
Self::Assume1 => {
|
||||
if let VDataEnum::Tuple(mut v) = args[0].run(vars).data {
|
||||
if let VDataEnum::Tuple(mut v) = args[0].run(vars, libs).data {
|
||||
v.pop().unwrap()
|
||||
} else {
|
||||
panic!(
|
||||
"ASSUMPTION FAILED: assume1 :: {}",
|
||||
if args.len() > 1 {
|
||||
if let VDataEnum::String(v) = args[1].run(vars).data {
|
||||
if let VDataEnum::String(v) = args[1].run(vars, libs).data {
|
||||
v
|
||||
} else {
|
||||
String::new()
|
||||
@ -526,7 +533,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
}
|
||||
BuiltinFunction::Print => {
|
||||
if let VDataEnum::String(arg) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(arg) = args[0].run(vars, libs).data {
|
||||
print!("{}", arg);
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
} else {
|
||||
@ -534,7 +541,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
}
|
||||
BuiltinFunction::Println => {
|
||||
if let VDataEnum::String(arg) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(arg) = args[0].run(vars, libs).data {
|
||||
println!("{}", arg);
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
} else {
|
||||
@ -542,7 +549,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
}
|
||||
BuiltinFunction::Debug => {
|
||||
println!("{:#?}", args[0].run(vars).data);
|
||||
println!("{:#?}", args[0].run(vars, libs).data);
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
}
|
||||
Self::StdinReadLine => {
|
||||
@ -551,13 +558,15 @@ impl BuiltinFunction {
|
||||
VDataEnum::String(line.trim_end_matches(['\n', '\r']).to_string()).to()
|
||||
}
|
||||
BuiltinFunction::ToString => {
|
||||
VDataEnum::String(format!("{}", args[0].run(vars).data)).to()
|
||||
VDataEnum::String(format!("{}", args[0].run(vars, libs).data)).to()
|
||||
}
|
||||
BuiltinFunction::Format => {
|
||||
if let VDataEnum::String(mut text) = args.first().unwrap().run(vars).data {
|
||||
if let VDataEnum::String(mut text) = args.first().unwrap().run(vars, libs).data {
|
||||
for (i, arg) in args.iter().skip(1).enumerate() {
|
||||
text =
|
||||
text.replace(&format!("{{{i}}}"), &format!("{}", arg.run(vars).data));
|
||||
text = text.replace(
|
||||
&format!("{{{i}}}"),
|
||||
&format!("{}", arg.run(vars, libs).data),
|
||||
);
|
||||
}
|
||||
VDataEnum::String(text).to()
|
||||
} else {
|
||||
@ -566,7 +575,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
BuiltinFunction::ParseInt => {
|
||||
if args.len() == 1 {
|
||||
if let VDataEnum::String(s) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(s) = args[0].run(vars, libs).data {
|
||||
if let Ok(s) = s.parse() {
|
||||
VDataEnum::Int(s).to()
|
||||
} else {
|
||||
@ -581,7 +590,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
BuiltinFunction::ParseFloat => {
|
||||
if args.len() == 1 {
|
||||
if let VDataEnum::String(s) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(s) = args[0].run(vars, libs).data {
|
||||
if let Ok(s) = s.parse() {
|
||||
VDataEnum::Float(s).to()
|
||||
} else {
|
||||
@ -596,15 +605,15 @@ impl BuiltinFunction {
|
||||
}
|
||||
BuiltinFunction::Run => {
|
||||
if args.len() >= 1 {
|
||||
if let VDataEnum::Function(f) = args[0].run(vars).data {
|
||||
if let VDataEnum::Function(f) = args[0].run(vars, libs).data {
|
||||
if f.inputs.len() != args.len() - 1 {
|
||||
unreachable!()
|
||||
}
|
||||
for (i, var) in f.inputs.iter().enumerate() {
|
||||
let val = args[i + 1].run(vars);
|
||||
let val = args[i + 1].run(vars, libs);
|
||||
*vars[*var].lock().unwrap() = val;
|
||||
}
|
||||
f.run(vars)
|
||||
f.run(vars, libs)
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
@ -614,7 +623,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
BuiltinFunction::Thread => {
|
||||
if args.len() >= 1 {
|
||||
if let VDataEnum::Function(f) = args[0].run(vars).data {
|
||||
if let VDataEnum::Function(f) = args[0].run(vars, libs).data {
|
||||
if f.inputs.len() != args.len() - 1 {
|
||||
unreachable!()
|
||||
}
|
||||
@ -622,14 +631,15 @@ impl BuiltinFunction {
|
||||
let mut thread_vars = vars.clone();
|
||||
let mut run_input_types = vec![];
|
||||
for (i, var) in f.inputs.iter().enumerate() {
|
||||
let val = args[i + 1].run(vars);
|
||||
let val = args[i + 1].run(vars, libs);
|
||||
run_input_types.push(val.out_single());
|
||||
thread_vars[*var] = Arc::new(Mutex::new(val));
|
||||
}
|
||||
let out_type = f.out(&run_input_types);
|
||||
let libs = libs.clone();
|
||||
VDataEnum::Thread(
|
||||
VDataThreadEnum::Running(std::thread::spawn(move || {
|
||||
f.run(&thread_vars)
|
||||
f.run(&thread_vars, &libs)
|
||||
}))
|
||||
.to(),
|
||||
out_type,
|
||||
@ -644,7 +654,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
BuiltinFunction::Await => {
|
||||
if args.len() == 1 {
|
||||
if let VDataEnum::Thread(t, _) = args[0].run(vars).data {
|
||||
if let VDataEnum::Thread(t, _) = args[0].run(vars, libs).data {
|
||||
t.get()
|
||||
} else {
|
||||
unreachable!()
|
||||
@ -655,7 +665,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
BuiltinFunction::Sleep => {
|
||||
if args.len() == 1 {
|
||||
match args[0].run(vars).data {
|
||||
match args[0].run(vars, libs).data {
|
||||
VDataEnum::Int(v) => std::thread::sleep(Duration::from_secs(v as _)),
|
||||
VDataEnum::Float(v) => std::thread::sleep(Duration::from_secs_f64(v)),
|
||||
_ => unreachable!(),
|
||||
@ -667,7 +677,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Exit => {
|
||||
if let Some(s) = args.first() {
|
||||
if let VDataEnum::Int(v) = s.run(vars).data {
|
||||
if let VDataEnum::Int(v) = s.run(vars, libs).data {
|
||||
std::process::exit(v as _);
|
||||
} else {
|
||||
std::process::exit(1);
|
||||
@ -678,7 +688,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::FsList => {
|
||||
if args.len() > 0 {
|
||||
if let VDataEnum::String(path) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(path) = args[0].run(vars, libs).data {
|
||||
if args.len() > 1 {
|
||||
todo!("fs_list advanced filters")
|
||||
}
|
||||
@ -713,7 +723,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::FsRead => {
|
||||
if args.len() > 0 {
|
||||
if let VDataEnum::String(path) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(path) = args[0].run(vars, libs).data {
|
||||
if let Ok(data) = std::fs::read(path) {
|
||||
VDataEnum::List(
|
||||
VSingleType::Int.into(),
|
||||
@ -735,7 +745,7 @@ impl BuiltinFunction {
|
||||
Self::FsWrite => {
|
||||
if args.len() > 1 {
|
||||
if let (VDataEnum::String(path), VDataEnum::List(_, data)) =
|
||||
(args[0].run(vars).data, args[1].run(vars).data)
|
||||
(args[0].run(vars, libs).data, args[1].run(vars, libs).data)
|
||||
{
|
||||
if let Some(bytes) = vdata_to_bytes(&data) {
|
||||
let file_path: PathBuf = path.into();
|
||||
@ -760,7 +770,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::BytesToString => {
|
||||
if args.len() == 1 {
|
||||
if let VDataEnum::List(_, byte_data) = args[0].run(vars).data {
|
||||
if let VDataEnum::List(_, byte_data) = args[0].run(vars, libs).data {
|
||||
if let Some(bytes) = vdata_to_bytes(&byte_data) {
|
||||
match String::from_utf8(bytes) {
|
||||
Ok(v) => VDataEnum::String(v).to(),
|
||||
@ -788,7 +798,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::StringToBytes => {
|
||||
if args.len() == 1 {
|
||||
if let VDataEnum::String(s) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(s) = args[0].run(vars, libs).data {
|
||||
VDataEnum::List(
|
||||
VSingleType::Int.into(),
|
||||
s.bytes().map(|v| VDataEnum::Int(v as isize).to()).collect(),
|
||||
@ -803,10 +813,10 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::RunCommand | Self::RunCommandGetBytes => {
|
||||
if args.len() > 0 {
|
||||
if let VDataEnum::String(s) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(s) = args[0].run(vars, libs).data {
|
||||
let mut command = std::process::Command::new(s);
|
||||
if args.len() > 1 {
|
||||
if let VDataEnum::List(_, args) = args[1].run(vars).data {
|
||||
if let VDataEnum::List(_, args) = args[1].run(vars, libs).data {
|
||||
for arg in args {
|
||||
if let VDataEnum::String(v) = arg.data {
|
||||
command.arg(v);
|
||||
@ -865,7 +875,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Add => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a + b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a as f64 + b).to()
|
||||
@ -882,7 +892,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Sub => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a - b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a as f64 - b).to()
|
||||
@ -899,7 +909,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Mul => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a * b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a as f64 * b).to()
|
||||
@ -916,7 +926,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Div => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a / b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a as f64 / b).to()
|
||||
@ -933,7 +943,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Mod => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a % b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a as f64 % b).to()
|
||||
@ -950,7 +960,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Pow => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(if b == 0 {
|
||||
1
|
||||
} else if b > 0 {
|
||||
@ -976,7 +986,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Eq => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a == b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Bool(a as f64 == b).to()
|
||||
@ -996,7 +1006,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Gt => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a > b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Bool(a as f64 > b).to()
|
||||
@ -1013,7 +1023,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Lt => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a < b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Bool((a as f64) < b).to()
|
||||
@ -1030,7 +1040,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Gtoe => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a >= b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Bool(a as f64 >= b).to()
|
||||
@ -1047,7 +1057,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Ltoe => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a <= b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Bool(a as f64 <= b).to()
|
||||
@ -1064,7 +1074,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Min => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a.min(b)).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float((a as f64).min(b)).to()
|
||||
@ -1083,7 +1093,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Max => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a.max(b)).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float((a as f64).max(b)).to()
|
||||
@ -1102,9 +1112,9 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Push => {
|
||||
if args.len() == 2 {
|
||||
if let VDataEnum::Reference(v) = args[0].run(vars).data {
|
||||
if let VDataEnum::Reference(v) = args[0].run(vars, libs).data {
|
||||
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
|
||||
v.push(args[1].run(vars));
|
||||
v.push(args[1].run(vars, libs));
|
||||
}
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
} else {
|
||||
@ -1117,10 +1127,10 @@ impl BuiltinFunction {
|
||||
Self::Insert => {
|
||||
if args.len() == 3 {
|
||||
if let (VDataEnum::Reference(v), VDataEnum::Int(i)) =
|
||||
(args[0].run(vars).data, args[2].run(vars).data)
|
||||
(args[0].run(vars, libs).data, args[2].run(vars, libs).data)
|
||||
{
|
||||
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
|
||||
v.insert(i as _, args[1].run(vars));
|
||||
v.insert(i as _, args[1].run(vars, libs));
|
||||
}
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
} else {
|
||||
@ -1132,7 +1142,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Pop => {
|
||||
if args.len() == 1 {
|
||||
if let VDataEnum::Reference(v) = args[0].run(vars).data {
|
||||
if let VDataEnum::Reference(v) = args[0].run(vars, libs).data {
|
||||
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
|
||||
v.pop().unwrap_or_else(|| VDataEnum::Tuple(vec![]).to())
|
||||
} else {
|
||||
@ -1148,7 +1158,7 @@ impl BuiltinFunction {
|
||||
Self::Remove => {
|
||||
if args.len() == 2 {
|
||||
if let (VDataEnum::Reference(v), VDataEnum::Int(i)) =
|
||||
(args[0].run(vars).data, args[1].run(vars).data)
|
||||
(args[0].run(vars, libs).data, args[1].run(vars, libs).data)
|
||||
{
|
||||
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
|
||||
if v.len() > i as _ && i >= 0 {
|
||||
@ -1169,19 +1179,21 @@ impl BuiltinFunction {
|
||||
Self::Get => {
|
||||
if args.len() == 2 {
|
||||
if let (VDataEnum::Reference(v), VDataEnum::Int(i)) =
|
||||
(args[0].run(vars).data, args[1].run(vars).data)
|
||||
(args[0].run(vars, libs).data, args[1].run(vars, libs).data)
|
||||
{
|
||||
if let VDataEnum::List(_, v) | VDataEnum::Tuple(v) =
|
||||
&mut v.lock().unwrap().data
|
||||
{
|
||||
if let VDataEnum::List(_, v) = &mut v.lock().unwrap().data {
|
||||
if i >= 0 {
|
||||
match v.get(i as usize) {
|
||||
Some(v) => v.clone(),
|
||||
Some(v) => VDataEnum::Tuple(vec![v.clone()]).to(),
|
||||
None => VDataEnum::Tuple(vec![]).to(),
|
||||
}
|
||||
} else {
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
}
|
||||
} else {
|
||||
unreachable!("get: not a list")
|
||||
unreachable!("get: not a list/tuple")
|
||||
}
|
||||
} else {
|
||||
unreachable!("get: not a reference and index")
|
||||
@ -1192,7 +1204,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Len => {
|
||||
if args.len() == 1 {
|
||||
VDataEnum::Int(match args[0].run(vars).data {
|
||||
VDataEnum::Int(match args[0].run(vars, libs).data {
|
||||
VDataEnum::String(v) => v.len(),
|
||||
VDataEnum::Tuple(v) => v.len(),
|
||||
VDataEnum::List(_, v) => v.len(),
|
||||
@ -1205,8 +1217,8 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Contains => {
|
||||
if args.len() == 2 {
|
||||
if let VDataEnum::String(a1) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(a2) = args[1].run(vars).data {
|
||||
if let VDataEnum::String(a1) = args[0].run(vars, libs).data {
|
||||
if let VDataEnum::String(a2) = args[1].run(vars, libs).data {
|
||||
VDataEnum::Bool(a1.contains(a2.as_str())).to()
|
||||
} else {
|
||||
unreachable!()
|
||||
@ -1220,8 +1232,8 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::StartsWith => {
|
||||
if args.len() == 2 {
|
||||
if let VDataEnum::String(a1) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(a2) = args[1].run(vars).data {
|
||||
if let VDataEnum::String(a1) = args[0].run(vars, libs).data {
|
||||
if let VDataEnum::String(a2) = args[1].run(vars, libs).data {
|
||||
VDataEnum::Bool(a1.starts_with(a2.as_str())).to()
|
||||
} else {
|
||||
unreachable!()
|
||||
@ -1235,8 +1247,8 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::EndsWith => {
|
||||
if args.len() == 2 {
|
||||
if let VDataEnum::String(a1) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(a2) = args[1].run(vars).data {
|
||||
if let VDataEnum::String(a1) = args[0].run(vars, libs).data {
|
||||
if let VDataEnum::String(a2) = args[1].run(vars, libs).data {
|
||||
VDataEnum::Bool(a1.ends_with(a2.as_str())).to()
|
||||
} else {
|
||||
unreachable!()
|
||||
@ -1250,7 +1262,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Trim => {
|
||||
if args.len() == 1 {
|
||||
if let VDataEnum::String(a) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(a) = args[0].run(vars, libs).data {
|
||||
VDataEnum::String(a.trim().to_string()).to()
|
||||
} else {
|
||||
unreachable!()
|
||||
@ -1261,17 +1273,17 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Substring => {
|
||||
if args.len() >= 2 {
|
||||
if let VDataEnum::String(a) = args[0].run(vars).data {
|
||||
if let VDataEnum::String(a) = args[0].run(vars, libs).data {
|
||||
if args.len() > 3 {
|
||||
unreachable!()
|
||||
}
|
||||
let left = if let VDataEnum::Int(left) = args[1].run(vars).data {
|
||||
let left = if let VDataEnum::Int(left) = args[1].run(vars, libs).data {
|
||||
left
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
let len = if args.len() == 3 {
|
||||
if let VDataEnum::Int(len) = args[2].run(vars).data {
|
||||
if let VDataEnum::Int(len) = args[2].run(vars, libs).data {
|
||||
Some(len)
|
||||
} else {
|
||||
unreachable!()
|
||||
@ -1300,7 +1312,7 @@ impl BuiltinFunction {
|
||||
Self::Regex => {
|
||||
if args.len() == 2 {
|
||||
if let (VDataEnum::String(a), VDataEnum::String(regex)) =
|
||||
(args[0].run(vars).data, args[1].run(vars).data)
|
||||
(args[0].run(vars, libs).data, args[1].run(vars, libs).data)
|
||||
{
|
||||
match regex::Regex::new(regex.as_str()) {
|
||||
Ok(regex) => {
|
||||
|
Loading…
Reference in New Issue
Block a user