authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-03 00:47:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-03 00:47:35-07:00
logf8ca6c70c74db6e6f0d4462aa763adb6f1f41c7e
tree99bc3d06bb37abb267a2a59f3ba04523c2c430eb
parentc89f77dd8e5005e60e8fb223c6c68b50566ac1ed

add labels and goto


14 files changed, 270 insertions(+), 27 deletions(-)

README.md+6-3
......@@ -45,7 +45,6 @@ make
4545 * variable declarations and assignment expressions
4646 * Type checking
4747 * loops
48 * labels and goto
4948 * inline assembly and syscalls
5049 * conditional compilation and ability to check target platform and architecture
5150 * main function with command line arguments
......@@ -110,7 +109,9 @@ PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type
110109
111110Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
112111
113Statement : NonBlockExpression token(Semicolon) | BlockExpression
112Statement : Label | NonBlockExpression token(Semicolon) | BlockExpression
113
114Label: token(Symbol) token(Colon)
114115
115116Expression : BlockExpression | NonBlockExpression
116117
......@@ -162,7 +163,9 @@ FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma)
162163
163164PrefixOp : token(Not) | token(Dash) | token(Tilde)
164165
165PrimaryExpression : token(Number) | token(String) | token(Unreachable) | GroupedExpression | token(Symbol)
166PrimaryExpression : token(Number) | token(String) | token(Unreachable) | GroupedExpression | token(Symbol) | Goto
167
168Goto: token(Goto) token(Symbol)
166169
167170GroupedExpression : token(LParen) Expression token(RParen)
168171```
doc/vim/syntax/zig.vim+2-2
......@@ -1,13 +1,13 @@
11" Vim syntax file
22" Language: Zig
33" Maintainer: Andrew Kelley
4" Latest Revision: 27 November 2015
4" Latest Revision: 02 December 2015
55
66if exists("b:current_syntax")
77 finish
88endif
99
10syn keyword zigKeyword fn return mut const extern unreachable export pub as use if else let void
10syn keyword zigKeyword fn return mut const extern unreachable export pub as use if else let void goto
1111syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128
1212
1313syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell
example/hello_world/hello.zig+12-1
......@@ -6,7 +6,18 @@ extern {
66 fn exit(code: i32) -> unreachable;
77}
88
9fn loop(a : i32) {
10 if a == 0 {
11 goto done;
12 }
13 puts("loop");
14 loop(a - 1);
15
16done:
17 return;
18}
19
920export fn _start() -> unreachable {
10 puts("Hello, world!");
21 loop(3);
1122 exit(0);
1223}
src/analyze.cpp+65-7
......@@ -131,6 +131,25 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
131131 resolve_type(g, node->data.fn_proto.return_type);
132132}
133133
134static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) {
135 assert(node->type == NodeTypeBlock);
136
137 for (int i = 0; i < node->data.block.statements.length; i += 1) {
138 AstNode *label_node = node->data.block.statements.at(i);
139 if (label_node->type != NodeTypeLabel)
140 continue;
141
142 LabelTableEntry *label_entry = allocate<LabelTableEntry>(1);
143 label_entry->label_node = label_node;
144 Buf *name = &label_node->data.label.name;
145 fn_table_entry->label_table.put(name, label_entry);
146
147 assert(!label_node->codegen_node);
148 label_node->codegen_node = allocate<CodeGenNode>(1);
149 label_node->codegen_node->data.label_entry = label_entry;
150 }
151}
152
134153static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, AstNode *node) {
135154 switch (node->type) {
136155 case NodeTypeExternBlock:
......@@ -158,6 +177,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
158177 fn_table_entry->calling_convention = LLVMCCallConv;
159178 fn_table_entry->import_entry = import;
160179 fn_table_entry->symbol_table.init(8);
180 fn_table_entry->label_table.init(8);
161181
162182 resolve_function_proto(g, fn_proto, fn_table_entry);
163183
......@@ -208,6 +228,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
208228 fn_table_entry->internal_linkage = is_internal;
209229 fn_table_entry->calling_convention = is_internal ? LLVMFastCallConv : LLVMCCallConv;
210230 fn_table_entry->symbol_table.init(8);
231 fn_table_entry->label_table.init(8);
211232
212233 g->fn_protos.append(fn_table_entry);
213234 g->fn_defs.append(fn_table_entry);
......@@ -222,6 +243,8 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
222243 assert(!proto_node->codegen_node);
223244 proto_node->codegen_node = allocate<CodeGenNode>(1);
224245 proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
246
247 preview_function_labels(g, node->data.fn_def.body, fn_table_entry);
225248 }
226249 }
227250 break;
......@@ -290,6 +313,8 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
290313 case NodeTypeCastExpr:
291314 case NodeTypePrefixOpExpr:
292315 case NodeTypeIfExpr:
316 case NodeTypeLabel:
317 case NodeTypeGoto:
293318 zig_unreachable();
294319 }
295320}
......@@ -339,6 +364,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
339364 return_type = g->builtin_types.entry_void;
340365 for (int i = 0; i < node->data.block.statements.length; i += 1) {
341366 AstNode *child = node->data.block.statements.at(i);
367 if (child->type == NodeTypeLabel)
368 continue;
342369 if (return_type == g->builtin_types.entry_unreachable) {
343370 if (child->type == NodeTypeVoid) {
344371 // {unreachable;void;void} is allowed.
......@@ -365,7 +392,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
365392
366393 if (actual_return_type == g->builtin_types.entry_unreachable) {
367394 // "return exit(0)" should just be "exit(0)".
368 add_node_error(g, node, buf_sprintf("returning is unreachable."));
395 add_node_error(g, node, buf_sprintf("returning is unreachable"));
369396 actual_return_type = g->builtin_types.entry_invalid;
370397 }
371398
......@@ -373,7 +400,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
373400 return_type = g->builtin_types.entry_unreachable;
374401 break;
375402 }
376
377403 case NodeTypeVariableDeclaration:
378404 {
379405 zig_panic("TODO: analyze variable declaration");
......@@ -382,6 +408,21 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
382408 break;
383409 }
384410
411 case NodeTypeGoto:
412 {
413 FnTableEntry *fn_table_entry = get_context_fn_entry(context);
414 auto table_entry = fn_table_entry->label_table.maybe_get(&node->data.go_to.name);
415 if (table_entry) {
416 assert(!node->codegen_node);
417 node->codegen_node = allocate<CodeGenNode>(1);
418 node->codegen_node->data.label_entry = table_entry->value;
419 } else {
420 add_node_error(g, node,
421 buf_sprintf("use of undeclared label '%s'", buf_ptr(&node->data.go_to.name)));
422 }
423 return_type = g->builtin_types.entry_unreachable;
424 break;
425 }
385426 case NodeTypeBinOpExpr:
386427 {
387428 switch (node->data.bin_op_expr.bin_op) {
......@@ -563,8 +604,18 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
563604 TypeTableEntry *then_type = analyze_expression(g, import, context, expected_type,
564605 node->data.if_expr.then_block);
565606
566 check_type_compatibility(g, node, expected_type, else_type);
567 return_type = then_type;
607 TypeTableEntry *primary_type;
608 TypeTableEntry *other_type;
609 if (then_type == g->builtin_types.entry_unreachable) {
610 primary_type = else_type;
611 other_type = then_type;
612 } else {
613 primary_type = then_type;
614 other_type = else_type;
615 }
616
617 check_type_compatibility(g, node, expected_type, other_type);
618 return_type = primary_type;
568619 break;
569620 }
570621 case NodeTypeDirective:
......@@ -577,14 +628,19 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
577628 case NodeTypeExternBlock:
578629 case NodeTypeFnDef:
579630 case NodeTypeUse:
631 case NodeTypeLabel:
580632 zig_unreachable();
581633 }
582634 assert(return_type);
583635 check_type_compatibility(g, node, expected_type, return_type);
584636
585 assert(!node->codegen_node);
586 node->codegen_node = allocate<CodeGenNode>(1);
587 node->codegen_node->data.expr_node.type_entry = return_type;
637 if (node->codegen_node) {
638 assert(node->type == NodeTypeGoto);
639 } else {
640 assert(node->type != NodeTypeGoto);
641 node->codegen_node = allocate<CodeGenNode>(1);
642 }
643 node->codegen_node->expr_node.type_entry = return_type;
588644
589645 return return_type;
590646}
......@@ -652,6 +708,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
652708 case NodeTypeCastExpr:
653709 case NodeTypePrefixOpExpr:
654710 case NodeTypeIfExpr:
711 case NodeTypeLabel:
712 case NodeTypeGoto:
655713 zig_unreachable();
656714 }
657715}
src/codegen.cpp+35-4
......@@ -115,7 +115,7 @@ static LLVMValueRef get_variable_value(CodeGen *g, Buf *name) {
115115}
116116
117117static TypeTableEntry *get_expr_type(AstNode *node) {
118 return node->codegen_node->data.expr_node.type_entry;
118 return node->codegen_node->expr_node.type_entry;
119119}
120120
121121static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
......@@ -407,11 +407,13 @@ static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {
407407
408408 LLVMPositionBuilderAtEnd(g->builder, then_block);
409409 LLVMValueRef then_expr_result = gen_expr(g, node->data.if_expr.then_block);
410 LLVMBuildBr(g->builder, endif_block);
410 if (get_expr_type(node->data.if_expr.then_block) != g->builtin_types.entry_unreachable)
411 LLVMBuildBr(g->builder, endif_block);
411412
412413 LLVMPositionBuilderAtEnd(g->builder, else_block);
413414 LLVMValueRef else_expr_result = gen_expr(g, node->data.if_expr.else_node);
414 LLVMBuildBr(g->builder, endif_block);
415 if (get_expr_type(node->data.if_expr.else_node) != g->builtin_types.entry_unreachable)
416 LLVMBuildBr(g->builder, endif_block);
415417
416418 LLVMPositionBuilderAtEnd(g->builder, endif_block);
417419 if (use_expr_value) {
......@@ -435,7 +437,8 @@ static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {
435437
436438 LLVMPositionBuilderAtEnd(g->builder, then_block);
437439 gen_expr(g, node->data.if_expr.then_block);
438 LLVMBuildBr(g->builder, endif_block);
440 if (get_expr_type(node->data.if_expr.then_block) != g->builtin_types.entry_unreachable)
441 LLVMBuildBr(g->builder, endif_block);
439442
440443 LLVMPositionBuilderAtEnd(g->builder, endif_block);
441444 return nullptr;
......@@ -518,6 +521,17 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
518521 }
519522 case NodeTypeBlock:
520523 return gen_block(g, node, nullptr);
524 case NodeTypeGoto:
525 add_debug_source_node(g, node);
526 return LLVMBuildBr(g->builder, node->codegen_node->data.label_entry->basic_block);
527 case NodeTypeLabel:
528 {
529 LLVMBasicBlockRef basic_block = node->codegen_node->data.label_entry->basic_block;
530 add_debug_source_node(g, node);
531 LLVMValueRef result = LLVMBuildBr(g->builder, basic_block);
532 LLVMPositionBuilderAtEnd(g->builder, basic_block);
533 return result;
534 }
521535 case NodeTypeRoot:
522536 case NodeTypeRootExportDecl:
523537 case NodeTypeFnProto:
......@@ -533,6 +547,20 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
533547 zig_unreachable();
534548}
535549
550static void build_label_blocks(CodeGen *g, AstNode *block_node) {
551 assert(block_node->type == NodeTypeBlock);
552 for (int i = 0; i < block_node->data.block.statements.length; i += 1) {
553 AstNode *label_node = block_node->data.block.statements.at(i);
554 if (label_node->type != NodeTypeLabel)
555 continue;
556
557 Buf *name = &label_node->data.label.name;
558 label_node->codegen_node->data.label_entry->basic_block = LLVMAppendBasicBlock(
559 g->cur_fn->fn_value, buf_ptr(name));
560 }
561
562}
563
536564static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnProto *fn_proto,
537565 LLVMZigDIFile *di_file)
538566{
......@@ -623,10 +651,13 @@ static void do_code_gen(CodeGen *g) {
623651 codegen_fn_def->params = allocate<LLVMValueRef>(LLVMCountParams(fn));
624652 LLVMGetParams(fn, codegen_fn_def->params);
625653
654 build_label_blocks(g, fn_def_node->data.fn_def.body);
655
626656 TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type;
627657 gen_block(g, fn_def_node->data.fn_def.body, implicit_return_type);
628658
629659 g->block_scopes.pop();
660
630661 }
631662 assert(!g->errors.length);
632663
src/main.cpp+11-2
......@@ -9,6 +9,7 @@
99#include "buffer.hpp"
1010#include "codegen.hpp"
1111#include "os.hpp"
12#include "error.hpp"
1213
1314#include <stdio.h>
1415
......@@ -48,6 +49,8 @@ struct Build {
4849};
4950
5051static int build(const char *arg0, Build *b) {
52 int err;
53
5154 if (!b->in_file)
5255 return usage(arg0);
5356
......@@ -59,11 +62,17 @@ static int build(const char *arg0, Build *b) {
5962 Buf root_source_name = BUF_INIT;
6063 if (buf_eql_str(&in_file_buf, "-")) {
6164 os_get_cwd(&root_source_dir);
62 os_fetch_file(stdin, &root_source_code);
65 if ((err = os_fetch_file(stdin, &root_source_code))) {
66 fprintf(stderr, "unable to read stdin: %s\n", err_str(err));
67 return 1;
68 }
6369 buf_init_from_str(&root_source_name, "");
6470 } else {
6571 os_path_split(&in_file_buf, &root_source_dir, &root_source_name);
66 os_fetch_file_path(buf_create_from_str(b->in_file), &root_source_code);
72 if ((err = os_fetch_file_path(buf_create_from_str(b->in_file), &root_source_code))) {
73 fprintf(stderr, "unable to open '%s': %s\n", b->in_file, err_str(err));
74 return 1;
75 }
6776 }
6877
6978 CodeGen *g = codegen_create(&root_source_dir);
src/parser.cpp+62-7
......@@ -95,6 +95,10 @@ const char *node_type_str(NodeType node_type) {
9595 return "Void";
9696 case NodeTypeIfExpr:
9797 return "IfExpr";
98 case NodeTypeLabel:
99 return "Label";
100 case NodeTypeGoto:
101 return "Label";
98102 }
99103 zig_unreachable();
100104}
......@@ -260,6 +264,12 @@ void ast_print(AstNode *node, int indent) {
260264 if (node->data.if_expr.else_node)
261265 ast_print(node->data.if_expr.else_node, indent + 2);
262266 break;
267 case NodeTypeLabel:
268 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name));
269 break;
270 case NodeTypeGoto:
271 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.go_to.name));
272 break;
263273 }
264274}
265275
......@@ -581,7 +591,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool
581591}
582592
583593/*
584PrimaryExpression : token(Number) | token(String) | token(Unreachable) | GroupedExpression | token(Symbol)
594PrimaryExpression : token(Number) | token(String) | token(Unreachable) | GroupedExpression | token(Symbol) | Goto
585595*/
586596static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
587597 Token *token = &pc->tokens->at(*token_index);
......@@ -609,6 +619,16 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
609619 ast_buf_from_token(pc, token, &node->data.symbol);
610620 *token_index += 1;
611621 return node;
622 } else if (token->id == TokenIdKeywordGoto) {
623 AstNode *node = ast_create_node(pc, NodeTypeGoto, token);
624 *token_index += 1;
625
626 Token *dest_symbol = &pc->tokens->at(*token_index);
627 *token_index += 1;
628 ast_expect_token(pc, dest_symbol, TokenIdSymbol);
629
630 ast_buf_from_token(pc, dest_symbol, &node->data.go_to.name);
631 return node;
612632 }
613633
614634 AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);
......@@ -1181,7 +1201,36 @@ static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool ma
11811201}
11821202
11831203/*
1184Statement : NonBlockExpression token(Semicolon) | BlockExpression
1204Label: token(Symbol) token(Colon)
1205*/
1206static AstNode *ast_parse_label(ParseContext *pc, int *token_index, bool mandatory) {
1207 Token *symbol_token = &pc->tokens->at(*token_index);
1208 if (symbol_token->id != TokenIdSymbol) {
1209 if (mandatory) {
1210 ast_invalid_token_error(pc, symbol_token);
1211 } else {
1212 return nullptr;
1213 }
1214 }
1215
1216 Token *colon_token = &pc->tokens->at(*token_index + 1);
1217 if (colon_token->id != TokenIdColon) {
1218 if (mandatory) {
1219 ast_invalid_token_error(pc, colon_token);
1220 } else {
1221 return nullptr;
1222 }
1223 }
1224
1225 *token_index += 2;
1226
1227 AstNode *node = ast_create_node(pc, NodeTypeLabel, symbol_token);
1228 ast_buf_from_token(pc, symbol_token, &node->data.label.name);
1229 return node;
1230}
1231
1232/*
1233Statement : Label | NonBlockExpression token(Semicolon) | BlockExpression
11851234Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
11861235*/
11871236static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory) {
......@@ -1204,12 +1253,18 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
12041253 // {2;} -> {2;void}
12051254 // {;2} -> {void;2}
12061255 for (;;) {
1207 AstNode *statement_node = ast_parse_block_expr(pc, token_index, false);
1208 bool semicolon_expected = !statement_node;
1209 if (!statement_node) {
1210 statement_node = ast_parse_non_block_expr(pc, token_index, false);
1256 AstNode *statement_node = ast_parse_label(pc, token_index, false);
1257 bool semicolon_expected;
1258 if (statement_node) {
1259 semicolon_expected = false;
1260 } else {
1261 statement_node = ast_parse_block_expr(pc, token_index, false);
1262 semicolon_expected = !statement_node;
12111263 if (!statement_node) {
1212 statement_node = ast_create_node(pc, NodeTypeVoid, last_token);
1264 statement_node = ast_parse_non_block_expr(pc, token_index, false);
1265 if (!statement_node) {
1266 statement_node = ast_create_node(pc, NodeTypeVoid, last_token);
1267 }
12131268 }
12141269 }
12151270 node->data.block.statements.append(statement_node);
src/parser.hpp+12
......@@ -41,6 +41,8 @@ enum NodeType {
4141 NodeTypeUse,
4242 NodeTypeVoid,
4343 NodeTypeIfExpr,
44 NodeTypeLabel,
45 NodeTypeGoto,
4446};
4547
4648struct AstNodeRoot {
......@@ -182,6 +184,14 @@ struct AstNodeIfExpr {
182184 AstNode *else_node; // null, block node, or other if expr node
183185};
184186
187struct AstNodeLabel {
188 Buf name;
189};
190
191struct AstNodeGoto {
192 Buf name;
193};
194
185195struct AstNode {
186196 enum NodeType type;
187197 int line;
......@@ -207,6 +217,8 @@ struct AstNode {
207217 AstNodeFnCallExpr fn_call_expr;
208218 AstNodeUse use;
209219 AstNodeIfExpr if_expr;
220 AstNodeLabel label;
221 AstNodeGoto go_to;
210222 Buf number;
211223 Buf string;
212224 Buf symbol;
src/semantic_info.hpp+9-1
......@@ -43,6 +43,11 @@ struct SymbolTableEntry {
4343 int param_index; // only valid in the case of parameters
4444};
4545
46struct LabelTableEntry {
47 AstNode *label_node;
48 LLVMBasicBlockRef basic_block;
49};
50
4651struct FnTableEntry {
4752 LLVMValueRef fn_value;
4853 AstNode *proto_node;
......@@ -54,6 +59,7 @@ struct FnTableEntry {
5459
5560 // reminder: hash tables must be initialized before use
5661 HashMap<Buf *, SymbolTableEntry *, buf_hash, buf_eql_buf> symbol_table;
62 HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
5763};
5864
5965struct CodeGen {
......@@ -100,6 +106,7 @@ struct CodeGen {
100106
101107 OutType out_type;
102108 FnTableEntry *cur_fn;
109 LLVMBasicBlockRef cur_basic_block;
103110 bool c_stdint_used;
104111 AstNode *root_export_decl;
105112 int version_major;
......@@ -132,9 +139,10 @@ struct CodeGenNode {
132139 union {
133140 TypeNode type_node; // for NodeTypeType
134141 FnDefNode fn_def_node; // for NodeTypeFnDef
135 ExprNode expr_node; // for all the expression nodes
136142 FnProtoNode fn_proto_node; // for NodeTypeFnProto
143 LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel
137144 } data;
145 ExprNode expr_node; // for all the expression nodes
138146};
139147
140148static inline Buf *hack_get_fn_call_name(CodeGen *g, AstNode *node) {
src/tokenizer.cpp+3
......@@ -189,6 +189,8 @@ static void end_token(Tokenize *t) {
189189 t->cur_tok->id = TokenIdKeywordIf;
190190 } else if (mem_eql_str(token_mem, token_len, "else")) {
191191 t->cur_tok->id = TokenIdKeywordElse;
192 } else if (mem_eql_str(token_mem, token_len, "goto")) {
193 t->cur_tok->id = TokenIdKeywordGoto;
192194 }
193195
194196 t->cur_tok = nullptr;
......@@ -586,6 +588,7 @@ static const char * token_name(Token *token) {
586588 case TokenIdKeywordVoid: return "Void";
587589 case TokenIdKeywordIf: return "If";
588590 case TokenIdKeywordElse: return "Else";
591 case TokenIdKeywordGoto: return "Goto";
589592 case TokenIdLParen: return "LParen";
590593 case TokenIdRParen: return "RParen";
591594 case TokenIdComma: return "Comma";
src/tokenizer.hpp+1
......@@ -27,6 +27,7 @@ enum TokenId {
2727 TokenIdKeywordVoid,
2828 TokenIdKeywordIf,
2929 TokenIdKeywordElse,
30 TokenIdKeywordGoto,
3031 TokenIdLParen,
3132 TokenIdRParen,
3233 TokenIdComma,
src/zig_llvm.cpp+13
......@@ -255,6 +255,19 @@ void LLVMZigDIBuilderFinalize(LLVMZigDIBuilder *dibuilder) {
255255 reinterpret_cast<DIBuilder*>(dibuilder)->finalize();
256256}
257257
258LLVMZigInsertionPoint *LLVMZigSaveInsertPoint(LLVMBuilderRef builder_wrapped) {
259 IRBuilderBase::InsertPoint *ip = new IRBuilderBase::InsertPoint();
260 *ip = unwrap(builder_wrapped)->saveIP();
261 return reinterpret_cast<LLVMZigInsertionPoint*>(ip);
262}
263
264void LLVMZigRestoreInsertPoint(LLVMBuilderRef builder, LLVMZigInsertionPoint *ip_wrapped) {
265 IRBuilderBase::InsertPoint *ip = reinterpret_cast<IRBuilderBase::InsertPoint*>(ip_wrapped);
266 unwrap(builder)->restoreIP(*ip);
267}
268
269//------------------------------------
270
258271enum FloatAbi {
259272 FloatAbiHard,
260273 FloatAbiSoft,
src/zig_llvm.hpp+4
......@@ -22,6 +22,7 @@ struct LLVMZigDIFile;
2222struct LLVMZigDILexicalBlock;
2323struct LLVMZigDISubprogram;
2424struct LLVMZigDISubroutineType;
25struct LLVMZigInsertionPoint;
2526
2627void LLVMZigInitializeLoopStrengthReducePass(LLVMPassRegistryRef R);
2728void LLVMZigInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);
......@@ -75,6 +76,9 @@ LLVMZigDISubprogram *LLVMZigCreateFunction(LLVMZigDIBuilder *dibuilder, LLVMZigD
7576
7677void LLVMZigDIBuilderFinalize(LLVMZigDIBuilder *dibuilder);
7778
79LLVMZigInsertionPoint *LLVMZigSaveInsertPoint(LLVMBuilderRef builder);
80void LLVMZigRestoreInsertPoint(LLVMBuilderRef builder, LLVMZigInsertionPoint *point);
81
7882
7983/*
8084 * This stuff is not LLVM API but it depends on the LLVM C++ API so we put it here.
test/run_tests.cpp+35
......@@ -232,6 +232,30 @@ static void add_compiling_test_cases(void) {
232232 exit(0);
233233 }
234234 )SOURCE", "pass\n");
235
236 add_simple_case("goto", R"SOURCE(
237 #link("c")
238 extern {
239 fn puts(s: *const u8) -> i32;
240 fn exit(code: i32) -> unreachable;
241 }
242
243 fn loop(a : i32) {
244 if a == 0 {
245 goto done;
246 }
247 puts("loop");
248 loop(a - 1);
249
250 done:
251 return;
252 }
253
254 export fn _start() -> unreachable {
255 loop(3);
256 exit(0);
257 }
258 )SOURCE", "loop\nloop\nloop\n");
235259}
236260
237261static void add_compile_failure_test_cases(void) {
......@@ -305,6 +329,17 @@ fn a() {
305329 )SOURCE", 2,
306330 ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'",
307331 ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'");
332
333 add_compile_fail_case("goto cause unreachable code", R"SOURCE(
334fn a() {
335 goto done;
336 b();
337done:
338 return;
339}
340fn b() {}
341 )SOURCE", 1, ".tmp_source.zig:4:5: error: unreachable code");
342
308343}
309344
310345static void print_compiler_invokation(TestCase *test_case, Buf *zig_stderr) {