commit 1b0fc58f155539dd081b27922c8cc6bce4243541
parent 1c1d9d41bd4768c440c269fc907019f2a6c11c11
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 16 Jan 2021 15:03:22 -0500
parse: implement switch expression
Diffstat:
3 files changed, 113 insertions(+), 1 deletion(-)
diff --git a/include/ast.h b/include/ast.h
@@ -260,6 +260,22 @@ struct ast_field_value {
struct ast_field_value *next;
};
+struct ast_case_option {
+ struct ast_expression *value;
+ struct ast_case_option *next;
+};
+
+struct ast_switch_case {
+ struct ast_case_option *options; // NULL for *
+ struct ast_expression *value;
+ struct ast_switch_case *next;
+};
+
+struct ast_expression_switch {
+ struct ast_expression *value;
+ struct ast_switch_case *cases;
+};
+
struct ast_expression_struct {
bool autofill;
struct identifier type;
@@ -292,6 +308,7 @@ struct ast_expression {
struct ast_expression_return _return;
struct ast_expression_slice slice;
struct ast_expression_struct _struct;
+ struct ast_expression_switch _switch;
struct ast_expression_unarithm unarithm;
};
};
diff --git a/src/lex.c b/src/lex.c
@@ -766,6 +766,9 @@ lex2(struct lexer *lexer, struct token *out, uint32_t c)
case '=':
out->token = T_LEQUAL;
break;
+ case '>':
+ out->token = T_CASE;
+ break;
default:
push(lexer, c, false);
out->token = T_EQUAL;
diff --git a/src/parse.c b/src/parse.c
@@ -1593,6 +1593,97 @@ parse_for_expression(struct lexer *lexer)
return exp;
}
+static struct ast_case_option *
+parse_case_options(struct lexer *lexer)
+{
+ struct token tok = {0};
+ switch (lex(lexer, &tok)) {
+ case T_TIMES:
+ want(lexer, T_CASE, &tok);
+ return NULL;
+ default:
+ unlex(lexer, &tok);
+ break;
+ }
+
+ bool more = true;
+ struct ast_case_option *opt = xcalloc(1, sizeof(struct ast_case_option));
+ struct ast_case_option *opts = opt;
+ struct ast_case_option **next = &opt->next;
+ while (more) {
+ opt->value = parse_simple_expression(lexer);
+ switch (lex(lexer, &tok)) {
+ case T_COMMA:
+ switch (lex(lexer, &tok)) {
+ case T_CASE:
+ more = false;
+ break;
+ default:
+ unlex(lexer, &tok);
+ break;
+ }
+ break;
+ case T_CASE:
+ more = false;
+ break;
+ default:
+ unlex(lexer, &tok);
+ opt = xcalloc(1, sizeof(struct ast_case_option));
+ *next = opt;
+ next = &opt->next;
+ break;
+ }
+ }
+
+ return opts;
+}
+
+static struct ast_expression *
+parse_switch_expression(struct lexer *lexer)
+{
+ trenter(TR_PARSE, "switch");
+ struct ast_expression *exp = mkexpr(&lexer->loc);
+ exp->type = EXPR_SWITCH;
+
+ struct token tok = {0};
+ want(lexer, T_LPAREN, &tok);
+ exp->_switch.value = parse_simple_expression(lexer);
+ want(lexer, T_RPAREN, &tok);
+
+ want(lexer, T_LBRACE, &tok);
+
+ bool more = true;
+ struct ast_switch_case **next_case = &exp->_switch.cases;
+ while (more) {
+ struct ast_switch_case *_case =
+ *next_case = xcalloc(1, sizeof(struct ast_switch_case));
+ _case->options = parse_case_options(lexer);
+ _case->value = parse_compound_expression(lexer);
+
+ switch (lex(lexer, &tok)) {
+ case T_COMMA:
+ switch (lex(lexer, &tok)) {
+ case T_RBRACE:
+ more = false;
+ break;
+ default:
+ unlex(lexer, &tok);
+ break;
+ }
+ break;
+ case T_RBRACE:
+ more = false;
+ break;
+ default:
+ synassert(false, &tok, T_COMMA, T_RBRACE, T_EOF);
+ }
+
+ next_case = &_case->next;
+ }
+
+ return exp;
+}
+
static struct ast_expression *
parse_complex_expression(struct lexer *lexer)
{
@@ -1605,8 +1696,9 @@ parse_complex_expression(struct lexer *lexer)
unlex(lexer, &tok);
return parse_for_expression(lexer);
case T_MATCH:
- case T_SWITCH:
assert(0); // TODO
+ case T_SWITCH:
+ return parse_switch_expression(lexer);
default:
unlex(lexer, &tok);
return parse_simple_expression(lexer);