diff --git a/src/ast/mod.rs b/src/ast/mod.rs index ca4ea2f..a85c19c 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -71,6 +71,11 @@ impl Position { offset: offset, } } + + pub fn with_file>(mut self, file: P) -> Self { + self.file = Some(file.into()); + self + } } impl<'a> From<&'a Position> for Position { diff --git a/src/build/format.rs b/src/build/format.rs index ec7b06c..b453aae 100644 --- a/src/build/format.rs +++ b/src/build/format.rs @@ -54,7 +54,7 @@ impl + Clone> FormatRenderer for SimpleFormatter { for c in self.tmpl.chars() { if c == '@' && !should_escape { if count == self.args.len() { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( "Too few arguments to string \ formatter.", error::ErrorType::FormatError, @@ -72,7 +72,7 @@ impl + Clone> FormatRenderer for SimpleFormatter { } } if self.args.len() != count { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_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( + return Err(Box::new(error::BuildError::new_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( + return Err(Box::new(error::BuildError::new_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( + return Err(Box::new(error::BuildError::new_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( + return Err(Box::new(error::BuildError::new_with_pos( "Expected '}' but got end of string", error::ErrorType::FormatError, pos.clone(), diff --git a/src/build/ir.rs b/src/build/ir.rs index f47abd1..37ec984 100644 --- a/src/build/ir.rs +++ b/src/build/ir.rs @@ -60,7 +60,7 @@ impl Val { ) } - pub fn equal(&self, target: &Self, pos: Position) -> Result { + pub fn equal(&self, target: &Self) -> Result { // first we do a type equality comparison match (self, target) { // Empty values are always equal. @@ -74,7 +74,7 @@ impl Val { Ok(false) } else { for (i, lv) in ldef.iter().enumerate() { - if !lv.equal(rdef[i].as_ref(), pos.clone())? { + if !lv.equal(rdef[i].as_ref())? { return Ok(false); } } @@ -92,7 +92,7 @@ impl Val { return Ok(false); } else { // field value equality. - if !lv.1.equal(field_target.1.as_ref(), pos.clone())? { + if !lv.1.equal(field_target.1.as_ref())? { return Ok(false); } } @@ -100,16 +100,13 @@ impl Val { Ok(true) } } - // FIXME(jwall): Maybe we don't require positions here? (&Val::Func(_), &Val::Func(_)) => Err(error::BuildError::new( "Func are not comparable", error::ErrorType::TypeFail, - pos, )), (&Val::Module(_), &Val::Module(_)) => Err(error::BuildError::new( "Module are not comparable", error::ErrorType::TypeFail, - pos, )), // EMPTY is always comparable for equality. (&Val::Empty, _) => Ok(false), @@ -117,7 +114,6 @@ impl Val { (me, tgt) => Err(error::BuildError::new( format!("Expected {} but got ({})", me.type_name(), tgt), error::ErrorType::TypeFail, - pos, )), } } diff --git a/src/build/mod.rs b/src/build/mod.rs index adf27eb..76d1449 100644 --- a/src/build/mod.rs +++ b/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( + return Err(Box::new(error::BuildError::new_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( + return Err(Box::new(error::BuildError::new_with_pos( format!("Expected {} but got ({})", $msg, val), error::ErrorType::TypeFail, $pos.clone(), @@ -277,15 +277,13 @@ 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( - 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::new_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), } @@ -329,7 +327,7 @@ impl<'a> FileBuilder<'a> { Some(val) => Ok(val), } } - Err(err) => Err(Box::new(error::BuildError::new( + Err(err) => Err(Box::new(error::BuildError::new_with_pos( format!("{}", err,), error::ErrorType::ParseError, (&input).into(), @@ -410,7 +408,7 @@ impl<'a> FileBuilder<'a> { mut_assets_cache.stash(path, result.clone())?; return Ok(result); } else { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!("No such import {} in the std library.", def.path.fragment), error::ErrorType::Unsupported, def.pos.clone(), @@ -420,7 +418,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( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Import Cycle Detected!!!! {} is already in import stack: {:?}", normalized.to_string_lossy(), @@ -452,7 +450,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( + return Err(Box::new(error::BuildError::new_with_pos( format!("Let {} binding collides with reserved word", name.fragment), error::ErrorType::ReservedWordError, name.pos.clone(), @@ -460,7 +458,7 @@ impl<'a> FileBuilder<'a> { } match self.scope.build_output.entry(name.into()) { Entry::Occupied(e) => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Binding \ for {:?} already \ @@ -492,7 +490,7 @@ impl<'a> FileBuilder<'a> { self.out_lock = Some((typ.fragment.to_string(), val.clone())); Ok(val) } else { - Err(Box::new(error::BuildError::new( + Err(Box::new(error::BuildError::new_with_pos( format!("You can only have one output per file."), error::ErrorType::Unsupported, pos.clone(), @@ -521,7 +519,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( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Expected \ String \ @@ -542,7 +540,7 @@ impl<'a> FileBuilder<'a> { return Ok(Rc::new(Val::List(new_vec))); } val => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Expected \ List \ @@ -556,7 +554,7 @@ impl<'a> FileBuilder<'a> { } }, ref expr => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!("{} does not support the '+' operation", expr.type_name()), error::ErrorType::Unsupported, lpos.clone(), @@ -580,7 +578,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( + return Err(Box::new(error::BuildError::new_with_pos( format!("{} does not support the '-' operation", expr.type_name()), error::ErrorType::Unsupported, lpos.clone(), @@ -604,7 +602,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( + return Err(Box::new(error::BuildError::new_with_pos( format!("{} does not support the '*' operation", expr.type_name()), error::ErrorType::Unsupported, lpos.clone(), @@ -628,7 +626,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( + return Err(Box::new(error::BuildError::new_with_pos( format!( "{} does not support the 'modulus' operation", expr.type_name() @@ -655,7 +653,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( + return Err(Box::new(error::BuildError::new_with_pos( format!("{} does not support the '*' operation", expr.type_name()), error::ErrorType::Unsupported, lpos.clone(), @@ -670,9 +668,14 @@ impl<'a> FileBuilder<'a> { left: Rc, right: Rc, ) -> Result, Box> { - Ok(Rc::new(Val::Boolean( - left.equal(right.as_ref(), pos.clone())?, - ))) + match left.equal(right.as_ref()) { + Ok(b) => Ok(Rc::new(Val::Boolean(b))), + Err(e) => Err(Box::new(error::BuildError::new_with_pos( + e.msg, + e.err_type, + pos.clone(), + ))), + } } fn do_not_deep_equal( @@ -681,9 +684,14 @@ impl<'a> FileBuilder<'a> { left: Rc, right: Rc, ) -> Result, Box> { - Ok(Rc::new(Val::Boolean( - !left.equal(right.as_ref(), pos.clone())?, - ))) + match left.equal(right.as_ref()) { + Ok(b) => Ok(Rc::new(Val::Boolean(!b))), + Err(e) => Err(Box::new(error::BuildError::new_with_pos( + e.msg, + e.err_type, + pos.clone(), + ))), + } } fn do_gt( @@ -703,7 +711,7 @@ impl<'a> FileBuilder<'a> { return Ok(Rc::new(Val::Boolean(l > r))); } } - Err(Box::new(error::BuildError::new( + Err(Box::new(error::BuildError::new_with_pos( format!("Expected {} but got ({})", left.type_name(), right,), error::ErrorType::TypeFail, pos.clone(), @@ -727,7 +735,7 @@ impl<'a> FileBuilder<'a> { return Ok(Rc::new(Val::Boolean(l < r))); } } - Err(Box::new(error::BuildError::new( + Err(Box::new(error::BuildError::new_with_pos( format!("Expected {} but got ({})", left.type_name(), right,), error::ErrorType::TypeFail, pos.clone(), @@ -750,7 +758,7 @@ impl<'a> FileBuilder<'a> { return Ok(Rc::new(Val::Boolean(l <= r))); } } - Err(Box::new(error::BuildError::new( + Err(Box::new(error::BuildError::new_with_pos( format!("Expected {} but got ({})", left.type_name(), right), error::ErrorType::TypeFail, pos.clone(), @@ -773,7 +781,7 @@ impl<'a> FileBuilder<'a> { return Ok(Rc::new(Val::Boolean(l >= r))); } } - Err(Box::new(error::BuildError::new( + Err(Box::new(error::BuildError::new_with_pos( format!("Expected {} but got ({})", left.type_name(), right,), error::ErrorType::TypeFail, pos.clone(), @@ -789,7 +797,7 @@ impl<'a> FileBuilder<'a> { Expression::Simple(Value::Symbol(ref s)) => { scope .lookup_sym(s, true) - .ok_or(Box::new(error::BuildError::new( + .ok_or(Box::new(error::BuildError::new_with_pos( format!("Unable to find binding {}", s.val,), error::ErrorType::NoSuchSymbol, pos, @@ -798,7 +806,7 @@ impl<'a> FileBuilder<'a> { Expression::Simple(Value::Str(ref s)) => { scope .lookup_sym(s, false) - .ok_or(Box::new(error::BuildError::new( + .ok_or(Box::new(error::BuildError::new_with_pos( format!("Unable to find binding {}", s.val,), error::ErrorType::NoSuchSymbol, pos, @@ -813,12 +821,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( + .ok_or(Box::new(error::BuildError::new_with_pos( format!("Unable to find binding {}", s,), error::ErrorType::NoSuchSymbol, pos, ))), - _ => Err(Box::new(error::BuildError::new( + _ => Err(Box::new(error::BuildError::new_with_pos( format!("Invalid selector lookup {}", val.type_name(),), error::ErrorType::NoSuchSymbol, pos, @@ -859,7 +867,7 @@ impl<'a> FileBuilder<'a> { return Ok(right); } } - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Expected boolean value for operator but got ({})", left.type_name() @@ -868,7 +876,7 @@ impl<'a> FileBuilder<'a> { right_pos.clone(), ))); } else { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Expected boolean value for operator but got ({})", left.type_name() @@ -891,7 +899,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( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Invalid righthand type for in operator {}", right.type_name() @@ -935,7 +943,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( + return Err(Box::new(error::BuildError::new_with_pos( format!("Expected string for regex but got ({})", right.type_name()), error::ErrorType::TypeFail, right_pos.clone(), @@ -944,7 +952,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( + return Err(Box::new(error::BuildError::new_with_pos( format!("Expected string but got ({})", left.type_name()), error::ErrorType::TypeFail, left_pos.clone(), @@ -993,7 +1001,7 @@ impl<'a> FileBuilder<'a> { &BinaryExprType::Div => self.divide_vals(&def.pos, def.right.pos(), left, right), &BinaryExprType::Mod => self.mod_vals(&def.pos, def.right.pos(), left, right), // Handle Comparison operators here - &BinaryExprType::Equal => self.do_deep_equal(def.right.pos(), left, right), + &BinaryExprType::Equal => self.do_deep_equal(&def.right.pos(), left, right), &BinaryExprType::GT => self.do_gt(&def.right.pos(), left, right), &BinaryExprType::LT => self.do_lt(&def.right.pos(), left, right), &BinaryExprType::GTEqual => self.do_gtequal(&def.right.pos(), left, right), @@ -1045,7 +1053,6 @@ impl<'a> FileBuilder<'a> { key ), error::ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } } @@ -1067,7 +1074,7 @@ impl<'a> FileBuilder<'a> { { v.insert((src_val.0, expr_result)); } else { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Expected type {} for field {} but got ({})", src_val.1.type_name(), @@ -1125,7 +1132,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( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Binding \ for {:?} already \ @@ -1146,7 +1153,7 @@ impl<'a> FileBuilder<'a> { // tuple using them. return Ok(b.get_outputs_as_val()); } else { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Weird value stored in our module parameters slot {:?}", mod_def.arg_tuple @@ -1156,7 +1163,7 @@ impl<'a> FileBuilder<'a> { ))); } } - Err(Box::new(error::BuildError::new( + Err(Box::new(error::BuildError::new_with_pos( format!("Expected Tuple or Module but got ({})", v), error::ErrorType::TypeFail, def.selector.pos().clone(), @@ -1200,14 +1207,14 @@ impl<'a> FileBuilder<'a> { } return match def.eval(self, argvals) { Ok(v) => Ok(v), - Err(e) => Err(Box::new(error::BuildError::new( + Err(e) => Err(Box::new(error::BuildError::new_with_pos( format!("Func evaluation failed\nCaused by:\n\t{}", e), error::ErrorType::TypeFail, call_pos, ))), }; } - Err(Box::new(error::BuildError::new( + Err(Box::new(error::BuildError::new_with_pos( // We should pretty print the selectors here. format!("{} is not a Function", v), error::ErrorType::TypeFail, @@ -1273,7 +1280,7 @@ impl<'a> FileBuilder<'a> { // Otherwise return the default. return self.eval_expr(def_expr, scope); } else { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Expected String but got \ {} in Select expression", @@ -1333,7 +1340,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( + return Err(Box::new(error::BuildError::new_with_pos( format!( "map on tuple expects the first item out list to be a string but got size {}", fs[0].type_name() @@ -1344,7 +1351,7 @@ impl<'a> FileBuilder<'a> { }; out.push((new_name, fs[1].clone())); } else { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "map on a tuple field expects a list of size 2 as output but got size {}", fs.len() @@ -1354,7 +1361,7 @@ impl<'a> FileBuilder<'a> { ))); } } else { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "map on a tuple field expects a list as output but got ({})", result.type_name() @@ -1386,7 +1393,7 @@ impl<'a> FileBuilder<'a> { let funcdef = match maybe_mac.as_ref() { &Val::Func(ref funcdef) => funcdef, _ => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!("Expected func but got {:?}", def.func), error::ErrorType::TypeFail, def.pos.clone(), @@ -1416,7 +1423,7 @@ impl<'a> FileBuilder<'a> { } } other => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Expected List Str, or Tuple as target but got {:?}", other.type_name() @@ -1451,7 +1458,7 @@ impl<'a> FileBuilder<'a> { // noop } _ => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Expected boolean or NULL for filter return but got ({})", out.type_name() @@ -1467,7 +1474,7 @@ impl<'a> FileBuilder<'a> { result.push_str(&s); } _ => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!("Expected string map return but got ({})", out.type_name()), error::ErrorType::TypeFail, def.pos.clone(), @@ -1490,7 +1497,7 @@ impl<'a> FileBuilder<'a> { let macdef = match maybe_mac.as_ref() { &Val::Func(ref macdef) => macdef, _ => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!("Expected func but got {:?}", def.func), error::ErrorType::TypeFail, def.pos.clone(), @@ -1502,7 +1509,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( + other => Err(Box::new(error::BuildError::new_with_pos( format!( "Expected List or Tuple as target but got {:?}", other.type_name() @@ -1612,7 +1619,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( + return Err(Box::new(error::BuildError::new_with_pos( format!("Error finding file {} {}", path, e), error::ErrorType::TypeFail, pos.clone(), @@ -1622,7 +1629,7 @@ impl<'a> FileBuilder<'a> { let mut f = match File::open(&normalized) { Ok(f) => f, Err(e) => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!("Error opening file {} {}", normalized.to_string_lossy(), e), error::ErrorType::TypeFail, pos.clone(), @@ -1653,7 +1660,7 @@ impl<'a> FileBuilder<'a> { }; Ok(val) } - None => Err(Box::new(error::BuildError::new( + None => Err(Box::new(error::BuildError::new_with_pos( format!("Unknown include conversion type {}", def.typ.fragment), error::ErrorType::Unsupported, def.typ.pos.clone(), @@ -1679,7 +1686,7 @@ impl<'a> FileBuilder<'a> { let start = match start.as_ref() { &Val::Int(i) => i, _ => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Expected an integer for range start but got ({})", start.type_name() @@ -1696,7 +1703,7 @@ impl<'a> FileBuilder<'a> { match step.as_ref() { &Val::Int(i) => i, _ => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Expected an integer for range step but got ({})", step.type_name() @@ -1715,7 +1722,7 @@ impl<'a> FileBuilder<'a> { let end = match end.as_ref() { &Val::Int(i) => i, _ => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!( "Expected an integer for range start but got ({})", end.type_name() @@ -1742,7 +1749,7 @@ impl<'a> FileBuilder<'a> { let typ = match tval.as_ref() { Val::Str(ref s) => s.clone(), _ => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!("Expected string expression but got ({})", tval), error::ErrorType::TypeFail, def.right.pos().clone(), @@ -1761,7 +1768,7 @@ impl<'a> FileBuilder<'a> { "func" => val.is_func(), "module" => val.is_module(), other => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_with_pos( format!("Expected valid type name but got ({})", other), error::ErrorType::TypeFail, def.right.pos().clone(), @@ -1797,13 +1804,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( + Err(Box::new(error::BuildError::new_with_pos( s.clone(), error::ErrorType::UserDefined, def.pos.clone(), ))) } else { - Err(Box::new(error::BuildError::new( + Err(Box::new(error::BuildError::new_with_pos( format!( "Expected string for message but got ({})", def.message.as_ref() @@ -1818,7 +1825,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( + Err(Box::new(error::BuildError::new_with_pos( format!( "Expected boolean for expression but got ({})", def.expr.as_ref() diff --git a/src/build/scope.rs b/src/build/scope.rs index eba0f9b..172652d 100644 --- a/src/build/scope.rs +++ b/src/build/scope.rs @@ -115,7 +115,7 @@ impl Scope { return Self::lookup_in_list(pos, idx, fs); } } - Err(Box::new(error::BuildError::new( + Err(Box::new(error::BuildError::new_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( + Err(Box::new(error::BuildError::new_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::()?, _ => { - return Err(Box::new(error::BuildError::new( + return Err(Box::new(error::BuildError::new_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( + Err(Box::new(error::BuildError::new_with_pos( format!("idx {} out of bounds in list", idx), error::ErrorType::NoSuchSymbol, pos.clone(), diff --git a/src/convert/exec.rs b/src/convert/exec.rs index 4c8e79f..e473ad2 100644 --- a/src/convert/exec.rs +++ b/src/convert/exec.rs @@ -17,7 +17,6 @@ use std; use std::io::{Cursor, Write}; use std::rc::Rc; -use crate::ast::Position; use crate::build::Val; use crate::build::Val::Tuple; use crate::convert; @@ -46,21 +45,18 @@ impl ExecConverter { return Err(Box::new(BuildError::new( "Exec tuples must have no more than 3 fields", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } let mut env: Option<&Vec<(String, Rc)>> = None; let mut command: Option<&str> = None; let mut args: Option<&Vec>> = None; for &(ref name, ref val) in fields.iter() { - // FIXME(jwall): BuildError should not require a Position. // We require a command field in our exec tuple. if name == "command" { if command.is_some() { return Err(Box::new(BuildError::new( "There can only be one command field in an exec tuple", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } if let &Val::Str(ref s) = val.as_ref() { @@ -70,7 +66,6 @@ impl ExecConverter { return Err(Box::new(BuildError::new( "The command field of an exec tuple must be a string", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } // We optionally allow an env field in our exec tuple. @@ -80,7 +75,6 @@ impl ExecConverter { return Err(Box::new(BuildError::new( "There can only be one env field in an exec tuple", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } env = Some(l); @@ -89,7 +83,6 @@ impl ExecConverter { return Err(Box::new(BuildError::new( "The env field of an exec tuple must be a list", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } // We optionally allow an args field in our exec tuple. @@ -99,7 +92,6 @@ impl ExecConverter { return Err(Box::new(BuildError::new( "There can only be one args field of an exec tuple", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } args = Some(l); @@ -108,7 +100,6 @@ impl ExecConverter { return Err(Box::new(BuildError::new( "The args field of an exec tuple must be a list", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } } @@ -116,7 +107,6 @@ impl ExecConverter { return Err(Box::new(BuildError::new( "An exec tuple must have a command field", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } // Okay if we have made it this far then we are ready to start creating our script. @@ -137,7 +127,6 @@ impl ExecConverter { return Err(Box::new(BuildError::new( "The env fields of an exec tuple must contain only string values", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } } @@ -158,7 +147,6 @@ impl ExecConverter { return Err(Box::new(BuildError::new( "Exec args must be a list of strings or tuples of strings.", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } } @@ -174,7 +162,6 @@ impl ExecConverter { Err(Box::new(BuildError::new( "Exec outputs must be of type Tuple", ErrorType::TypeFail, - Position::new(0, 0, 0), ))) } } diff --git a/src/convert/xml.rs b/src/convert/xml.rs index 3732c0f..30c1768 100644 --- a/src/convert/xml.rs +++ b/src/convert/xml.rs @@ -18,7 +18,6 @@ use std::io::Write; use std::rc::Rc; use super::traits::{ConvertResult, Converter}; -use crate::ast::Position; use crate::build::Val; use crate::error::BuildError; use crate::error::ErrorType; @@ -38,7 +37,6 @@ impl XmlConverter { Err(Box::new(BuildError::new( "Not a String value", ErrorType::TypeFail, - Position::new(0, 0, 0), ))) } } @@ -50,7 +48,6 @@ impl XmlConverter { Err(Box::new(BuildError::new( "Not a tuple value", ErrorType::TypeFail, - Position::new(0, 0, 0), ))) } } @@ -62,7 +59,6 @@ impl XmlConverter { Err(Box::new(BuildError::new( "Not a List value", ErrorType::TypeFail, - Position::new(0, 0, 0), ))) } } @@ -123,7 +119,6 @@ impl XmlConverter { return Err(Box::new(BuildError::new( "XML nodes can not have both text and name fields", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } if name.is_some() { @@ -160,7 +155,6 @@ impl XmlConverter { return Err(Box::new(BuildError::new( "XML nodes must be a Tuple or a string", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } Ok(()) @@ -209,7 +203,6 @@ impl XmlConverter { return Err(Box::new(BuildError::new( "XML version must be either 1.0 or 1.1", ErrorType::TypeFail, - Position::new(0, 0, 0), ))); } } @@ -226,14 +219,12 @@ impl XmlConverter { None => Err(Box::new(BuildError::new( "XML doc tuples must have a root field", ErrorType::TypeFail, - Position::new(0, 0, 0), ))), } } else { Err(Box::new(BuildError::new( "XML outputs must be a Tuple", ErrorType::TypeFail, - Position::new(0, 0, 0), ))) } } diff --git a/src/error.rs b/src/error.rs index b4d84e6..81002e5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -59,31 +59,44 @@ impl fmt::Display for ErrorType { /// Error defines an Error type for parsing and building UCG code. pub struct BuildError { pub err_type: ErrorType, - pub pos: Position, + pub pos: Option, pub msg: String, _pkgonly: (), } impl BuildError { - pub fn new>(msg: S, t: ErrorType, pos: Position) -> Self { + pub fn new_with_pos>(msg: S, t: ErrorType, pos: Position) -> Self { BuildError { err_type: t, - pos: pos, + pos: Some(pos), + msg: msg.into(), + _pkgonly: (), + } + } + + pub fn new>(msg: S, t: ErrorType) -> Self { + BuildError { + err_type: t, + pos: None, msg: msg.into(), _pkgonly: (), } } fn render(&self, w: &mut fmt::Formatter) -> fmt::Result { - let file = match self.pos.file { - Some(ref pb) => pb.to_string_lossy().to_string(), - None => "".to_string(), - }; - write!( - w, - "{} at {} line: {}, column: {}\nCaused By:\n\t{} ", - self.err_type, file, self.pos.line, self.pos.column, self.msg - )?; + if let Some(ref pos) = self.pos { + let file = match pos.file { + Some(ref pb) => pb.to_string_lossy().to_string(), + None => "".to_string(), + }; + write!( + w, + "{} at {} line: {}, column: {}\nCaused By:\n\t{} ", + self.err_type, file, pos.line, pos.column, self.msg + )?; + } else { + write!(w, "{} \nCaused By:\n\t{} ", self.err_type, self.msg)?; + } Ok(()) } } diff --git a/src/tokenizer/mod.rs b/src/tokenizer/mod.rs index 4f3879d..aa81fd6 100644 --- a/src/tokenizer/mod.rs +++ b/src/tokenizer/mod.rs @@ -664,7 +664,12 @@ pub fn pos<'a>(i: SliceIter<'a, Token>) -> Result, Position let tok = _i.next().unwrap(); let line = tok.pos.line; let column = tok.pos.column; - Result::Complete(i.clone(), Position::new(line, column, i.get_offset())) + let pos = Position::new(line, column, i.get_offset()); + let pos = match tok.pos.file { + Some(ref f) => pos.with_file(f), + None => pos, + }; + Result::Complete(i.clone(), pos) } #[cfg(test)]