mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FIX: Better error messages for func calls.
Also better more consistency for some type fails in other expressions.
This commit is contained in:
parent
a1bc81ee89
commit
214045f1a6
@ -270,7 +270,7 @@ fn test_binary_sum_operator_wrong_type_on_rhs_compile_failure() {
|
||||
assert_build_failure(
|
||||
"1 + \"foo\";",
|
||||
vec![
|
||||
Regex::new(r"Expected Integer but got .foo.").unwrap(),
|
||||
Regex::new(r"Expected Integer but got \(.foo.\)").unwrap(),
|
||||
Regex::new(r"at <eval> line: 1, column: 5").unwrap(),
|
||||
],
|
||||
)
|
||||
@ -281,7 +281,7 @@ fn test_binary_minus_operator_wrong_type_on_rhs_compile_failure() {
|
||||
assert_build_failure(
|
||||
"1 - \"foo\";",
|
||||
vec![
|
||||
Regex::new(r"Expected Integer but got .foo.").unwrap(),
|
||||
Regex::new(r"Expected Integer but got \(.foo.\)").unwrap(),
|
||||
Regex::new(r"at <eval> line: 1, column: 5").unwrap(),
|
||||
],
|
||||
)
|
||||
@ -292,7 +292,7 @@ fn test_binary_mul_operator_wrong_type_on_rhs_compile_failure() {
|
||||
assert_build_failure(
|
||||
"1 * \"foo\";",
|
||||
vec![
|
||||
Regex::new(r"Expected Integer but got .foo.").unwrap(),
|
||||
Regex::new(r"Expected Integer but got \(.foo.\)").unwrap(),
|
||||
Regex::new(r"at <eval> line: 1, column: 5").unwrap(),
|
||||
],
|
||||
)
|
||||
@ -303,7 +303,7 @@ fn test_binary_div_operator_wrong_type_on_rhs_compile_failure() {
|
||||
assert_build_failure(
|
||||
"1 / \"foo\";",
|
||||
vec![
|
||||
Regex::new(r"Expected Integer but got .foo.").unwrap(),
|
||||
Regex::new(r"Expected Integer but got \(.foo.\)").unwrap(),
|
||||
Regex::new(r"at <eval> line: 1, column: 5").unwrap(),
|
||||
],
|
||||
)
|
||||
@ -314,7 +314,7 @@ fn test_binary_gt_operator_wrong_type_on_rhs_compile_failure() {
|
||||
assert_build_failure(
|
||||
"1 > \"foo\";",
|
||||
vec![
|
||||
Regex::new(r"Expected Integer but got .foo.").unwrap(),
|
||||
Regex::new(r"Expected Integer but got \(.foo.\)").unwrap(),
|
||||
Regex::new(r"at <eval> line: 1, column: 5").unwrap(),
|
||||
],
|
||||
)
|
||||
@ -325,7 +325,7 @@ fn test_binary_lt_operator_wrong_type_on_rhs_compile_failure() {
|
||||
assert_build_failure(
|
||||
"1 < \"foo\";",
|
||||
vec![
|
||||
Regex::new(r"Expected Integer but got .foo.").unwrap(),
|
||||
Regex::new(r"Expected Integer but got \(.foo.\)").unwrap(),
|
||||
Regex::new(r"at <eval> line: 1, column: 5").unwrap(),
|
||||
],
|
||||
)
|
||||
@ -336,7 +336,7 @@ fn test_binary_lteq_operator_wrong_type_on_rhs_compile_failure() {
|
||||
assert_build_failure(
|
||||
"1 <= \"foo\";",
|
||||
vec![
|
||||
Regex::new(r"Expected Integer but got .foo.").unwrap(),
|
||||
Regex::new(r"Expected Integer but got \(.foo.\)").unwrap(),
|
||||
Regex::new(r"at <eval> line: 1, column: 6").unwrap(),
|
||||
],
|
||||
)
|
||||
@ -347,7 +347,7 @@ fn test_binary_gteq_operator_wrong_type_on_rhs_compile_failure() {
|
||||
assert_build_failure(
|
||||
"1 >= \"foo\";",
|
||||
vec![
|
||||
Regex::new(r"Expected Integer but got .foo.").unwrap(),
|
||||
Regex::new(r"Expected Integer but got \(.foo.\)").unwrap(),
|
||||
Regex::new(r"at <eval> line: 1, column: 6").unwrap(),
|
||||
],
|
||||
)
|
||||
@ -358,7 +358,7 @@ fn test_binary_eqeq_operator_wrong_type_on_rhs_compile_failure() {
|
||||
assert_build_failure(
|
||||
"1 == \"foo\";",
|
||||
vec![
|
||||
Regex::new(r"Expected Integer but got .foo.").unwrap(),
|
||||
Regex::new(r"Expected Integer but got \(.foo.\)").unwrap(),
|
||||
Regex::new(r"at <eval> line: 1, column: 6").unwrap(),
|
||||
],
|
||||
)
|
||||
@ -529,3 +529,29 @@ fn test_copy_expression_wrong_field_type_compile_failure() {
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
// TODO(jwall): Function call errors
|
||||
|
||||
#[test]
|
||||
fn test_func_call_wrong_argument_length_compile_failure() {
|
||||
assert_build_failure(
|
||||
"let foo = func() => 1;\nfoo(1);",
|
||||
vec![
|
||||
Regex::new(r"Func called with too many args").unwrap(),
|
||||
Regex::new(r"at <eval> line: 2, column: 1").unwrap(),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_func_call_wrong_argument_type_compile_failure() {
|
||||
assert_build_failure(
|
||||
"let foo = func(i) => 1 + i;\nfoo(\"bar\");",
|
||||
vec![
|
||||
Regex::new(r"Func evaluation failed").unwrap(),
|
||||
Regex::new(r"at <eval> line: 1, column: 26").unwrap(),
|
||||
Regex::new(r"Expected Integer but got \(.bar.\)").unwrap(),
|
||||
Regex::new(r"at <eval> line: 2, column: 1").unwrap(),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ impl Val {
|
||||
(&Val::Empty, _) => Ok(false),
|
||||
(_, &Val::Empty) => Ok(false),
|
||||
(me, tgt) => Err(error::BuildError::new(
|
||||
format!("Expected {} but got {}", me.type_name(), tgt),
|
||||
format!("Expected {} but got ({})", me.type_name(), tgt),
|
||||
error::ErrorType::TypeFail,
|
||||
pos,
|
||||
)),
|
||||
|
@ -55,8 +55,6 @@ impl FuncDef {
|
||||
/// Expands a ucg function using the given arguments into a new Tuple.
|
||||
pub fn eval(
|
||||
&self,
|
||||
// TODO(jwall): This should come from the FuncDef instead.
|
||||
root: PathBuf,
|
||||
parent_builder: &FileBuilder,
|
||||
mut args: Vec<Rc<Val>>,
|
||||
) -> Result<Rc<Val>, Box<dyn Error>> {
|
||||
@ -64,10 +62,7 @@ impl FuncDef {
|
||||
// func call error.
|
||||
if args.len() > self.argdefs.len() {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!(
|
||||
"Func called with too many args in file: {}",
|
||||
root.to_string_lossy()
|
||||
),
|
||||
"Func called with too many args",
|
||||
error::ErrorType::BadArgLen,
|
||||
self.pos.clone(),
|
||||
)));
|
||||
@ -135,7 +130,7 @@ macro_rules! eval_binary_expr {
|
||||
}
|
||||
val => {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!("Expected {} but got {}", $msg, val),
|
||||
format!("Expected {} but got ({})", $msg, val),
|
||||
error::ErrorType::TypeFail,
|
||||
$pos.clone(),
|
||||
)));
|
||||
@ -682,7 +677,7 @@ impl<'a> FileBuilder<'a> {
|
||||
}
|
||||
}
|
||||
Err(Box::new(error::BuildError::new(
|
||||
format!("Expected {} but got {}", left.type_name(), right,),
|
||||
format!("Expected {} but got ({})", left.type_name(), right,),
|
||||
error::ErrorType::TypeFail,
|
||||
pos.clone(),
|
||||
)))
|
||||
@ -706,7 +701,7 @@ impl<'a> FileBuilder<'a> {
|
||||
}
|
||||
}
|
||||
Err(Box::new(error::BuildError::new(
|
||||
format!("Expected {} but got {}", left.type_name(), right,),
|
||||
format!("Expected {} but got ({})", left.type_name(), right,),
|
||||
error::ErrorType::TypeFail,
|
||||
pos.clone(),
|
||||
)))
|
||||
@ -729,7 +724,7 @@ impl<'a> FileBuilder<'a> {
|
||||
}
|
||||
}
|
||||
Err(Box::new(error::BuildError::new(
|
||||
format!("Expected {} but got {}", left.type_name(), right),
|
||||
format!("Expected {} but got ({})", left.type_name(), right),
|
||||
error::ErrorType::TypeFail,
|
||||
pos.clone(),
|
||||
)))
|
||||
@ -752,7 +747,7 @@ impl<'a> FileBuilder<'a> {
|
||||
}
|
||||
}
|
||||
Err(Box::new(error::BuildError::new(
|
||||
format!("Expected {} but got {}", left.type_name(), right,),
|
||||
format!("Expected {} but got ({})", left.type_name(), right,),
|
||||
error::ErrorType::TypeFail,
|
||||
pos.clone(),
|
||||
)))
|
||||
@ -839,7 +834,7 @@ impl<'a> FileBuilder<'a> {
|
||||
}
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!(
|
||||
"Expected boolean value for operator but got {}",
|
||||
"Expected boolean value for operator but got ({})",
|
||||
left.type_name()
|
||||
),
|
||||
error::ErrorType::TypeFail,
|
||||
@ -848,7 +843,7 @@ impl<'a> FileBuilder<'a> {
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!(
|
||||
"Expected boolean value for operator but got {}",
|
||||
"Expected boolean value for operator but got ({})",
|
||||
left.type_name()
|
||||
),
|
||||
error::ErrorType::TypeFail,
|
||||
@ -914,7 +909,7 @@ impl<'a> FileBuilder<'a> {
|
||||
regex::Regex::new(s.as_ref())?
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!("Expected string for regex but got {}", right.type_name()),
|
||||
format!("Expected string for regex but got ({})", right.type_name()),
|
||||
error::ErrorType::TypeFail,
|
||||
right_pos.clone(),
|
||||
)));
|
||||
@ -923,7 +918,7 @@ impl<'a> FileBuilder<'a> {
|
||||
s.as_ref()
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!("Expected string but got {}", left.type_name()),
|
||||
format!("Expected string but got ({})", left.type_name()),
|
||||
error::ErrorType::TypeFail,
|
||||
left_pos.clone(),
|
||||
)));
|
||||
@ -1164,13 +1159,21 @@ impl<'a> FileBuilder<'a> {
|
||||
fn eval_call(&self, def: &CallDef, scope: &Scope) -> Result<Rc<Val>, Box<dyn Error>> {
|
||||
let args = &def.arglist;
|
||||
let v = self.eval_value(&def.funcref, scope)?;
|
||||
let call_pos = def.pos.clone();
|
||||
if let &Val::Func(ref def) = v.deref() {
|
||||
// Congratulations this is actually a function.
|
||||
let mut argvals: Vec<Rc<Val>> = Vec::new();
|
||||
for arg in args.iter() {
|
||||
argvals.push(self.eval_expr(arg, scope)?);
|
||||
}
|
||||
return Ok(def.eval(self.working_dir.clone(), self, argvals)?);
|
||||
return match def.eval(self, argvals) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(Box::new(error::BuildError::new(
|
||||
format!("Func evaluation failed\nCaused by:\n\t{}", e),
|
||||
error::ErrorType::TypeFail,
|
||||
call_pos,
|
||||
))),
|
||||
};
|
||||
}
|
||||
Err(Box::new(error::BuildError::new(
|
||||
// We should pretty print the selectors here.
|
||||
@ -1259,7 +1262,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let mut out = Vec::new();
|
||||
for item in elems.iter() {
|
||||
let argvals = vec![item.clone()];
|
||||
let val = def.eval(self.working_dir.clone(), self, argvals)?;
|
||||
let val = def.eval(self, argvals)?;
|
||||
match typ {
|
||||
ProcessingOpType::Map => {
|
||||
out.push(val.clone());
|
||||
@ -1288,7 +1291,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let mut out = Vec::new();
|
||||
for &(ref name, ref val) in fs {
|
||||
let argvals = vec![Rc::new(Val::Str(name.val.clone())), val.clone()];
|
||||
let result = def.eval(self.working_dir.clone(), self, argvals)?;
|
||||
let result = def.eval(self, argvals)?;
|
||||
match typ {
|
||||
ProcessingOpType::Map => {
|
||||
if let &Val::List(ref fs) = result.as_ref() {
|
||||
@ -1324,7 +1327,7 @@ impl<'a> FileBuilder<'a> {
|
||||
} else {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!(
|
||||
"map on a tuple field expects a list as output but got {:?}",
|
||||
"map on a tuple field expects a list as output but got ({})",
|
||||
result.type_name()
|
||||
),
|
||||
error::ErrorType::TypeFail,
|
||||
@ -1365,7 +1368,7 @@ impl<'a> FileBuilder<'a> {
|
||||
&Val::List(ref elems) => {
|
||||
for item in elems.iter() {
|
||||
let argvals = vec![acc.clone(), item.clone()];
|
||||
let result = funcdef.eval(self.working_dir.clone(), self, argvals)?;
|
||||
let result = funcdef.eval(self, argvals)?;
|
||||
acc = result;
|
||||
}
|
||||
}
|
||||
@ -1376,14 +1379,14 @@ impl<'a> FileBuilder<'a> {
|
||||
Rc::new(Val::Str(name.val.clone())),
|
||||
val.clone(),
|
||||
];
|
||||
let result = funcdef.eval(self.working_dir.clone(), self, argvals)?;
|
||||
let result = funcdef.eval(self, argvals)?;
|
||||
acc = result;
|
||||
}
|
||||
}
|
||||
&Val::Str(ref s) => {
|
||||
for gc in s.graphemes(true) {
|
||||
let argvals = vec![acc.clone(), Rc::new(Val::Str(gc.to_string()))];
|
||||
let result = funcdef.eval(self.working_dir.clone(), self, argvals)?;
|
||||
let result = funcdef.eval(self, argvals)?;
|
||||
acc = result;
|
||||
}
|
||||
}
|
||||
@ -1410,7 +1413,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let mut result = String::new();
|
||||
for gc in s.graphemes(true) {
|
||||
let arg = Rc::new(Val::Str(gc.to_string()));
|
||||
let out = def.eval(self.working_dir.clone(), self, vec![arg])?;
|
||||
let out = def.eval(self, vec![arg])?;
|
||||
match typ {
|
||||
ProcessingOpType::Filter => {
|
||||
match out.as_ref() {
|
||||
@ -1425,7 +1428,7 @@ impl<'a> FileBuilder<'a> {
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!(
|
||||
"Expected boolean or NULL for filter return but got {}",
|
||||
"Expected boolean or NULL for filter return but got ({})",
|
||||
out.type_name()
|
||||
),
|
||||
error::ErrorType::TypeFail,
|
||||
@ -1440,7 +1443,7 @@ impl<'a> FileBuilder<'a> {
|
||||
}
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!("Expected string map return but got {}", out.type_name()),
|
||||
format!("Expected string map return but got ({})", out.type_name()),
|
||||
error::ErrorType::TypeFail,
|
||||
def.pos.clone(),
|
||||
)));
|
||||
@ -1648,7 +1651,7 @@ impl<'a> FileBuilder<'a> {
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!(
|
||||
"Expected an integer for range start but got {}",
|
||||
"Expected an integer for range start but got ({})",
|
||||
start.type_name()
|
||||
),
|
||||
error::ErrorType::TypeFail,
|
||||
@ -1665,7 +1668,7 @@ impl<'a> FileBuilder<'a> {
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!(
|
||||
"Expected an integer for range step but got {}",
|
||||
"Expected an integer for range step but got ({})",
|
||||
step.type_name()
|
||||
),
|
||||
error::ErrorType::TypeFail,
|
||||
@ -1684,7 +1687,7 @@ impl<'a> FileBuilder<'a> {
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!(
|
||||
"Expected an integer for range start but got {}",
|
||||
"Expected an integer for range start but got ({})",
|
||||
end.type_name()
|
||||
),
|
||||
error::ErrorType::TypeFail,
|
||||
@ -1710,7 +1713,7 @@ impl<'a> FileBuilder<'a> {
|
||||
Val::Str(ref s) => s.clone(),
|
||||
_ => {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!("Expected string expression but got {}", tval),
|
||||
format!("Expected string expression but got ({})", tval),
|
||||
error::ErrorType::TypeFail,
|
||||
def.right.pos().clone(),
|
||||
)));
|
||||
@ -1729,7 +1732,7 @@ impl<'a> FileBuilder<'a> {
|
||||
"module" => val.is_module(),
|
||||
other => {
|
||||
return Err(Box::new(error::BuildError::new(
|
||||
format!("Expected valid type name but got {}", other),
|
||||
format!("Expected valid type name but got ({})", other),
|
||||
error::ErrorType::TypeFail,
|
||||
def.right.pos().clone(),
|
||||
)));
|
||||
@ -1772,7 +1775,7 @@ impl<'a> FileBuilder<'a> {
|
||||
} else {
|
||||
Err(Box::new(error::BuildError::new(
|
||||
format!(
|
||||
"Expected string for message but got {}",
|
||||
"Expected string for message but got ({})",
|
||||
def.message.as_ref()
|
||||
),
|
||||
error::ErrorType::TypeFail,
|
||||
@ -1787,7 +1790,7 @@ impl<'a> FileBuilder<'a> {
|
||||
} else {
|
||||
Err(Box::new(error::BuildError::new(
|
||||
format!(
|
||||
"Expected boolean for expression but got {}",
|
||||
"Expected boolean for expression but got ({})",
|
||||
def.expr.as_ref()
|
||||
),
|
||||
error::ErrorType::TypeFail,
|
||||
|
@ -170,70 +170,6 @@ fn test_expr_copy_no_such_tuple() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Expected Tuple or Module got 1")]
|
||||
fn test_expr_copy_not_a_tuple() {
|
||||
let i_paths = Vec::new();
|
||||
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
||||
let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, cache);
|
||||
b.scope
|
||||
.build_output
|
||||
.entry(value_node!("tpl1".to_string(), Position::new(1, 0, 0)))
|
||||
.or_insert(Rc::new(Val::Int(1)));
|
||||
test_expr_to_val(
|
||||
vec![(
|
||||
Expression::Copy(CopyDef {
|
||||
selector: Value::Symbol(PositionedItem::new(
|
||||
"tpl1".to_string(),
|
||||
Position::new(1, 1, 1),
|
||||
)),
|
||||
fields: Vec::new(),
|
||||
pos: Position::new(1, 0, 0),
|
||||
}),
|
||||
Val::Tuple(Vec::new()),
|
||||
)],
|
||||
b,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Expected type Integer for field fld1 but got String")]
|
||||
fn test_expr_copy_field_type_error() {
|
||||
let i_paths = Vec::new();
|
||||
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
||||
let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, cache);
|
||||
b.scope
|
||||
.build_output
|
||||
.entry(value_node!("tpl1".to_string(), Position::new(1, 0, 0)))
|
||||
.or_insert(Rc::new(Val::Tuple(vec![(
|
||||
value_node!("fld1".to_string(), Position::new(1, 0, 0)),
|
||||
Rc::new(Val::Int(1)),
|
||||
)])));
|
||||
test_expr_to_val(
|
||||
vec![(
|
||||
Expression::Copy(CopyDef {
|
||||
selector: Value::Symbol(PositionedItem::new(
|
||||
"tpl1".to_string(),
|
||||
Position::new(1, 1, 1),
|
||||
)),
|
||||
fields: vec![(
|
||||
make_tok!("fld1", Position::new(1, 1, 1)),
|
||||
Expression::Simple(Value::Str(value_node!(
|
||||
"2".to_string(),
|
||||
Position::new(1, 1, 1)
|
||||
))),
|
||||
)],
|
||||
pos: Position::new(1, 0, 0),
|
||||
}),
|
||||
Val::Tuple(vec![(
|
||||
value_node!("fld1".to_string(), Position::new(1, 1, 1)),
|
||||
Rc::new(Val::Str("2".to_string())),
|
||||
)]),
|
||||
)],
|
||||
b,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Expected String but got Integer in Select expression")]
|
||||
fn test_select_expr_not_a_string() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user