authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-19 20:29:09-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-19 20:29:36-07:00
logc17309dbc52c055dfd147ba46c6fa110df6b8227
tree3773ed747e002cba9cf8a9b1d9ae1b3edc2e06e4
parent17e574fec60b5e675a8ac69d197f1cc28336056c

add switch statement support to parser


7 files changed, 204 insertions(+), 6 deletions(-)

doc/langref.md+1-1
......@@ -94,7 +94,7 @@ BlockExpression : IfExpression | Block | WhileExpression | ForExpression | Switc
9494
9595SwitchExpression : "switch" "(" Expression ")" "{" many(SwitchProng) "}"
9696
97SwitchProng : (list(SwitchItem, ",") | "else") option("(" "Symbol" ")") "=>" Expression ","
97SwitchProng : (list(SwitchItem, ",") | "else") option("," "(" "Symbol" ")") "=>" Expression ","
9898
9999SwitchItem : Expression | (Expression "..." Expression)
100100
src/all_types.hpp+25
......@@ -139,6 +139,9 @@ enum NodeType {
139139 NodeTypeIfVarExpr,
140140 NodeTypeWhileExpr,
141141 NodeTypeForExpr,
142 NodeTypeSwitchExpr,
143 NodeTypeSwitchProng,
144 NodeTypeSwitchRange,
142145 NodeTypeLabel,
143146 NodeTypeGoto,
144147 NodeTypeBreak,
......@@ -411,6 +414,25 @@ struct AstNodeForExpr {
411414 VariableTableEntry *index_var;
412415};
413416
417struct AstNodeSwitchExpr {
418 AstNode *expr;
419 ZigList<AstNode *> prongs;
420
421 // populated by semantic analyzer
422 Expr resolved_expr;
423};
424
425struct AstNodeSwitchProng {
426 ZigList<AstNode *> items;
427 AstNode *var_symbol;
428 AstNode *expr;
429};
430
431struct AstNodeSwitchRange {
432 AstNode *start;
433 AstNode *end;
434};
435
414436struct AstNodeLabel {
415437 Buf name;
416438
......@@ -623,6 +645,9 @@ struct AstNode {
623645 AstNodeIfVarExpr if_var_expr;
624646 AstNodeWhileExpr while_expr;
625647 AstNodeForExpr for_expr;
648 AstNodeSwitchExpr switch_expr;
649 AstNodeSwitchProng switch_prong;
650 AstNodeSwitchRange switch_range;
626651 AstNodeLabel label;
627652 AstNodeGoto goto_expr;
628653 AstNodeAsmExpr asm_expr;
src/analyze.cpp+52
......@@ -30,6 +30,8 @@ static AstNode *first_executing_node(AstNode *node) {
3030 return first_executing_node(node->data.slice_expr.array_ref_expr);
3131 case NodeTypeFieldAccessExpr:
3232 return first_executing_node(node->data.field_access_expr.struct_expr);
33 case NodeTypeSwitchRange:
34 return first_executing_node(node->data.switch_range.start);
3335 case NodeTypeRoot:
3436 case NodeTypeRootExportDecl:
3537 case NodeTypeFnProto:
......@@ -61,6 +63,8 @@ static AstNode *first_executing_node(AstNode *node) {
6163 case NodeTypeStructValueField:
6264 case NodeTypeWhileExpr:
6365 case NodeTypeForExpr:
66 case NodeTypeSwitchExpr:
67 case NodeTypeSwitchProng:
6468 case NodeTypeContainerInitExpr:
6569 case NodeTypeArrayType:
6670 return node;
......@@ -943,6 +947,9 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
943947 case NodeTypeIfVarExpr:
944948 case NodeTypeWhileExpr:
945949 case NodeTypeForExpr:
950 case NodeTypeSwitchExpr:
951 case NodeTypeSwitchProng:
952 case NodeTypeSwitchRange:
946953 case NodeTypeLabel:
947954 case NodeTypeGoto:
948955 case NodeTypeBreak:
......@@ -3007,6 +3014,12 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
30073014 zig_unreachable();
30083015}
30093016
3017static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
3018 TypeTableEntry *expected_type, AstNode *node)
3019{
3020 zig_panic("TODO analyze_switch_expr");
3021}
3022
30103023static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
30113024 TypeTableEntry *expected_type, AstNode *node)
30123025{
......@@ -3184,6 +3197,11 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
31843197 case NodeTypeArrayType:
31853198 return_type = analyze_array_type(g, import, context, expected_type, node);
31863199 break;
3200 case NodeTypeSwitchExpr:
3201 return_type = analyze_switch_expr(g, import, context, expected_type, node);
3202 break;
3203 case NodeTypeSwitchProng:
3204 case NodeTypeSwitchRange:
31873205 case NodeTypeDirective:
31883206 case NodeTypeFnDecl:
31893207 case NodeTypeFnProto:
......@@ -3338,6 +3356,9 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
33383356 case NodeTypeIfVarExpr:
33393357 case NodeTypeWhileExpr:
33403358 case NodeTypeForExpr:
3359 case NodeTypeSwitchExpr:
3360 case NodeTypeSwitchProng:
3361 case NodeTypeSwitchRange:
33413362 case NodeTypeLabel:
33423363 case NodeTypeGoto:
33433364 case NodeTypeBreak:
......@@ -3472,6 +3493,24 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
34723493 }
34733494 collect_expr_decl_deps(g, import, node->data.array_type.child_type, decl_node);
34743495 break;
3496 case NodeTypeSwitchExpr:
3497 collect_expr_decl_deps(g, import, node->data.switch_expr.expr, decl_node);
3498 for (int i = 0; i < node->data.switch_expr.prongs.length; i += 1) {
3499 AstNode *prong = node->data.switch_expr.prongs.at(i);
3500 collect_expr_decl_deps(g, import, prong, decl_node);
3501 }
3502 break;
3503 case NodeTypeSwitchProng:
3504 for (int i = 0; i < node->data.switch_prong.items.length; i += 1) {
3505 AstNode *child = node->data.switch_prong.items.at(i);
3506 collect_expr_decl_deps(g, import, child, decl_node);
3507 }
3508 collect_expr_decl_deps(g, import, node->data.switch_prong.expr, decl_node);
3509 break;
3510 case NodeTypeSwitchRange:
3511 collect_expr_decl_deps(g, import, node->data.switch_range.start, decl_node);
3512 collect_expr_decl_deps(g, import, node->data.switch_range.end, decl_node);
3513 break;
34753514 case NodeTypeVariableDeclaration:
34763515 case NodeTypeFnProto:
34773516 case NodeTypeExternBlock:
......@@ -3661,6 +3700,9 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
36613700 case NodeTypeIfVarExpr:
36623701 case NodeTypeWhileExpr:
36633702 case NodeTypeForExpr:
3703 case NodeTypeSwitchExpr:
3704 case NodeTypeSwitchProng:
3705 case NodeTypeSwitchRange:
36643706 case NodeTypeLabel:
36653707 case NodeTypeGoto:
36663708 case NodeTypeBreak:
......@@ -3869,6 +3911,10 @@ Expr *get_resolved_expr(AstNode *node) {
38693911 return &node->data.label.resolved_expr;
38703912 case NodeTypeArrayType:
38713913 return &node->data.array_type.resolved_expr;
3914 case NodeTypeSwitchExpr:
3915 return &node->data.switch_expr.resolved_expr;
3916 case NodeTypeSwitchProng:
3917 case NodeTypeSwitchRange:
38723918 case NodeTypeRoot:
38733919 case NodeTypeRootExportDecl:
38743920 case NodeTypeFnProto:
......@@ -3902,6 +3948,9 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
39023948 case NodeTypeIfVarExpr:
39033949 case NodeTypeWhileExpr:
39043950 case NodeTypeForExpr:
3951 case NodeTypeSwitchExpr:
3952 case NodeTypeSwitchProng:
3953 case NodeTypeSwitchRange:
39053954 case NodeTypeAsmExpr:
39063955 case NodeTypeContainerInitExpr:
39073956 case NodeTypeRoot:
......@@ -3953,6 +4002,9 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
39534002 case NodeTypeIfVarExpr:
39544003 case NodeTypeWhileExpr:
39554004 case NodeTypeForExpr:
4005 case NodeTypeSwitchExpr:
4006 case NodeTypeSwitchProng:
4007 case NodeTypeSwitchRange:
39564008 case NodeTypeAsmExpr:
39574009 case NodeTypeContainerInitExpr:
39584010 case NodeTypeRoot:
src/codegen.cpp+10
......@@ -1965,6 +1965,12 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
19651965 return fn_entry->fn_value;
19661966}
19671967
1968static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
1969 assert(node->type == NodeTypeSwitchExpr);
1970
1971 zig_panic("TODO gen_switch_expr");
1972}
1973
19681974static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
19691975 switch (node->type) {
19701976 case NodeTypeBinOpExpr:
......@@ -2040,6 +2046,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
20402046 }
20412047 case NodeTypeContainerInitExpr:
20422048 return gen_container_init_expr(g, node);
2049 case NodeTypeSwitchExpr:
2050 return gen_switch_expr(g, node);
20432051 case NodeTypeRoot:
20442052 case NodeTypeRootExportDecl:
20452053 case NodeTypeFnProto:
......@@ -2053,6 +2061,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
20532061 case NodeTypeStructField:
20542062 case NodeTypeStructValueField:
20552063 case NodeTypeArrayType:
2064 case NodeTypeSwitchProng:
2065 case NodeTypeSwitchRange:
20562066 zig_unreachable();
20572067 }
20582068 zig_unreachable();
src/parser.cpp+112-5
......@@ -123,6 +123,12 @@ const char *node_type_str(NodeType node_type) {
123123 return "WhileExpr";
124124 case NodeTypeForExpr:
125125 return "ForExpr";
126 case NodeTypeSwitchExpr:
127 return "SwitchExpr";
128 case NodeTypeSwitchProng:
129 return "SwitchProng";
130 case NodeTypeSwitchRange:
131 return "SwitchRange";
126132 case NodeTypeLabel:
127133 return "Label";
128134 case NodeTypeGoto:
......@@ -342,6 +348,30 @@ void ast_print(AstNode *node, int indent) {
342348 }
343349 ast_print(node->data.for_expr.body, indent + 2);
344350 break;
351 case NodeTypeSwitchExpr:
352 fprintf(stderr, "%s\n", node_type_str(node->type));
353 ast_print(node->data.switch_expr.expr, indent + 2);
354 for (int i = 0; i < node->data.switch_expr.prongs.length; i += 1) {
355 AstNode *child_node = node->data.switch_expr.prongs.at(i);
356 ast_print(child_node, indent + 2);
357 }
358 break;
359 case NodeTypeSwitchProng:
360 fprintf(stderr, "%s\n", node_type_str(node->type));
361 for (int i = 0; i < node->data.switch_prong.items.length; i += 1) {
362 AstNode *child_node = node->data.switch_prong.items.at(i);
363 ast_print(child_node, indent + 2);
364 }
365 if (node->data.switch_prong.var_symbol) {
366 ast_print(node->data.switch_prong.var_symbol, indent + 2);
367 }
368 ast_print(node->data.switch_prong.expr, indent + 2);
369 break;
370 case NodeTypeSwitchRange:
371 fprintf(stderr, "%s\n", node_type_str(node->type));
372 ast_print(node->data.switch_range.start, indent + 2);
373 ast_print(node->data.switch_range.end, indent + 2);
374 break;
345375 case NodeTypeLabel:
346376 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name));
347377 break;
......@@ -2167,7 +2197,80 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mand
21672197}
21682198
21692199/*
2170BlockExpression : IfExpression | Block | WhileExpression | ForExpression
2200SwitchExpression : "switch" "(" Expression ")" "{" many(SwitchProng) "}"
2201SwitchProng : (list(SwitchItem, ",") | "else") option("," "(" "Symbol" ")") "=>" Expression ","
2202SwitchItem : Expression | (Expression "..." Expression)
2203*/
2204static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool mandatory) {
2205 Token *token = &pc->tokens->at(*token_index);
2206
2207 if (token->id != TokenIdKeywordSwitch) {
2208 if (mandatory) {
2209 ast_invalid_token_error(pc, token);
2210 } else {
2211 return nullptr;
2212 }
2213 }
2214 *token_index += 1;
2215
2216 AstNode *node = ast_create_node(pc, NodeTypeSwitchExpr, token);
2217
2218 ast_eat_token(pc, token_index, TokenIdLParen);
2219 node->data.switch_expr.expr = ast_parse_expression(pc, token_index, true);
2220 ast_eat_token(pc, token_index, TokenIdRParen);
2221 ast_eat_token(pc, token_index, TokenIdLBrace);
2222
2223 for (;;) {
2224 Token *token = &pc->tokens->at(*token_index);
2225
2226 if (token->id == TokenIdRBrace) {
2227 *token_index += 1;
2228 return node;
2229 }
2230
2231 AstNode *prong_node = ast_create_node(pc, NodeTypeSwitchProng, token);
2232 node->data.switch_expr.prongs.append(prong_node);
2233
2234 if (token->id == TokenIdKeywordElse) {
2235 *token_index += 1;
2236 } else for (;;) {
2237 AstNode *expr1 = ast_parse_expression(pc, token_index, true);
2238 Token *ellipsis_tok = &pc->tokens->at(*token_index);
2239 if (ellipsis_tok->id == TokenIdEllipsis) {
2240 *token_index += 1;
2241
2242 AstNode *range_node = ast_create_node(pc, NodeTypeSwitchRange, ellipsis_tok);
2243 prong_node->data.switch_prong.items.append(range_node);
2244
2245 range_node->data.switch_range.start = expr1;
2246 range_node->data.switch_range.end = ast_parse_expression(pc, token_index, true);
2247 } else {
2248 prong_node->data.switch_prong.items.append(expr1);
2249 }
2250 Token *comma_tok = &pc->tokens->at(*token_index);
2251 if (comma_tok->id == TokenIdComma) {
2252 *token_index += 1;
2253 continue;
2254 }
2255 break;
2256 }
2257
2258 Token *arrow_or_comma = &pc->tokens->at(*token_index);
2259 if (arrow_or_comma->id == TokenIdComma) {
2260 *token_index += 1;
2261 ast_eat_token(pc, token_index, TokenIdLParen);
2262 prong_node->data.switch_prong.var_symbol = ast_parse_symbol(pc, token_index);
2263 ast_eat_token(pc, token_index, TokenIdRParen);
2264 }
2265
2266 ast_eat_token(pc, token_index, TokenIdFatArrow);
2267 prong_node->data.switch_prong.expr = ast_parse_expression(pc, token_index, true);
2268 ast_eat_token(pc, token_index, TokenIdComma);
2269 }
2270}
2271
2272/*
2273BlockExpression : IfExpression | Block | WhileExpression | ForExpression | SwitchExpression
21712274*/
21722275static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
21732276 Token *token = &pc->tokens->at(*token_index);
......@@ -2176,10 +2279,6 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma
21762279 if (if_expr)
21772280 return if_expr;
21782281
2179 AstNode *block = ast_parse_block(pc, token_index, false);
2180 if (block)
2181 return block;
2182
21832282 AstNode *while_expr = ast_parse_while_expr(pc, token_index, false);
21842283 if (while_expr)
21852284 return while_expr;
......@@ -2188,6 +2287,14 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma
21882287 if (for_expr)
21892288 return for_expr;
21902289
2290 AstNode *switch_expr = ast_parse_switch_expr(pc, token_index, false);
2291 if (switch_expr)
2292 return switch_expr;
2293
2294 AstNode *block = ast_parse_block(pc, token_index, false);
2295 if (block)
2296 return block;
2297
21912298 if (mandatory)
21922299 ast_invalid_token_error(pc, token);
21932300
src/tokenizer.cpp+3
......@@ -243,6 +243,8 @@ static void end_token(Tokenize *t) {
243243 t->cur_tok->id = TokenIdKeywordNull;
244244 } else if (mem_eql_str(token_mem, token_len, "noalias")) {
245245 t->cur_tok->id = TokenIdKeywordNoAlias;
246 } else if (mem_eql_str(token_mem, token_len, "switch")) {
247 t->cur_tok->id = TokenIdKeywordSwitch;
246248 }
247249
248250 t->cur_tok = nullptr;
......@@ -1035,6 +1037,7 @@ const char * token_name(TokenId id) {
10351037 case TokenIdKeywordBreak: return "break";
10361038 case TokenIdKeywordNull: return "null";
10371039 case TokenIdKeywordNoAlias: return "noalias";
1040 case TokenIdKeywordSwitch: return "switch";
10381041 case TokenIdLParen: return "(";
10391042 case TokenIdRParen: return ")";
10401043 case TokenIdComma: return ",";
src/tokenizer.hpp+1
......@@ -36,6 +36,7 @@ enum TokenId {
3636 TokenIdKeywordBreak,
3737 TokenIdKeywordNull,
3838 TokenIdKeywordNoAlias,
39 TokenIdKeywordSwitch,
3940 TokenIdLParen,
4041 TokenIdRParen,
4142 TokenIdComma,