error handling
This commit is contained in:
26
sample/handle.pl.xml
Normal file
26
sample/handle.pl.xml
Normal 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>
|
||||||
13
src/error.rs
13
src/error.rs
@@ -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 {}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
10
src/stl.rs
10
src/stl.rs
@@ -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())
|
||||||
|
|||||||
Reference in New Issue
Block a user