error handling

This commit is contained in:
Altareos
2022-06-03 12:39:14 +02:00
parent d8166a9ff6
commit 9e6f0c454a
4 changed files with 70 additions and 5 deletions

26
sample/handle.pl.xml Normal file
View File

@@ -0,0 +1,26 @@
<program name="handle">
<main>
<handle>
<try>
<integer value="non" />
<call function="print-line">
<arguments>
<string value="there is no bug" />
</arguments>
</call>
</try>
<catch variable="err">
<call function="print-line">
<arguments>
<string value="oh no there is a bug" />
</arguments>
</call>
<call function="print-line">
<arguments>
<value variable="err" />
</arguments>
</call>
</catch>
</handle>
</main>
</program>

View File

@@ -17,7 +17,7 @@ pub struct MissingAttribute(pub &'static str, pub &'static str);
impl fmt::Display for MissingAttribute { impl fmt::Display for MissingAttribute {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 {} 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 {}

View File

@@ -43,6 +43,7 @@ pub enum Instruction {
}, },
Each(String, Box<Instruction>, Vec<Instruction>), Each(String, Box<Instruction>, Vec<Instruction>),
While(Box<Instruction>, Vec<Instruction>), While(Box<Instruction>, Vec<Instruction>),
Handle(Vec<Instruction>, Vec<Instruction>, String),
} }
impl Instruction { impl Instruction {
@@ -230,6 +231,19 @@ impl Instruction {
util::find_node(&node, "do").ok_or(MissingChild("while", "from"))?, 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))?, tag => Err(format!("unknown tag '{}'", tag))?,
}) })
} }
@@ -698,6 +712,18 @@ impl Instruction {
} }
None 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 { } else {
None None

View File

@@ -1,3 +1,5 @@
use crate::error::InaccessibleFile;
use super::error::{BadArgumentCount, InvalidArgument}; use super::error::{BadArgumentCount, InvalidArgument};
use super::{Context, Value}; use super::{Context, Value};
use std::cell::RefCell; use std::cell::RefCell;
@@ -232,12 +234,12 @@ fn write_file(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
.open(path) .open(path)
{ {
if let Ok(_) = write!(file, "{}", contents) { if let Ok(_) = write!(file, "{}", contents) {
Ok(Some(Value::Integer(1))) Ok(None)
} else { } else {
Ok(Some(Value::Integer(0))) Err(InaccessibleFile(path.clone()).into())
} }
} else { } else {
Ok(Some(Value::Integer(0))) Err(InaccessibleFile(path.clone()).into())
} }
} else { } else {
Err(InvalidArgument("write-file", "string").into()) Err(InvalidArgument("write-file", "string").into())
@@ -256,7 +258,7 @@ fn read_file(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
if let Ok(contents) = fs::read_to_string(path) { if let Ok(contents) = fs::read_to_string(path) {
Ok(Some(Value::String(contents))) Ok(Some(Value::String(contents)))
} else { } else {
Ok(None) Err(InaccessibleFile(path.clone()).into())
} }
} else { } else {
Err(InvalidArgument("read-file", "string").into()) Err(InvalidArgument("read-file", "string").into())