diff --git a/integration_tests/select_expressions_test.ucg b/integration_tests/select_expressions_test.ucg index dae560c..4b70286 100644 --- a/integration_tests/select_expressions_test.ucg +++ b/integration_tests/select_expressions_test.ucg @@ -52,4 +52,19 @@ let iflike = select true, "default", { 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", }; \ No newline at end of file diff --git a/src/build/compile_test.rs b/src/build/compile_test.rs index 35ddd35..3b28519 100644 --- a/src/build/compile_test.rs +++ b/src/build/compile_test.rs @@ -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 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 line: 1, column: 8").unwrap(), + ], + ) +} diff --git a/src/build/mod.rs b/src/build/mod.rs index 9b50bb4..4b69aff 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -1291,7 +1291,6 @@ impl<'a> FileBuilder<'a> { fn eval_select(&self, def: &SelectDef, scope: &Scope) -> Result, Box> { 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!( diff --git a/src/parse/mod.rs b/src/parse/mod.rs index c77f3d1..eb83232 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -466,11 +466,11 @@ fn select_expression(input: SliceIter) -> Result, 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) -> Result, 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",