- 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
This commit is contained in:
Dummi26 2023-03-12 13:14:18 +01:00
parent 369b37371c
commit 05ecc809c3
3 changed files with 68 additions and 15 deletions

View File

@ -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)?));

View File

@ -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 {
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 {
for (i, v) in v.iter().enumerate() {
if i != 0 {
write!(f, " {v}")?;
} else {
write!(f, "{v}")?;
}
}
match self {
Self::List(..) => write!(f, "...")?,

View File

@ -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<ExitCode>, 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<RStatement>, vars: &Vec<Arc<Mutex<VData>>>) -> 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(
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(
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(),