commit 07196daba75a25dcde6f2f20dca666ad662467c7
parent 9fc2f079bbef9ac7491174b547b146b572a0f876
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 22 Jan 2021 19:24:41 -0500
parse: implement match expressions
Diffstat:
M | include/ast.h | | | 43 | ++++++++++++++++++++++++++++--------------- |
M | src/parse.c | | | 88 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
2 files changed, 115 insertions(+), 16 deletions(-)
diff --git a/include/ast.h b/include/ast.h
@@ -224,6 +224,18 @@ struct ast_expression_list {
struct ast_expression_list *next;
};
+struct ast_match_case {
+ char *name; // May be null
+ struct ast_type *type;
+ struct ast_expression *value;
+ struct ast_match_case *next;
+};
+
+struct ast_expression_match {
+ struct ast_expression *value;
+ struct ast_match_case *cases;
+};
+
struct ast_expression_measure {
enum measure_operator op;
union {
@@ -242,21 +254,6 @@ struct ast_expression_slice {
struct ast_expression *start, *end;
};
-struct ast_expression_struct;
-
-struct ast_field_value {
- bool is_embedded;
- union {
- struct {
- char *name;
- struct ast_type *type;
- struct ast_expression *initializer;
- } field;
- struct ast_expression *embedded;
- };
- struct ast_field_value *next;
-};
-
struct ast_case_option {
struct ast_expression *value;
struct ast_case_option *next;
@@ -273,6 +270,21 @@ struct ast_expression_switch {
struct ast_switch_case *cases;
};
+struct ast_expression_struct;
+
+struct ast_field_value {
+ bool is_embedded;
+ union {
+ struct {
+ char *name;
+ struct ast_type *type;
+ struct ast_expression *initializer;
+ } field;
+ struct ast_expression *embedded;
+ };
+ struct ast_field_value *next;
+};
+
struct ast_expression_struct {
bool autofill;
struct identifier type;
@@ -302,6 +314,7 @@ struct ast_expression {
struct ast_expression_for _for;
struct ast_expression_if _if;
struct ast_expression_list list;
+ struct ast_expression_match match;
struct ast_expression_measure measure;
struct ast_expression_return _return;
struct ast_expression_slice slice;
diff --git a/src/parse.c b/src/parse.c
@@ -1691,6 +1691,92 @@ parse_switch_expression(struct lexer *lexer)
}
static struct ast_expression *
+parse_match_expression(struct lexer *lexer)
+{
+ trenter(TR_PARSE, "match");
+ struct ast_expression *exp = mkexpr(&lexer->loc);
+ exp->type = EXPR_MATCH;
+
+ struct token tok = {0};
+ want(lexer, T_LPAREN, &tok);
+ exp->match.value = parse_simple_expression(lexer);
+ want(lexer, T_RPAREN, &tok);
+ want(lexer, T_LBRACE, &tok);
+
+ bool more = true;
+ struct ast_match_case **next_case = &exp->match.cases;
+ while (more) {
+ struct ast_match_case *_case =
+ *next_case = xcalloc(1, sizeof(struct ast_match_case));
+
+ struct token tok2 = {0};
+ switch (lex(lexer, &tok)) {
+ case T_NAME:
+ switch (lex(lexer, &tok2)) {
+ case T_COLON:
+ _case->name = tok.name; // Assumes ownership
+ _case->type = parse_type(lexer);
+ break;
+ case T_DOUBLE_COLON:
+ _case->type = parse_type(lexer);
+ assert(_case->type->storage == TYPE_STORAGE_ALIAS);
+ struct identifier ident = {
+ .name = tok.name, // Assumes ownership
+ .ns = xcalloc(1, sizeof(struct identifier)),
+ };
+ *ident.ns = _case->type->alias;
+ _case->type->alias = ident;
+ break;
+ case T_CASE:
+ unlex(lexer, &tok);
+ _case->type = parse_type(lexer);
+ assert(_case->type->storage == TYPE_STORAGE_ALIAS);
+ unlex(lexer, &tok2);
+ break;
+ default:
+ synassert(false, &tok, T_COLON,
+ T_DOUBLE_COLON, T_CASE, T_EOF);
+ break;
+ }
+ break;
+ case T_TIMES:
+ want(lexer, T_CASE, &tok);
+ break;
+ default:
+ unlex(lexer, &tok);
+ _case->type = parse_type(lexer);
+ want(lexer, T_CASE, &tok);
+ break;
+ }
+
+ _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;
+ }
+
+ trleave(TR_PARSE, NULL);
+ return exp;
+}
+
+static struct ast_expression *
parse_complex_expression(struct lexer *lexer)
{
struct token tok;
@@ -1702,7 +1788,7 @@ parse_complex_expression(struct lexer *lexer)
unlex(lexer, &tok);
return parse_for_expression(lexer);
case T_MATCH:
- assert(0); // TODO
+ return parse_match_expression(lexer);
case T_SWITCH:
return parse_switch_expression(lexer);
default: