diff --git a/sample/handle.pl.xml b/sample/handle.pl.xml new file mode 100644 index 0000000..f1ce811 --- /dev/null +++ b/sample/handle.pl.xml @@ -0,0 +1,26 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/src/error.rs b/src/error.rs index 78e0293..ba7d666 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,7 +17,7 @@ pub struct MissingAttribute(pub &'static str, pub &'static str); impl fmt::Display for MissingAttribute { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "missing '{}' child in '{}' node", self.1, self.0) + write!(f, "missing '{}' attribute in '{}' node", self.1, self.0) } } @@ -118,3 +118,14 @@ impl fmt::Display for UnknownVariable { } impl Error for UnknownVariable {} + +#[derive(Clone, Debug)] +pub struct InaccessibleFile(pub String); + +impl fmt::Display for InaccessibleFile { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "unable to access file '{}'", self.0) + } +} + +impl Error for InaccessibleFile {} diff --git a/src/instruction.rs b/src/instruction.rs index 745841e..43fe269 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -43,6 +43,7 @@ pub enum Instruction { }, Each(String, Box, Vec), While(Box, Vec), + Handle(Vec, Vec, String), } impl Instruction { @@ -230,6 +231,19 @@ impl Instruction { util::find_node(&node, "do").ok_or(MissingChild("while", "from"))?, )?, ), + "handle" => Instruction::Handle( + Instruction::from_children( + util::find_node(&node, "try").ok_or(MissingChild("handle", "try"))?, + )?, + Instruction::from_children( + util::find_node(&node, "catch").ok_or(MissingChild("handle", "try"))?, + )?, + util::find_node(&node, "catch") + .ok_or(MissingChild("handle", "try"))? + .attribute("variable") + .ok_or(MissingAttribute("catch", "variable"))? + .to_string(), + ), tag => Err(format!("unknown tag '{}'", tag))?, }) } @@ -698,6 +712,18 @@ impl Instruction { } None } + Instruction::Handle(try_block, catch_block, variable) => { + for ins in try_block { + if let Err(e) = ins.run(ctx, globals) { + ctx.assign(variable.clone(), Value::String(e.to_string())); + for ins in catch_block { + ins.run(ctx, globals)?; + } + break; + } + } + None + } } } else { None diff --git a/src/stl.rs b/src/stl.rs index 8396105..8dec93b 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -1,3 +1,5 @@ +use crate::error::InaccessibleFile; + use super::error::{BadArgumentCount, InvalidArgument}; use super::{Context, Value}; use std::cell::RefCell; @@ -232,12 +234,12 @@ fn write_file(vals: Vec) -> Result, Box> { .open(path) { if let Ok(_) = write!(file, "{}", contents) { - Ok(Some(Value::Integer(1))) + Ok(None) } else { - Ok(Some(Value::Integer(0))) + Err(InaccessibleFile(path.clone()).into()) } } else { - Ok(Some(Value::Integer(0))) + Err(InaccessibleFile(path.clone()).into()) } } else { Err(InvalidArgument("write-file", "string").into()) @@ -256,7 +258,7 @@ fn read_file(vals: Vec) -> Result, Box> { if let Ok(contents) = fs::read_to_string(path) { Ok(Some(Value::String(contents))) } else { - Ok(None) + Err(InaccessibleFile(path.clone()).into()) } } else { Err(InvalidArgument("read-file", "string").into())