aboutsummaryrefslogtreecommitdiff
path: root/src/parser.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2016-01-19 20:29:09 -0700
committerAndrew Kelley <superjoe30@gmail.com>2016-01-19 20:29:36 -0700
commitc17309dbc52c055dfd147ba46c6fa110df6b8227 (patch)
tree3773ed747e002cba9cf8a9b1d9ae1b3edc2e06e4 /src/parser.cpp
parent17e574fec60b5e675a8ac69d197f1cc28336056c (diff)
downloadzig-c17309dbc52c055dfd147ba46c6fa110df6b8227.tar.gz
zig-c17309dbc52c055dfd147ba46c6fa110df6b8227.zip
add switch statement support to parser
Diffstat (limited to 'src/parser.cpp')
-rw-r--r--src/parser.cpp117
1 files changed, 112 insertions, 5 deletions
diff --git a/src/parser.cpp b/src/parser.cpp
index 6d86c53518..32ecc9885a 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -123,6 +123,12 @@ const char *node_type_str(NodeType node_type) {
return "WhileExpr";
case NodeTypeForExpr:
return "ForExpr";
+ case NodeTypeSwitchExpr:
+ return "SwitchExpr";
+ case NodeTypeSwitchProng:
+ return "SwitchProng";
+ case NodeTypeSwitchRange:
+ return "SwitchRange";
case NodeTypeLabel:
return "Label";
case NodeTypeGoto:
@@ -342,6 +348,30 @@ void ast_print(AstNode *node, int indent) {
}
ast_print(node->data.for_expr.body, indent + 2);
break;
+ case NodeTypeSwitchExpr:
+ fprintf(stderr, "%s\n", node_type_str(node->type));
+ ast_print(node->data.switch_expr.expr, indent + 2);
+ for (int i = 0; i < node->data.switch_expr.prongs.length; i += 1) {
+ AstNode *child_node = node->data.switch_expr.prongs.at(i);
+ ast_print(child_node, indent + 2);
+ }
+ break;
+ case NodeTypeSwitchProng:
+ fprintf(stderr, "%s\n", node_type_str(node->type));
+ for (int i = 0; i < node->data.switch_prong.items.length; i += 1) {
+ AstNode *child_node = node->data.switch_prong.items.at(i);
+ ast_print(child_node, indent + 2);
+ }
+ if (node->data.switch_prong.var_symbol) {
+ ast_print(node->data.switch_prong.var_symbol, indent + 2);
+ }
+ ast_print(node->data.switch_prong.expr, indent + 2);
+ break;
+ case NodeTypeSwitchRange:
+ fprintf(stderr, "%s\n", node_type_str(node->type));
+ ast_print(node->data.switch_range.start, indent + 2);
+ ast_print(node->data.switch_range.end, indent + 2);
+ break;
case NodeTypeLabel:
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name));
break;
@@ -2167,7 +2197,80 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mand
}
/*
-BlockExpression : IfExpression | Block | WhileExpression | ForExpression
+SwitchExpression : "switch" "(" Expression ")" "{" many(SwitchProng) "}"
+SwitchProng : (list(SwitchItem, ",") | "else") option("," "(" "Symbol" ")") "=>" Expression ","
+SwitchItem : Expression | (Expression "..." Expression)
+*/
+static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool mandatory) {
+ Token *token = &pc->tokens->at(*token_index);
+
+ if (token->id != TokenIdKeywordSwitch) {
+ if (mandatory) {
+ ast_invalid_token_error(pc, token);
+ } else {
+ return nullptr;
+ }
+ }
+ *token_index += 1;
+
+ AstNode *node = ast_create_node(pc, NodeTypeSwitchExpr, token);
+
+ ast_eat_token(pc, token_index, TokenIdLParen);
+ node->data.switch_expr.expr = ast_parse_expression(pc, token_index, true);
+ ast_eat_token(pc, token_index, TokenIdRParen);
+ ast_eat_token(pc, token_index, TokenIdLBrace);
+
+ for (;;) {
+ Token *token = &pc->tokens->at(*token_index);
+
+ if (token->id == TokenIdRBrace) {
+ *token_index += 1;
+ return node;
+ }
+
+ AstNode *prong_node = ast_create_node(pc, NodeTypeSwitchProng, token);
+ node->data.switch_expr.prongs.append(prong_node);
+
+ if (token->id == TokenIdKeywordElse) {
+ *token_index += 1;
+ } else for (;;) {
+ AstNode *expr1 = ast_parse_expression(pc, token_index, true);
+ Token *ellipsis_tok = &pc->tokens->at(*token_index);
+ if (ellipsis_tok->id == TokenIdEllipsis) {
+ *token_index += 1;
+
+ AstNode *range_node = ast_create_node(pc, NodeTypeSwitchRange, ellipsis_tok);
+ prong_node->data.switch_prong.items.append(range_node);
+
+ range_node->data.switch_range.start = expr1;
+ range_node->data.switch_range.end = ast_parse_expression(pc, token_index, true);
+ } else {
+ prong_node->data.switch_prong.items.append(expr1);
+ }
+ Token *comma_tok = &pc->tokens->at(*token_index);
+ if (comma_tok->id == TokenIdComma) {
+ *token_index += 1;
+ continue;
+ }
+ break;
+ }
+
+ Token *arrow_or_comma = &pc->tokens->at(*token_index);
+ if (arrow_or_comma->id == TokenIdComma) {
+ *token_index += 1;
+ ast_eat_token(pc, token_index, TokenIdLParen);
+ prong_node->data.switch_prong.var_symbol = ast_parse_symbol(pc, token_index);
+ ast_eat_token(pc, token_index, TokenIdRParen);
+ }
+
+ ast_eat_token(pc, token_index, TokenIdFatArrow);
+ prong_node->data.switch_prong.expr = ast_parse_expression(pc, token_index, true);
+ ast_eat_token(pc, token_index, TokenIdComma);
+ }
+}
+
+/*
+BlockExpression : IfExpression | Block | WhileExpression | ForExpression | SwitchExpression
*/
static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
@@ -2176,10 +2279,6 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma
if (if_expr)
return if_expr;
- AstNode *block = ast_parse_block(pc, token_index, false);
- if (block)
- return block;
-
AstNode *while_expr = ast_parse_while_expr(pc, token_index, false);
if (while_expr)
return while_expr;
@@ -2188,6 +2287,14 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma
if (for_expr)
return for_expr;
+ AstNode *switch_expr = ast_parse_switch_expr(pc, token_index, false);
+ if (switch_expr)
+ return switch_expr;
+
+ AstNode *block = ast_parse_block(pc, token_index, false);
+ if (block)
+ return block;
+
if (mandatory)
ast_invalid_token_error(pc, token);