From e7977aeccd2e66c4bf308397e81b66e5f5ed810e 2021-06-03 16:06:17 From: mh Date: 2021-06-03 16:06:17 Subject: [PATCH] make assert() and put() statements, test all statementlike expressions --- diff --git a/src/protocol/parser/pass_validation_linking.rs b/src/protocol/parser/pass_validation_linking.rs index 57c1e2b94ccad88bb44718d92541dd09f09d89ae..f840a194e8f548126fb870eb33d535a4b1ab22e0 100644 --- a/src/protocol/parser/pass_validation_linking.rs +++ b/src/protocol/parser/pass_validation_linking.rs @@ -984,6 +984,7 @@ impl Visitor for PassValidationLinking { // Check whether the method is allowed to be called within the code's // context (in sync, definition type, etc.) let mut expected_wrapping_new_stmt = false; + let mut is_like_a_statement = false; match &mut call_expr.method { Method::Get => { if !self.def_type.is_primitive() { @@ -1012,6 +1013,7 @@ impl Visitor for PassValidationLinking { "a call to 'put' may only occur inside synchronous blocks" )); } + is_like_a_statement = true; }, Method::Fires => { if !self.def_type.is_primitive() { @@ -1042,6 +1044,7 @@ impl Visitor for PassValidationLinking { "assert statements may only occur inside synchronous blocks" )); } + is_like_a_statement = true; }, Method::UserFunction => {}, Method::UserComponent => { @@ -1065,6 +1068,17 @@ impl Visitor for PassValidationLinking { } } + if is_like_a_statement { + // More lying: these function calls are not expressions at all, no sirree. + match self.expr_parent { + ExpressionParent::ExpressionStmt(_) => {}, + _ => return Err(ParseError::new_error_str_at_span( + &ctx.module.source, call_expr.full_span, + "this function call acts like a statement, and may not be used inside expressions" + )), + } + } + // Check the number of arguments let call_definition = ctx.types.get_base_definition(&call_expr.definition).unwrap(); let num_expected_args = match &call_definition.definition { diff --git a/src/protocol/tests/parser_validation.rs b/src/protocol/tests/parser_validation.rs index 14c1bb9856a7ad5c1a8fa2b9bc1ab77803786980..2c2c6b5a75a20425fbc96b40011e9b257d61007f 100644 --- a/src/protocol/tests/parser_validation.rs +++ b/src/protocol/tests/parser_validation.rs @@ -350,4 +350,56 @@ fn test_incorrect_union_instance() { .assert_msg_has(1, "has been resolved to 's32'") .assert_msg_has(1, "has been resolved to 'bool'"); }); +} + +#[test] +fn test_statementlike_expressions() { + Tester::new_single_source_expect_err("assignment", " + func test() -> u32 { + u32 val = 0; + if ((val += 2) == 2) { + return 0; + } + + return 1; + } + ").error(|e| { e + .assert_occurs_at(0, "val += 2") + .assert_msg_has(0, "assignments are statements"); + }); + + Tester::new_single_source_expect_err("assert", " + primitive combobulator(in i, out o) { + while (true) synchronous { + if (fires(i) && fires(o)) { + auto val = get(i); + put(o, val); + + // Array of assert output types + auto waza = { + assert(length(val) > 5), + assert(val[0] == 0), + assert(val[1] == 0) + }; + } else { + assert(false); + } + } + } + ").error(|e| { e + .assert_occurs_at(0, "assert(length(val) > 5)") + .assert_msg_has(0, "function call acts like a statement"); + }); + + Tester::new_single_source_expect_err("put", " + primitive ragnarokifier(out o) { + // Same as above, less convoluted + synchronous { + auto result = { put(o, 0), put(o, 1), put(o, 2) }; + } + } + ").error(|e| { e + .assert_occurs_at(0, "put(o, 0)") + .assert_msg_has(0, "function call acts like a statement"); + }); } \ No newline at end of file