mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FEATURE: Allow BuildErrors to wrap other errors.
This commit is contained in:
parent
d2bd18b647
commit
014710a4ba
@ -143,13 +143,7 @@ fn test_type_checks() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "UserDefined")]
|
||||
fn test_declarative_failures_are_user_defined() {
|
||||
assert_build("fail \"I am a failure!\";");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Caused By:\n\tI am a failure!")]
|
||||
#[should_panic(expected = "UserDefined: I am a failure!")]
|
||||
fn test_declarative_failures_are_caused_by_msg() {
|
||||
assert_build("fail \"I am a failure!\";");
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ impl<V: Into<String> + Clone> FormatRenderer for SimpleFormatter<V> {
|
||||
for c in self.tmpl.chars() {
|
||||
if c == '@' && !should_escape {
|
||||
if count == self.args.len() {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
"Too few arguments to string \
|
||||
formatter.",
|
||||
error::ErrorType::FormatError,
|
||||
@ -72,7 +72,7 @@ impl<V: Into<String> + Clone> FormatRenderer for SimpleFormatter<V> {
|
||||
}
|
||||
}
|
||||
if self.args.len() != count {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
"Too many arguments to string \
|
||||
formatter.",
|
||||
error::ErrorType::FormatError,
|
||||
@ -111,7 +111,7 @@ impl<'a> ExpressionFormatter<'a> {
|
||||
if c == '{' {
|
||||
brace_count += 1;
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Invalid syntax for format string expected '{{' but got {}",
|
||||
c
|
||||
@ -122,7 +122,7 @@ impl<'a> ExpressionFormatter<'a> {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
"Invalid syntax for format string expected '{' but string ended",
|
||||
error::ErrorType::FormatError,
|
||||
pos.clone(),
|
||||
@ -148,7 +148,7 @@ impl<'a> ExpressionFormatter<'a> {
|
||||
}
|
||||
// empty expressions are an error
|
||||
if expr_string.is_empty() {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
"Got an empty expression in format string",
|
||||
error::ErrorType::FormatError,
|
||||
pos.clone(),
|
||||
@ -163,7 +163,7 @@ impl<'a> ExpressionFormatter<'a> {
|
||||
expr_string.push(c);
|
||||
}
|
||||
}
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
"Expected '}' but got end of string",
|
||||
error::ErrorType::FormatError,
|
||||
pos.clone(),
|
||||
|
131
src/build/mod.rs
131
src/build/mod.rs
@ -61,7 +61,7 @@ impl FuncDef {
|
||||
// Error conditions. If the args don't match the length and types of the argdefs then this is
|
||||
// func call error.
|
||||
if args.len() > self.argdefs.len() {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
"Func called with too many args",
|
||||
error::ErrorType::BadArgLen,
|
||||
self.pos.clone(),
|
||||
@ -129,7 +129,7 @@ macro_rules! eval_binary_expr {
|
||||
return Ok(Rc::new($result));
|
||||
}
|
||||
val => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected {} but got ({})", $msg, val),
|
||||
error::ErrorType::TypeFail,
|
||||
$pos.clone(),
|
||||
@ -277,13 +277,15 @@ impl<'a> FileBuilder<'a> {
|
||||
&Value::Int(ref i) => Ok(Rc::new(Val::Int(i.val))),
|
||||
&Value::Float(ref f) => Ok(Rc::new(Val::Float(f.val))),
|
||||
&Value::Str(ref s) => Ok(Rc::new(Val::Str(s.val.to_string()))),
|
||||
&Value::Symbol(ref s) => scope.lookup_sym(&(s.into()), true).ok_or(Box::new(
|
||||
error::BuildError::new_with_pos(
|
||||
format!("Unable to find binding {}", s.val,),
|
||||
error::ErrorType::NoSuchSymbol,
|
||||
v.pos().clone(),
|
||||
),
|
||||
)),
|
||||
&Value::Symbol(ref s) => {
|
||||
scope
|
||||
.lookup_sym(&(s.into()), true)
|
||||
.ok_or(Box::new(error::BuildError::with_pos(
|
||||
format!("Unable to find binding {}", s.val,),
|
||||
error::ErrorType::NoSuchSymbol,
|
||||
v.pos().clone(),
|
||||
)))
|
||||
}
|
||||
&Value::List(ref def) => self.eval_list(def, scope),
|
||||
&Value::Tuple(ref tuple) => self.eval_tuple(&tuple.val, scope),
|
||||
}
|
||||
@ -327,7 +329,7 @@ impl<'a> FileBuilder<'a> {
|
||||
Some(val) => Ok(val),
|
||||
}
|
||||
}
|
||||
Err(err) => Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(err) => Err(Box::new(error::BuildError::with_pos(
|
||||
format!("{}", err,),
|
||||
error::ErrorType::ParseError,
|
||||
(&input).into(),
|
||||
@ -408,7 +410,7 @@ impl<'a> FileBuilder<'a> {
|
||||
mut_assets_cache.stash(path, result.clone())?;
|
||||
return Ok(result);
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("No such import {} in the std library.", def.path.fragment),
|
||||
error::ErrorType::Unsupported,
|
||||
def.pos.clone(),
|
||||
@ -418,7 +420,7 @@ impl<'a> FileBuilder<'a> {
|
||||
// Try a relative path first.
|
||||
let normalized = self.find_file(&def.path.fragment, true)?;
|
||||
if self.detect_import_cycle(normalized.to_string_lossy().as_ref()) {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Import Cycle Detected!!!! {} is already in import stack: {:?}",
|
||||
normalized.to_string_lossy(),
|
||||
@ -450,7 +452,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let val = self.eval_expr(&def.value, &child_scope)?;
|
||||
let name = &def.name;
|
||||
if Self::check_reserved_word(&name.fragment) {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Let {} binding collides with reserved word", name.fragment),
|
||||
error::ErrorType::ReservedWordError,
|
||||
name.pos.clone(),
|
||||
@ -458,7 +460,7 @@ impl<'a> FileBuilder<'a> {
|
||||
}
|
||||
match self.scope.build_output.entry(name.into()) {
|
||||
Entry::Occupied(e) => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Binding \
|
||||
for {:?} already \
|
||||
@ -490,7 +492,7 @@ impl<'a> FileBuilder<'a> {
|
||||
self.out_lock = Some((typ.fragment.to_string(), val.clone()));
|
||||
Ok(val)
|
||||
} else {
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
format!("You can only have one output per file."),
|
||||
error::ErrorType::Unsupported,
|
||||
pos.clone(),
|
||||
@ -519,7 +521,7 @@ impl<'a> FileBuilder<'a> {
|
||||
return Ok(Rc::new(Val::Str([s.to_string(), ss.clone()].concat())));
|
||||
}
|
||||
val => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected \
|
||||
String \
|
||||
@ -540,7 +542,7 @@ impl<'a> FileBuilder<'a> {
|
||||
return Ok(Rc::new(Val::List(new_vec)));
|
||||
}
|
||||
val => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected \
|
||||
List \
|
||||
@ -554,7 +556,7 @@ impl<'a> FileBuilder<'a> {
|
||||
}
|
||||
},
|
||||
ref expr => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("{} does not support the '+' operation", expr.type_name()),
|
||||
error::ErrorType::Unsupported,
|
||||
lpos.clone(),
|
||||
@ -578,7 +580,7 @@ impl<'a> FileBuilder<'a> {
|
||||
eval_binary_expr!(&Val::Float(ff), rpos, right, Val::Float(f - ff), "Float")
|
||||
}
|
||||
ref expr => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("{} does not support the '-' operation", expr.type_name()),
|
||||
error::ErrorType::Unsupported,
|
||||
lpos.clone(),
|
||||
@ -602,7 +604,7 @@ impl<'a> FileBuilder<'a> {
|
||||
eval_binary_expr!(&Val::Float(ff), rpos, right, Val::Float(f * ff), "Float")
|
||||
}
|
||||
ref expr => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("{} does not support the '*' operation", expr.type_name()),
|
||||
error::ErrorType::Unsupported,
|
||||
lpos.clone(),
|
||||
@ -626,7 +628,7 @@ impl<'a> FileBuilder<'a> {
|
||||
eval_binary_expr!(&Val::Float(ff), rpos, right, Val::Float(f % ff), "Float")
|
||||
}
|
||||
ref expr => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"{} does not support the 'modulus' operation",
|
||||
expr.type_name()
|
||||
@ -653,7 +655,7 @@ impl<'a> FileBuilder<'a> {
|
||||
eval_binary_expr!(&Val::Float(ff), rpos, right, Val::Float(f / ff), "Float")
|
||||
}
|
||||
ref expr => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("{} does not support the '*' operation", expr.type_name()),
|
||||
error::ErrorType::Unsupported,
|
||||
lpos.clone(),
|
||||
@ -670,7 +672,7 @@ impl<'a> FileBuilder<'a> {
|
||||
) -> Result<Rc<Val>, Box<dyn Error>> {
|
||||
match left.equal(right.as_ref()) {
|
||||
Ok(b) => Ok(Rc::new(Val::Boolean(b))),
|
||||
Err(e) => Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(e) => Err(Box::new(error::BuildError::with_pos(
|
||||
e.msg,
|
||||
e.err_type,
|
||||
pos.clone(),
|
||||
@ -686,7 +688,7 @@ impl<'a> FileBuilder<'a> {
|
||||
) -> Result<Rc<Val>, Box<dyn Error>> {
|
||||
match left.equal(right.as_ref()) {
|
||||
Ok(b) => Ok(Rc::new(Val::Boolean(!b))),
|
||||
Err(e) => Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(e) => Err(Box::new(error::BuildError::with_pos(
|
||||
e.msg,
|
||||
e.err_type,
|
||||
pos.clone(),
|
||||
@ -711,7 +713,7 @@ impl<'a> FileBuilder<'a> {
|
||||
return Ok(Rc::new(Val::Boolean(l > r)));
|
||||
}
|
||||
}
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected {} but got ({})", left.type_name(), right,),
|
||||
error::ErrorType::TypeFail,
|
||||
pos.clone(),
|
||||
@ -735,7 +737,7 @@ impl<'a> FileBuilder<'a> {
|
||||
return Ok(Rc::new(Val::Boolean(l < r)));
|
||||
}
|
||||
}
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected {} but got ({})", left.type_name(), right,),
|
||||
error::ErrorType::TypeFail,
|
||||
pos.clone(),
|
||||
@ -758,7 +760,7 @@ impl<'a> FileBuilder<'a> {
|
||||
return Ok(Rc::new(Val::Boolean(l <= r)));
|
||||
}
|
||||
}
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected {} but got ({})", left.type_name(), right),
|
||||
error::ErrorType::TypeFail,
|
||||
pos.clone(),
|
||||
@ -781,7 +783,7 @@ impl<'a> FileBuilder<'a> {
|
||||
return Ok(Rc::new(Val::Boolean(l >= r)));
|
||||
}
|
||||
}
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected {} but got ({})", left.type_name(), right,),
|
||||
error::ErrorType::TypeFail,
|
||||
pos.clone(),
|
||||
@ -797,7 +799,7 @@ impl<'a> FileBuilder<'a> {
|
||||
Expression::Simple(Value::Symbol(ref s)) => {
|
||||
scope
|
||||
.lookup_sym(s, true)
|
||||
.ok_or(Box::new(error::BuildError::new_with_pos(
|
||||
.ok_or(Box::new(error::BuildError::with_pos(
|
||||
format!("Unable to find binding {}", s.val,),
|
||||
error::ErrorType::NoSuchSymbol,
|
||||
pos,
|
||||
@ -806,7 +808,7 @@ impl<'a> FileBuilder<'a> {
|
||||
Expression::Simple(Value::Str(ref s)) => {
|
||||
scope
|
||||
.lookup_sym(s, false)
|
||||
.ok_or(Box::new(error::BuildError::new_with_pos(
|
||||
.ok_or(Box::new(error::BuildError::with_pos(
|
||||
format!("Unable to find binding {}", s.val,),
|
||||
error::ErrorType::NoSuchSymbol,
|
||||
pos,
|
||||
@ -821,12 +823,12 @@ impl<'a> FileBuilder<'a> {
|
||||
Val::Int(i) => scope.lookup_idx(right.pos(), &Val::Int(*i)),
|
||||
Val::Str(ref s) => scope
|
||||
.lookup_sym(&PositionedItem::new(s.clone(), pos.clone()), false)
|
||||
.ok_or(Box::new(error::BuildError::new_with_pos(
|
||||
.ok_or(Box::new(error::BuildError::with_pos(
|
||||
format!("Unable to find binding {}", s,),
|
||||
error::ErrorType::NoSuchSymbol,
|
||||
pos,
|
||||
))),
|
||||
_ => Err(Box::new(error::BuildError::new_with_pos(
|
||||
_ => Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Invalid selector lookup {}", val.type_name(),),
|
||||
error::ErrorType::NoSuchSymbol,
|
||||
pos,
|
||||
@ -867,7 +869,7 @@ impl<'a> FileBuilder<'a> {
|
||||
return Ok(right);
|
||||
}
|
||||
}
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected boolean value for operator but got ({})",
|
||||
left.type_name()
|
||||
@ -876,7 +878,7 @@ impl<'a> FileBuilder<'a> {
|
||||
right_pos.clone(),
|
||||
)));
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected boolean value for operator but got ({})",
|
||||
left.type_name()
|
||||
@ -899,7 +901,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let right = self.eval_expr(right, scope)?;
|
||||
// presence checks are only valid for tuples and lists.
|
||||
if !(right.is_tuple() || right.is_list()) {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Invalid righthand type for in operator {}",
|
||||
right.type_name()
|
||||
@ -943,7 +945,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let re = if let Val::Str(ref s) = right.as_ref() {
|
||||
regex::Regex::new(s.as_ref())?
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected string for regex but got ({})", right.type_name()),
|
||||
error::ErrorType::TypeFail,
|
||||
right_pos.clone(),
|
||||
@ -952,7 +954,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let tgt = if let Val::Str(ref s) = left.as_ref() {
|
||||
s.as_ref()
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected string but got ({})", left.type_name()),
|
||||
error::ErrorType::TypeFail,
|
||||
left_pos.clone(),
|
||||
@ -1074,7 +1076,7 @@ impl<'a> FileBuilder<'a> {
|
||||
{
|
||||
v.insert((src_val.0, expr_result));
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected type {} for field {} but got ({})",
|
||||
src_val.1.type_name(),
|
||||
@ -1132,7 +1134,7 @@ impl<'a> FileBuilder<'a> {
|
||||
PositionedItem::new_with_pos(String::from("mod"), Position::new(0, 0, 0));
|
||||
match b.scope.build_output.entry(mod_key) {
|
||||
Entry::Occupied(e) => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Binding \
|
||||
for {:?} already \
|
||||
@ -1153,7 +1155,7 @@ impl<'a> FileBuilder<'a> {
|
||||
// tuple using them.
|
||||
return Ok(b.get_outputs_as_val());
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Weird value stored in our module parameters slot {:?}",
|
||||
mod_def.arg_tuple
|
||||
@ -1163,7 +1165,7 @@ impl<'a> FileBuilder<'a> {
|
||||
)));
|
||||
}
|
||||
}
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected Tuple or Module but got ({})", v),
|
||||
error::ErrorType::TypeFail,
|
||||
def.selector.pos().clone(),
|
||||
@ -1207,14 +1209,14 @@ impl<'a> FileBuilder<'a> {
|
||||
}
|
||||
return match def.eval(self, argvals) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(e) => Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Func evaluation failed\nCaused by:\n\t{}", e),
|
||||
error::ErrorType::TypeFail,
|
||||
call_pos,
|
||||
))),
|
||||
};
|
||||
}
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
// We should pretty print the selectors here.
|
||||
format!("{} is not a Function", v),
|
||||
error::ErrorType::TypeFail,
|
||||
@ -1280,7 +1282,7 @@ impl<'a> FileBuilder<'a> {
|
||||
// Otherwise return the default.
|
||||
return self.eval_expr(def_expr, scope);
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected String but got \
|
||||
{} in Select expression",
|
||||
@ -1340,7 +1342,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let new_name = if let &Val::Str(ref s) = fs[0].as_ref() {
|
||||
s.clone()
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"map on tuple expects the first item out list to be a string but got size {}",
|
||||
fs[0].type_name()
|
||||
@ -1351,7 +1353,7 @@ impl<'a> FileBuilder<'a> {
|
||||
};
|
||||
out.push((new_name, fs[1].clone()));
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"map on a tuple field expects a list of size 2 as output but got size {}",
|
||||
fs.len()
|
||||
@ -1361,7 +1363,7 @@ impl<'a> FileBuilder<'a> {
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"map on a tuple field expects a list as output but got ({})",
|
||||
result.type_name()
|
||||
@ -1393,7 +1395,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let funcdef = match maybe_mac.as_ref() {
|
||||
&Val::Func(ref funcdef) => funcdef,
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected func but got {:?}", def.func),
|
||||
error::ErrorType::TypeFail,
|
||||
def.pos.clone(),
|
||||
@ -1423,7 +1425,7 @@ impl<'a> FileBuilder<'a> {
|
||||
}
|
||||
}
|
||||
other => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected List Str, or Tuple as target but got {:?}",
|
||||
other.type_name()
|
||||
@ -1458,7 +1460,7 @@ impl<'a> FileBuilder<'a> {
|
||||
// noop
|
||||
}
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected boolean or NULL for filter return but got ({})",
|
||||
out.type_name()
|
||||
@ -1474,7 +1476,7 @@ impl<'a> FileBuilder<'a> {
|
||||
result.push_str(&s);
|
||||
}
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected string map return but got ({})", out.type_name()),
|
||||
error::ErrorType::TypeFail,
|
||||
def.pos.clone(),
|
||||
@ -1497,7 +1499,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let macdef = match maybe_mac.as_ref() {
|
||||
&Val::Func(ref macdef) => macdef,
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected func but got {:?}", def.func),
|
||||
error::ErrorType::TypeFail,
|
||||
def.pos.clone(),
|
||||
@ -1509,7 +1511,7 @@ impl<'a> FileBuilder<'a> {
|
||||
&Val::Tuple(ref fs) => self.eval_functional_tuple_processing(fs, macdef, typ),
|
||||
// TODO(jwall): Strings?
|
||||
&Val::Str(ref s) => self.eval_functional_string_processing(s, macdef, typ),
|
||||
other => Err(Box::new(error::BuildError::new_with_pos(
|
||||
other => Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected List or Tuple as target but got {:?}",
|
||||
other.type_name()
|
||||
@ -1619,7 +1621,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let normalized = match self.find_file(path, false) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Error finding file {} {}", path, e),
|
||||
error::ErrorType::TypeFail,
|
||||
pos.clone(),
|
||||
@ -1629,7 +1631,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let mut f = match File::open(&normalized) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Error opening file {} {}", normalized.to_string_lossy(), e),
|
||||
error::ErrorType::TypeFail,
|
||||
pos.clone(),
|
||||
@ -1656,11 +1658,12 @@ impl<'a> FileBuilder<'a> {
|
||||
eprintln!("including an empty file. Use NULL as the result");
|
||||
Rc::new(Val::Empty)
|
||||
} else {
|
||||
// FIXME(jwall): This should be wrapped in a BuildError
|
||||
importer.import(file_contents.as_bytes())?
|
||||
};
|
||||
Ok(val)
|
||||
}
|
||||
None => Err(Box::new(error::BuildError::new_with_pos(
|
||||
None => Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Unknown include conversion type {}", def.typ.fragment),
|
||||
error::ErrorType::Unsupported,
|
||||
def.typ.pos.clone(),
|
||||
@ -1686,7 +1689,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let start = match start.as_ref() {
|
||||
&Val::Int(i) => i,
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected an integer for range start but got ({})",
|
||||
start.type_name()
|
||||
@ -1703,7 +1706,7 @@ impl<'a> FileBuilder<'a> {
|
||||
match step.as_ref() {
|
||||
&Val::Int(i) => i,
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected an integer for range step but got ({})",
|
||||
step.type_name()
|
||||
@ -1722,7 +1725,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let end = match end.as_ref() {
|
||||
&Val::Int(i) => i,
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected an integer for range start but got ({})",
|
||||
end.type_name()
|
||||
@ -1749,7 +1752,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let typ = match tval.as_ref() {
|
||||
Val::Str(ref s) => s.clone(),
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected string expression but got ({})", tval),
|
||||
error::ErrorType::TypeFail,
|
||||
def.right.pos().clone(),
|
||||
@ -1768,7 +1771,7 @@ impl<'a> FileBuilder<'a> {
|
||||
"func" => val.is_func(),
|
||||
"module" => val.is_module(),
|
||||
other => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Expected valid type name but got ({})", other),
|
||||
error::ErrorType::TypeFail,
|
||||
def.right.pos().clone(),
|
||||
@ -1804,13 +1807,13 @@ impl<'a> FileBuilder<'a> {
|
||||
&Expression::Fail(ref def) => {
|
||||
let err = self.eval_expr(&def.message, scope)?;
|
||||
return if let Val::Str(ref s) = err.as_ref() {
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
s.clone(),
|
||||
error::ErrorType::UserDefined,
|
||||
def.pos.clone(),
|
||||
)))
|
||||
} else {
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected string for message but got ({})",
|
||||
def.message.as_ref()
|
||||
@ -1825,7 +1828,7 @@ impl<'a> FileBuilder<'a> {
|
||||
return if let Val::Boolean(b) = val.as_ref() {
|
||||
Ok(Rc::new(Val::Boolean(!b)))
|
||||
} else {
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
format!(
|
||||
"Expected boolean for expression but got ({})",
|
||||
def.expr.as_ref()
|
||||
|
@ -115,7 +115,7 @@ impl Scope {
|
||||
return Self::lookup_in_list(pos, idx, fs);
|
||||
}
|
||||
}
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
"Not a list in index lookup.",
|
||||
error::ErrorType::TypeFail,
|
||||
pos.clone(),
|
||||
@ -189,7 +189,7 @@ impl Scope {
|
||||
if let Some(vv) = find_in_fieldlist(&field, fs) {
|
||||
Ok(vv)
|
||||
} else {
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Unable to {} match element in tuple.", field,),
|
||||
error::ErrorType::NoSuchSymbol,
|
||||
pos.clone(),
|
||||
@ -206,7 +206,7 @@ impl Scope {
|
||||
&Val::Int(i) => i as usize,
|
||||
&Val::Str(ref s) => s.parse::<usize>()?,
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new_with_pos(
|
||||
return Err(Box::new(error::BuildError::with_pos(
|
||||
format!("Invalid idx type {} for list lookup", field),
|
||||
error::ErrorType::TypeFail,
|
||||
pos.clone(),
|
||||
@ -216,7 +216,7 @@ impl Scope {
|
||||
if idx < elems.len() {
|
||||
Ok(elems[idx].clone())
|
||||
} else {
|
||||
Err(Box::new(error::BuildError::new_with_pos(
|
||||
Err(Box::new(error::BuildError::with_pos(
|
||||
format!("idx {} out of bounds in list", idx),
|
||||
error::ErrorType::NoSuchSymbol,
|
||||
pos.clone(),
|
||||
|
21
src/error.rs
21
src/error.rs
@ -61,15 +61,19 @@ pub struct BuildError {
|
||||
pub err_type: ErrorType,
|
||||
pub pos: Option<Position>,
|
||||
pub msg: String,
|
||||
pub cause: Option<Box<dyn error::Error>>,
|
||||
// This field is only present to prevent people from constructing these
|
||||
// outside of the module they are defined in.
|
||||
_pkgonly: (),
|
||||
}
|
||||
|
||||
impl BuildError {
|
||||
pub fn new_with_pos<S: Into<String>>(msg: S, t: ErrorType, pos: Position) -> Self {
|
||||
pub fn with_pos<S: Into<String>>(msg: S, t: ErrorType, pos: Position) -> Self {
|
||||
BuildError {
|
||||
err_type: t,
|
||||
pos: Some(pos),
|
||||
msg: msg.into(),
|
||||
cause: None,
|
||||
_pkgonly: (),
|
||||
}
|
||||
}
|
||||
@ -79,10 +83,16 @@ impl BuildError {
|
||||
err_type: t,
|
||||
pos: None,
|
||||
msg: msg.into(),
|
||||
cause: None,
|
||||
_pkgonly: (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wrap_cause(mut self, cause: Box<dyn error::Error>) -> Self {
|
||||
self.cause = Some(cause);
|
||||
self
|
||||
}
|
||||
|
||||
fn render(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(ref pos) = self.pos {
|
||||
let file = match pos.file {
|
||||
@ -91,11 +101,14 @@ impl BuildError {
|
||||
};
|
||||
write!(
|
||||
w,
|
||||
"{} at {} line: {}, column: {}\nCaused By:\n\t{} ",
|
||||
self.err_type, file, pos.line, pos.column, self.msg
|
||||
"{}: {} at {} line: {}, column: {}",
|
||||
self.err_type, self.msg, file, pos.line, pos.column
|
||||
)?;
|
||||
} else {
|
||||
write!(w, "{} \nCaused By:\n\t{} ", self.err_type, self.msg)?;
|
||||
write!(w, "{}: {}", self.err_type, self.msg)?;
|
||||
}
|
||||
if let Some(ref cause) = self.cause {
|
||||
write!(w, "\nCaused By:\n\t{}", cause)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user