+ if (!parser_next(parser)) {
+ parseerror(parser, "expected semicolon or loop label");
+ return false;
+ }
+
+ if (parser->tok == TOKEN_IDENT) {
+ if (!OPTS_FLAG(LOOP_LABELS))
+ parseerror(parser, "labeled loops not activated, try using -floop-labels");
+ i = vec_size(loops);
+ while (i--) {
+ if (loops[i] && !strcmp(loops[i], parser_tokval(parser)))
+ break;
+ if (!i) {
+ parseerror(parser, "no such loop to %s: `%s`",
+ (is_continue ? "continue" : "break out of"),
+ parser_tokval(parser));
+ return false;
+ }
+ ++levels;
+ }
+ if (!parser_next(parser)) {
+ parseerror(parser, "expected semicolon");
+ return false;
+ }
+ }
+
+ if (parser->tok != ';') {
+ parseerror(parser, "expected semicolon");
+ return false;
+ }
+
+ if (!parser_next(parser))
+ parseerror(parser, "parse error");
+
+ *out = (ast_expression*)ast_breakcont_new(ctx, is_continue, levels);
+ return true;
+}
+
+/* returns true when it was a variable qualifier, false otherwise!
+ * on error, cvq is set to CV_WRONG
+ */
+static bool parse_var_qualifiers(parser_t *parser, bool with_local, int *cvq, bool *noref, bool *noreturn, bool *is_static)
+{
+ bool had_const = false;
+ bool had_var = false;
+ bool had_noref = false;
+ bool had_noreturn = false;
+ bool had_attrib = false;
+ bool had_static = false;
+
+ *cvq = CV_NONE;
+ for (;;) {
+ if (parser->tok == TOKEN_ATTRIBUTE_OPEN) {
+ had_attrib = true;
+ /* parse an attribute */
+ if (!parser_next(parser)) {
+ parseerror(parser, "expected attribute after `[[`");
+ *cvq = CV_WRONG;
+ return false;
+ }
+ if (!strcmp(parser_tokval(parser), "noreturn")) {
+ had_noreturn = true;
+ if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
+ parseerror(parser, "`noreturn` attribute has no parameters, expected `]]`");
+ *cvq = CV_WRONG;
+ return false;
+ }
+ }
+ else if (!strcmp(parser_tokval(parser), "noref")) {
+ had_noref = true;
+ if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
+ parseerror(parser, "`noref` attribute has no parameters, expected `]]`");
+ *cvq = CV_WRONG;
+ return false;
+ }
+ }
+ else
+ {
+ /* Skip tokens until we hit a ]] */
+ (void)!parsewarning(parser, WARN_UNKNOWN_ATTRIBUTE, "unknown attribute starting with `%s`", parser_tokval(parser));
+ while (parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
+ if (!parser_next(parser)) {
+ parseerror(parser, "error inside attribute");
+ *cvq = CV_WRONG;
+ return false;
+ }
+ }
+ }
+ }
+ else if (!strcmp(parser_tokval(parser), "static"))
+ had_static = true;
+ else if (!strcmp(parser_tokval(parser), "const"))
+ had_const = true;
+ else if (!strcmp(parser_tokval(parser), "var"))
+ had_var = true;
+ else if (with_local && !strcmp(parser_tokval(parser), "local"))
+ had_var = true;
+ else if (!strcmp(parser_tokval(parser), "noref"))
+ had_noref = true;
+ else if (!had_const && !had_var && !had_noref && !had_noreturn && !had_attrib && !had_static) {
+ return false;
+ }
+ else
+ break;
+ if (!parser_next(parser))
+ goto onerr;
+ }
+ if (had_const)
+ *cvq = CV_CONST;
+ else if (had_var)
+ *cvq = CV_VAR;
+ else
+ *cvq = CV_NONE;
+ *noref = had_noref;
+ *noreturn = had_noreturn;
+ *is_static = had_static;
+ return true;
+onerr:
+ parseerror(parser, "parse error after variable qualifier");
+ *cvq = CV_WRONG;
+ return true;
+}
+
+static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression **out);
+static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **out)
+{
+ bool rv;
+ char *label = NULL;
+
+ /* skip the 'while' and get the body */
+ if (!parser_next(parser)) {
+ if (OPTS_FLAG(LOOP_LABELS))
+ parseerror(parser, "expected loop label or 'switch' operand in parenthesis");
+ else
+ parseerror(parser, "expected 'switch' operand in parenthesis");
+ return false;
+ }
+
+ if (parser->tok == ':') {
+ if (!OPTS_FLAG(LOOP_LABELS))
+ parseerror(parser, "labeled loops not activated, try using -floop-labels");
+ if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
+ parseerror(parser, "expected loop label");
+ return false;
+ }
+ label = util_strdup(parser_tokval(parser));
+ if (!parser_next(parser)) {
+ mem_d(label);
+ parseerror(parser, "expected 'switch' operand in parenthesis");
+ return false;
+ }
+ }