harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 1b0fc58f155539dd081b27922c8cc6bce4243541
parent 1c1d9d41bd4768c440c269fc907019f2a6c11c11
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat, 16 Jan 2021 15:03:22 -0500

parse: implement switch expression

Diffstat:
Minclude/ast.h | 17+++++++++++++++++
Msrc/lex.c | 3+++
Msrc/parse.c | 94++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
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);