FEATURE: Parsing and evaluation with optional defaults in select.

This commit is contained in:
Jeremy Wall 2019-03-01 17:10:03 -06:00
parent e095cb3235
commit 40107cefb6
4 changed files with 63 additions and 7 deletions

View File

@ -53,3 +53,18 @@ assert {
ok = iflike == "I was true",
desc = "iflike == \"I was true\"",
};
let no_default_test = func(b) => select b, {
true = "I was true",
false = "I was false",
};
assert {
ok = no_default_test(true) == "I was true",
desc = "no default successfully detects true",
};
assert {
ok = no_default_test(false) == "I was false",
desc = "no default successfully detects false",
};

View File

@ -547,3 +547,25 @@ fn test_func_call_wrong_argument_type_compile_failure() {
],
)
}
#[test]
fn test_select_missed_case_string_no_default_compile_failure() {
assert_build_failure(
"select \"a\", { b = 1, };",
vec![
Regex::new(r"Unhandled select case .a. with no default").unwrap(),
Regex::new(r"at <eval> line: 1, column: 8").unwrap(),
],
)
}
#[test]
fn test_select_missed_case_boolean_no_default_compile_failure() {
assert_build_failure(
"select true, { false = 1, };",
vec![
Regex::new(r"Unhandled select case true with no default").unwrap(),
Regex::new(r"at <eval> line: 1, column: 8").unwrap(),
],
)
}

View File

@ -1291,7 +1291,6 @@ impl<'a> FileBuilder<'a> {
fn eval_select(&self, def: &SelectDef, scope: &Scope) -> Result<Rc<Val>, Box<dyn Error>> {
let target = &def.val;
// FIXME(jwall): Handle the no default case in here.
let def_expr = def.default.as_ref().unwrap();
let fields = &def.tuple;
// First resolve the target expression.
let v = self.eval_expr(target, scope)?;
@ -1305,7 +1304,17 @@ impl<'a> FileBuilder<'a> {
}
}
// Otherwise return the default.
return self.eval_expr(def_expr, scope);
match def.default.as_ref() {
Some(e) => self.eval_expr(e, scope),
None => {
return Err(error::BuildError::with_pos(
format!("Unhandled select case \"{}\" with no default", name),
error::ErrorType::TypeFail,
def.val.pos().clone(),
)
.to_boxed());
}
}
} else if let &Val::Boolean(b) = v.deref() {
for &(ref fname, ref val_expr) in fields.iter() {
if &fname.fragment == "true" && b {
@ -1316,7 +1325,17 @@ impl<'a> FileBuilder<'a> {
}
}
// Otherwise return the default.
return self.eval_expr(def_expr, scope);
match def.default.as_ref() {
Some(e) => self.eval_expr(e, scope),
None => {
return Err(error::BuildError::with_pos(
format!("Unhandled select case {} with no default", b),
error::ErrorType::TypeFail,
def.val.pos().clone(),
)
.to_boxed());
}
}
} else {
return Err(error::BuildError::with_pos(
format!(

View File

@ -466,11 +466,11 @@ fn select_expression(input: SliceIter<Token>) -> Result<SliceIter<Token>, Expres
_ => must!(punct!(",")),
(expr)
),
default => do_each!(
default => optional!(do_each!(
expr => trace_parse!(must!(expression)),
_ => must!(punct!(",")),
_ => punct!(","),
(expr)
),
)),
map => trace_parse!(must!(tuple)),
(val, default, map)
);
@ -479,7 +479,7 @@ fn select_expression(input: SliceIter<Token>) -> Result<SliceIter<Token>, Expres
Result::Fail(e) => Result::Fail(e),
Result::Incomplete(offset) => Result::Incomplete(offset),
Result::Complete(rest, (val, default, map)) => {
match tuple_to_select(input.clone(), val, Some(default), map) {
match tuple_to_select(input.clone(), val, default, map) {
Ok(expr) => Result::Complete(rest, expr),
Err(e) => Result::Fail(Error::caused_by(
"Invalid Select Expression",