From 05ecc809c3f036db143330204bed17288292f62c Mon Sep 17 00:00:00 2001 From: Dummi26 Date: Sun, 12 Mar 2023 13:14:18 +0100 Subject: [PATCH] - fixed a bug with switch syntax closing brace being recognized twice by the parser - writing to a variable when the type that is being written doesn't fit will shadow the variable to prevent weird issues where a variable would be changed to a different type from within a block, then after that block it would still have data of that type but its type wouldn't reflect this, causing switch! to miss some cases. might remove shadowing in the future, who knows. - added run_command_get_bytes --- src/parse/parse.rs | 1 + src/script/block.rs | 32 +++++++++++++++++++++------ src/script/builtins.rs | 50 +++++++++++++++++++++++++++++++++++------- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/parse/parse.rs b/src/parse/parse.rs index fb41c1d..23993ee 100644 --- a/src/parse/parse.rs +++ b/src/parse/parse.rs @@ -266,6 +266,7 @@ fn parse_statement_adv( loop { file.skip_whitespaces(); if let Some('}') = file.peek() { + file.next(); break; } cases.push((parse_type(file)?, parse_statement(file)?)); diff --git a/src/script/block.rs b/src/script/block.rs index 1981693..3b40c88 100644 --- a/src/script/block.rs +++ b/src/script/block.rs @@ -400,9 +400,19 @@ pub mod to_runnable { } .to(); if let Some(opt) = &s.output_to { - if let Some(var) = linfo.vars.get_mut(opt) { - var.1 = var.1.clone() | statement.out(); - statement.output_to = Some(var.0); + if let Some(var) = linfo.vars.get(opt) { + let out = statement.out(); + let var_id = var.0; + let var_out = &var.1; + let inv_types = out.fits_in(&var_out); + if !inv_types.is_empty() { + eprintln!("Warn: shadowing variable {opt} because statement's output type {out} does not fit in the original variable's {var_out}. This might become an error in the future, or it might stop shadowing the variiable entirely - for stable scripts, avoid this by giving the variable a different name."); + linfo.vars.insert(opt.clone(), (ginfo.vars, out)); + statement.output_to = Some(ginfo.vars); + ginfo.vars += 1; + } else { + statement.output_to = Some(var_id); + } } else { linfo .vars @@ -728,8 +738,12 @@ impl Display for VSingleType { Self::String => write!(f, "string"), Self::Tuple(types) => { write!(f, "[")?; - for t in types { - write!(f, "{t}")?; + for (i, t) in types.iter().enumerate() { + if i != 0 { + write!(f, " {t}")?; + } else { + write!(f, "{t}")?; + } } write!(f, "]")?; Ok(()) @@ -829,8 +843,12 @@ impl Display for VDataEnum { Self::String(v) => write!(f, "{v}"), Self::Tuple(v) | Self::List(_, v) => { write!(f, "[")?; - for v in v { - write!(f, "{v}")?; + for (i, v) in v.iter().enumerate() { + if i != 0 { + write!(f, " {v}")?; + } else { + write!(f, "{v}")?; + } } match self { Self::List(..) => write!(f, "...")?, diff --git a/src/script/builtins.rs b/src/script/builtins.rs index ebfea90..b914d85 100644 --- a/src/script/builtins.rs +++ b/src/script/builtins.rs @@ -38,6 +38,7 @@ pub enum BuiltinFunction { StringToBytes, // OS RunCommand, + RunCommandGetBytes, } impl BuiltinFunction { @@ -60,6 +61,7 @@ impl BuiltinFunction { "bytes_to_string" => Self::BytesToString, "string_to_bytes" => Self::StringToBytes, "run_command" => Self::RunCommand, + "run_command_get_bytes" => Self::RunCommandGetBytes, _ => return None, }) } @@ -120,6 +122,20 @@ impl BuiltinFunction { ]), ], }, + Self::RunCommandGetBytes => VType { + types: vec![ + // error + VSingleType::String.into(), + // success: Option, stdout, stderr + VSingleType::Tuple(vec![ + VType { + types: vec![VSingleType::Tuple(vec![]).into(), VSingleType::Int.into()], + }, + VSingleType::List(VSingleType::Int.into()).into(), + VSingleType::List(VSingleType::Int.into()).into(), + ]), + ], + }, } } pub fn run(&self, args: &Vec, vars: &Vec>>) -> VData { @@ -129,7 +145,7 @@ impl BuiltinFunction { print!("{}", arg); VDataEnum::Tuple(vec![]).to() } else { - unreachable!() + unreachable!("print function called with non-string arg") } } BuiltinFunction::Println => { @@ -365,7 +381,7 @@ impl BuiltinFunction { unreachable!("string_to_bytes not 1 arg") } } - Self::RunCommand => { + Self::RunCommand | Self::RunCommandGetBytes => { if args.len() > 0 { if let VDataEnum::String(s) = args[0].run(vars).data { let mut command = std::process::Command::new(s); @@ -390,13 +406,31 @@ impl BuiltinFunction { VDataEnum::Tuple(vec![]) } .to(), - VDataEnum::String( - String::from_utf8_lossy(&out.stdout).into_owned(), - ) + match self { + Self::RunCommandGetBytes => VDataEnum::List( + VSingleType::Int.into(), + out.stdout + .iter() + .map(|v| VDataEnum::Int(*v as _).to()) + .collect(), + ), + _ => VDataEnum::String( + String::from_utf8_lossy(&out.stdout).into_owned(), + ), + } .to(), - VDataEnum::String( - String::from_utf8_lossy(&out.stderr).into_owned(), - ) + match self { + Self::RunCommandGetBytes => VDataEnum::List( + VSingleType::Int.into(), + out.stderr + .iter() + .map(|v| VDataEnum::Int(*v as _).to()) + .collect(), + ), + _ => VDataEnum::String( + String::from_utf8_lossy(&out.stderr).into_owned(), + ), + } .to(), ]) .to(),