aboutsummaryrefslogtreecommitdiff
path: root/src/parser.cpp
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2016-09-04 16:16:17 +0100
committerGinger Bill <bill@gingerbill.org>2016-09-04 16:16:17 +0100
commitc2e3c3801acd8af32fcf6ea3ad2d3a2ddc94c870 (patch)
tree4686866a14b65f9d9c4a37567c8593f7951b1881 /src/parser.cpp
parentcdd8eadda172b3ced7a774dfa1f22a976b3bdb7f (diff)
Type match statement for tagged unions
Diffstat (limited to 'src/parser.cpp')
-rw-r--r--src/parser.cpp121
1 files changed, 83 insertions, 38 deletions
diff --git a/src/parser.cpp b/src/parser.cpp
index b2e4aba93..eb7d05952 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -164,6 +164,11 @@ AST_NODE_KIND(_ComplexStmtBegin, "", struct{}) \
AstNode *init, *tag; \
AstNode *body; \
}) \
+ AST_NODE_KIND(TypeMatchStmt, "type match statement", struct { \
+ Token token; \
+ AstNode *tag, *var; \
+ AstNode *body; \
+ }) \
AST_NODE_KIND(DeferStmt, "defer statement", struct { Token token; AstNode *stmt; }) \
AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; }) \
AST_NODE_KIND(UsingStmt, "using statement", struct { Token token; AstNode *node; }) \
@@ -682,6 +687,16 @@ gb_inline AstNode *make_match_stmt(AstFile *f, Token token, AstNode *init, AstNo
return result;
}
+
+gb_inline AstNode *make_type_match_stmt(AstFile *f, Token token, AstNode *tag, AstNode *var, AstNode *body) {
+ AstNode *result = make_node(f, AstNode_TypeMatchStmt);
+ result->TypeMatchStmt.token = token;
+ result->TypeMatchStmt.tag = tag;
+ result->TypeMatchStmt.var = var;
+ result->TypeMatchStmt.body = body;
+ return result;
+}
+
gb_inline AstNode *make_case_clause(AstFile *f, Token token, AstNode *list, isize list_count, AstNode *stmts, isize stmt_count) {
AstNode *result = make_node(f, AstNode_CaseClause);
result->CaseClause.token = token;
@@ -1399,10 +1414,7 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) {
break;
case Token_OpenBrace: {
- if (is_literal_type(operand) && f->expr_level >= 0) {
- if (lhs) {
- // TODO(bill): Handle this
- }
+ if (!lhs && is_literal_type(operand) && f->expr_level >= 0) {
operand = parse_literal_value(f, operand);
} else {
loop = false;
@@ -1432,7 +1444,7 @@ AstNode *parse_unary_expr(AstFile *f, b32 lhs) {
AstNode *operand;
Token op = f->cursor[0];
next_token(f);
- operand = parse_unary_expr(f, false);
+ operand = parse_unary_expr(f, lhs);
return make_unary_expr(f, op, operand);
} break;
}
@@ -2247,6 +2259,23 @@ AstNode *parse_case_clause(AstFile *f) {
return make_case_clause(f, token, list, list_count, stmts, stmt_count);
}
+
+AstNode *parse_type_case_clause(AstFile *f) {
+ Token token = f->cursor[0];
+ AstNode *clause = NULL;
+ if (allow_token(f, Token_case)) {
+ clause = parse_expr(f, false);
+ } else {
+ expect_token(f, Token_default);
+ }
+ expect_token(f, Token_Colon); // TODO(bill): Is this the best syntax?
+ isize stmt_count = 0;
+ AstNode *stmts = parse_stmt_list(f, &stmt_count);
+
+ return make_case_clause(f, token, clause, 1, stmts, stmt_count);
+}
+
+
AstNode *parse_match_stmt(AstFile *f) {
if (f->curr_proc == NULL) {
ast_file_err(f, f->cursor[0], "You cannot use a match statement in the file scope");
@@ -2254,50 +2283,66 @@ AstNode *parse_match_stmt(AstFile *f) {
}
Token token = expect_token(f, Token_match);
-
AstNode *init = NULL;
AstNode *tag = NULL;
- if (f->cursor[0].kind != Token_OpenBrace) {
- isize prev_level = f->expr_level;
- f->expr_level = -1;
- if (f->cursor[0].kind != Token_Semicolon) {
- tag = parse_simple_stmt(f);
+ AstNode *body = NULL;
+ Token open, close;
+
+ if (allow_token(f, Token_type)) {
+ tag = parse_expr(f, true);
+ expect_token(f, Token_ArrowRight);
+ AstNode *var = parse_identifier(f);
+
+ open = expect_token(f, Token_OpenBrace);
+ AstNode *list = NULL;
+ AstNode *list_curr = NULL;
+ isize list_count = 0;
+
+ while (f->cursor[0].kind == Token_case ||
+ f->cursor[0].kind == Token_default) {
+ DLIST_APPEND(list, list_curr, parse_type_case_clause(f));
+ list_count++;
}
- if (allow_token(f, Token_Semicolon)) {
- init = tag;
- tag = NULL;
- if (f->cursor[0].kind != Token_OpenBrace) {
+
+ close = expect_token(f, Token_CloseBrace);
+ body = make_block_stmt(f, list, list_count, open, close);
+ return make_type_match_stmt(f, token, tag, var, body);
+ } else {
+ if (f->cursor[0].kind != Token_OpenBrace) {
+ isize prev_level = f->expr_level;
+ f->expr_level = -1;
+ if (f->cursor[0].kind != Token_Semicolon) {
tag = parse_simple_stmt(f);
}
- }
+ if (allow_token(f, Token_Semicolon)) {
+ init = tag;
+ tag = NULL;
+ if (f->cursor[0].kind != Token_OpenBrace) {
+ tag = parse_simple_stmt(f);
+ }
+ }
- f->expr_level = prev_level;
- }
+ f->expr_level = prev_level;
+ }
- Token open = expect_token(f, Token_OpenBrace);
- AstNode *list = NULL;
- AstNode *list_curr = NULL;
- isize list_count = 0;
-#if 1
- while (f->cursor[0].kind == Token_case ||
- f->cursor[0].kind == Token_default) {
- DLIST_APPEND(list, list_curr, parse_case_clause(f));
- list_count++;
- }
-#else
+ open = expect_token(f, Token_OpenBrace);
+ AstNode *list = NULL;
+ AstNode *list_curr = NULL;
+ isize list_count = 0;
- while (f->cursor[0].kind == Token_ArrowRight) {
- DLIST_APPEND(list, list_curr, parse_case_clause(f));
- list_count++;
- }
+ while (f->cursor[0].kind == Token_case ||
+ f->cursor[0].kind == Token_default) {
+ DLIST_APPEND(list, list_curr, parse_case_clause(f));
+ list_count++;
+ }
-#endif
- Token close = expect_token(f, Token_CloseBrace);
+ close = expect_token(f, Token_CloseBrace);
- AstNode *body = make_block_stmt(f, list, list_count, open, close);
+ body = make_block_stmt(f, list, list_count, open, close);
- tag = convert_stmt_to_expr(f, tag, make_string("match expression"));
- return make_match_stmt(f, token, init, tag, body);
+ tag = convert_stmt_to_expr(f, tag, make_string("match expression"));
+ return make_match_stmt(f, token, init, tag, body);
+ }
}