authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-12-01 10:44:30-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-12-01 10:44:30-07:00
logab327344b671bff7f874f24691d7e3f19176167c
treec437760bbc1f7059417b21e37c3d15a42534d4e8
parent9278dbedd5242bf4253da29c0fab36eea9dda61b
parentdfb6682089ad758b7ba72733778a9aa8c544c164

merge conflicts


25 files changed, 565 insertions(+), 290 deletions(-)

CMakeLists.txt+1
......@@ -31,6 +31,7 @@ set(ZIG_SOURCES
3131 "${CMAKE_SOURCE_DIR}/src/main.cpp"
3232 "${CMAKE_SOURCE_DIR}/src/os.cpp"
3333 "${CMAKE_SOURCE_DIR}/src/util.cpp"
34 "${CMAKE_SOURCE_DIR}/src/errmsg.cpp"
3435 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
3536)
3637
README.md-1
......@@ -43,7 +43,6 @@ make
4343## Roadmap
4444
4545 * variable declarations and assignment expressions
46 * Multiple files
4746 * Type checking
4847 * inline assembly and syscalls
4948 * running code at compile time
example/multiple_files/foo.zig+1-1
......@@ -6,6 +6,6 @@ fn private_function() {
66 puts("it works!");
77}
88
9fn print_text() {
9pub fn print_text() {
1010 private_function();
1111}
example/multiple_files/libc.zig+2-2
......@@ -1,5 +1,5 @@
11#link("c")
22extern {
3 fn puts(s: *mut u8) -> i32;
4 fn exit(code: i32) -> unreachable;
3 pub fn puts(s: *mut u8) -> i32;
4 pub fn exit(code: i32) -> unreachable;
55}
example/multiple_files/main.zig+2-2
......@@ -1,9 +1,9 @@
1export executable "test";
1export executable "test-multiple-files";
22
33use "libc.zig";
44use "foo.zig";
55
6fn _start() -> unreachable {
6export fn _start() -> unreachable {
77 private_function();
88}
99
src/analyze.cpp+129-145
......@@ -17,14 +17,18 @@ struct BlockContext {
1717 BlockContext *parent;
1818};
1919
20static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
21 g->errors.add_one();
22 ErrorMsg *last_msg = &g->errors.last();
23 last_msg->line_start = node->line;
24 last_msg->column_start = node->column;
25 last_msg->line_end = -1;
26 last_msg->column_end = -1;
27 last_msg->msg = msg;
20void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
21 ErrorMsg *err = allocate<ErrorMsg>(1);
22 err->line_start = node->line;
23 err->column_start = node->column;
24 err->line_end = -1;
25 err->column_end = -1;
26 err->msg = msg;
27 err->path = node->owner->path;
28 err->source = node->owner->source_code;
29 err->line_offsets = node->owner->line_offsets;
30
31 g->errors.append(err);
2832}
2933
3034static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) {
......@@ -139,6 +143,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
139143 AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
140144 assert(fn_decl->type == NodeTypeFnDecl);
141145 AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto;
146 bool is_pub = (fn_proto->data.fn_proto.visib_mod == FnProtoVisibModPub);
142147 resolve_function_proto(g, fn_proto);
143148 Buf *name = &fn_proto->data.fn_proto.name;
144149
......@@ -147,7 +152,12 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
147152 fn_table_entry->is_extern = true;
148153 fn_table_entry->calling_convention = LLVMCCallConv;
149154 fn_table_entry->import_entry = import;
150 g->fn_table.put(name, fn_table_entry);
155
156 g->fn_protos.append(fn_table_entry);
157 import->fn_table.put(name, fn_table_entry);
158 if (is_pub) {
159 g->fn_table.put(name, fn_table_entry);
160 }
151161 }
152162 break;
153163 case NodeTypeFnDef:
......@@ -155,67 +165,89 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
155165 AstNode *proto_node = node->data.fn_def.fn_proto;
156166 assert(proto_node->type == NodeTypeFnProto);
157167 Buf *proto_name = &proto_node->data.fn_proto.name;
158 auto entry = g->fn_table.maybe_get(proto_name);
168 auto entry = import->fn_table.maybe_get(proto_name);
169 bool skip = false;
170 bool is_internal = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport);
171 bool is_pub = (proto_node->data.fn_proto.visib_mod == FnProtoVisibModPub);
159172 if (entry) {
160173 add_node_error(g, node,
161174 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
162175 assert(!node->codegen_node);
163176 node->codegen_node = allocate<CodeGenNode>(1);
164177 node->codegen_node->data.fn_def_node.skip = true;
165 } else {
178 skip = true;
179 } else if (is_pub) {
180 auto entry = g->fn_table.maybe_get(proto_name);
181 if (entry) {
182 add_node_error(g, node,
183 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
184 assert(!node->codegen_node);
185 node->codegen_node = allocate<CodeGenNode>(1);
186 node->codegen_node->data.fn_def_node.skip = true;
187 skip = true;
188 }
189 }
190 if (!skip) {
166191 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
167192 fn_table_entry->import_entry = import;
168193 fn_table_entry->proto_node = proto_node;
169194 fn_table_entry->fn_def_node = node;
170 fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport;
171 if (fn_table_entry->internal_linkage) {
172 fn_table_entry->calling_convention = LLVMFastCallConv;
173 } else {
174 fn_table_entry->calling_convention = LLVMCCallConv;
175 }
176 g->fn_table.put(proto_name, fn_table_entry);
195 fn_table_entry->internal_linkage = is_internal;
196 fn_table_entry->calling_convention = is_internal ? LLVMFastCallConv : LLVMCCallConv;
197
198 g->fn_protos.append(fn_table_entry);
177199 g->fn_defs.append(fn_table_entry);
178200
201 import->fn_table.put(proto_name, fn_table_entry);
202 if (is_pub) {
203 g->fn_table.put(proto_name, fn_table_entry);
204 }
205
179206 resolve_function_proto(g, proto_node);
180207 }
181208 }
182209 break;
183210 case NodeTypeRootExportDecl:
184 for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) {
185 AstNode *directive_node = node->data.root_export_decl.directives->at(i);
186 Buf *name = &directive_node->data.directive.name;
187 Buf *param = &directive_node->data.directive.param;
188 if (buf_eql_str(name, "version")) {
189 set_root_export_version(g, param, directive_node);
190 } else {
191 add_node_error(g, directive_node,
192 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
211 if (import == g->root_import) {
212 for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) {
213 AstNode *directive_node = node->data.root_export_decl.directives->at(i);
214 Buf *name = &directive_node->data.directive.name;
215 Buf *param = &directive_node->data.directive.param;
216 if (buf_eql_str(name, "version")) {
217 set_root_export_version(g, param, directive_node);
218 } else {
219 add_node_error(g, directive_node,
220 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
221 }
193222 }
194 }
195223
196 if (g->root_export_decl) {
197 add_node_error(g, node,
198 buf_sprintf("only one root export declaration allowed"));
199 } else {
200 g->root_export_decl = node;
201
202 if (!g->root_out_name)
203 g->root_out_name = &node->data.root_export_decl.name;
204
205 Buf *out_type = &node->data.root_export_decl.type;
206 OutType export_out_type;
207 if (buf_eql_str(out_type, "executable")) {
208 export_out_type = OutTypeExe;
209 } else if (buf_eql_str(out_type, "library")) {
210 export_out_type = OutTypeLib;
211 } else if (buf_eql_str(out_type, "object")) {
212 export_out_type = OutTypeObj;
213 } else {
224 if (g->root_export_decl) {
214225 add_node_error(g, node,
215 buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
226 buf_sprintf("only one root export declaration allowed"));
227 } else {
228 g->root_export_decl = node;
229
230 if (!g->root_out_name)
231 g->root_out_name = &node->data.root_export_decl.name;
232
233 Buf *out_type = &node->data.root_export_decl.type;
234 OutType export_out_type;
235 if (buf_eql_str(out_type, "executable")) {
236 export_out_type = OutTypeExe;
237 } else if (buf_eql_str(out_type, "library")) {
238 export_out_type = OutTypeLib;
239 } else if (buf_eql_str(out_type, "object")) {
240 export_out_type = OutTypeObj;
241 } else {
242 add_node_error(g, node,
243 buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
244 }
245 if (g->out_type == OutTypeUnknown)
246 g->out_type = export_out_type;
216247 }
217 if (g->out_type == OutTypeUnknown)
218 g->out_type = export_out_type;
248 } else {
249 add_node_error(g, node,
250 buf_sprintf("root export declaration only valid in root source file"));
219251 }
220252 break;
221253 case NodeTypeUse:
......@@ -263,7 +295,7 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *
263295 add_node_error(g, node, buf_sprintf("type mismatch."));
264296}
265297
266static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) {
298static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) {
267299 switch (node->type) {
268300 case NodeTypeBlock:
269301 {
......@@ -276,7 +308,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
276308 buf_sprintf("unreachable code"));
277309 break;
278310 }
279 return_type = analyze_expression(g, context, nullptr, child);
311 return_type = analyze_expression(g, import, context, nullptr, child);
280312 }
281313 return return_type;
282314 }
......@@ -286,7 +318,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
286318 TypeTableEntry *expected_return_type = get_return_type(context);
287319 TypeTableEntry *actual_return_type;
288320 if (node->data.return_expr.expr) {
289 actual_return_type = analyze_expression(g, context, expected_return_type, node->data.return_expr.expr);
321 actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr);
290322 } else {
291323 actual_return_type = g->builtin_types.entry_void;
292324 }
......@@ -304,8 +336,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
304336 case NodeTypeBinOpExpr:
305337 {
306338 // TODO: think about expected types
307 analyze_expression(g, context, expected_type, node->data.bin_op_expr.op1);
308 analyze_expression(g, context, expected_type, node->data.bin_op_expr.op2);
339 analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op1);
340 analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op2);
309341 return expected_type;
310342 }
311343
......@@ -313,14 +345,17 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
313345 {
314346 Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);
315347
316 auto entry = g->fn_table.maybe_get(name);
348 auto entry = import->fn_table.maybe_get(name);
349 if (!entry)
350 entry = g->fn_table.maybe_get(name);
351
317352 if (!entry) {
318353 add_node_error(g, node,
319354 buf_sprintf("undefined function: '%s'", buf_ptr(name)));
320355 // still analyze the parameters, even though we don't know what to expect
321356 for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
322357 AstNode *child = node->data.fn_call_expr.params.at(i);
323 analyze_expression(g, context, nullptr, child);
358 analyze_expression(g, import, context, nullptr, child);
324359 }
325360
326361 return g->builtin_types.entry_invalid;
......@@ -350,7 +385,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
350385 if (param_type_node->codegen_node)
351386 expected_param_type = param_type_node->codegen_node->data.type_node.entry;
352387 }
353 analyze_expression(g, context, expected_param_type, child);
388 analyze_expression(g, import, context, expected_param_type, child);
354389 }
355390
356391 TypeTableEntry *return_type = fn_proto->return_type->codegen_node->data.type_node.entry;
......@@ -444,76 +479,7 @@ static void check_fn_def_control_flow(CodeGen *g, AstNode *node) {
444479 }
445480}
446481
447static void analyze_expression(CodeGen *g, AstNode *node) {
448 switch (node->type) {
449 case NodeTypeBlock:
450 for (int i = 0; i < node->data.block.statements.length; i += 1) {
451 AstNode *child = node->data.block.statements.at(i);
452 analyze_expression(g, child);
453 }
454 break;
455 case NodeTypeReturnExpr:
456 if (node->data.return_expr.expr) {
457 analyze_expression(g, node->data.return_expr.expr);
458 }
459 break;
460 case NodeTypeBinOpExpr:
461 analyze_expression(g, node->data.bin_op_expr.op1);
462 analyze_expression(g, node->data.bin_op_expr.op2);
463 break;
464 case NodeTypeFnCallExpr:
465 {
466 Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);
467
468 auto entry = g->fn_table.maybe_get(name);
469 if (!entry) {
470 add_node_error(g, node,
471 buf_sprintf("undefined function: '%s'", buf_ptr(name)));
472 } else {
473 FnTableEntry *fn_table_entry = entry->value;
474 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
475 int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length;
476 int actual_param_count = node->data.fn_call_expr.params.length;
477 if (expected_param_count != actual_param_count) {
478 add_node_error(g, node,
479 buf_sprintf("wrong number of arguments. Expected %d, got %d.",
480 expected_param_count, actual_param_count));
481 }
482 }
483
484 for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
485 AstNode *child = node->data.fn_call_expr.params.at(i);
486 analyze_expression(g, child);
487 }
488 break;
489 }
490 case NodeTypeCastExpr:
491 zig_panic("TODO");
492 break;
493 case NodeTypePrefixOpExpr:
494 zig_panic("TODO");
495 break;
496 case NodeTypeNumberLiteral:
497 case NodeTypeStringLiteral:
498 case NodeTypeUnreachable:
499 case NodeTypeSymbol:
500 // nothing to do
501 break;
502 case NodeTypeDirective:
503 case NodeTypeFnDecl:
504 case NodeTypeFnProto:
505 case NodeTypeParamDecl:
506 case NodeTypeType:
507 case NodeTypeRoot:
508 case NodeTypeRootExportDecl:
509 case NodeTypeExternBlock:
510 case NodeTypeFnDef:
511 case NodeTypeUse:
512 zig_unreachable();
513 }
514}
515
516static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
482static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, AstNode *node) {
517483 switch (node->type) {
518484 case NodeTypeFnDef:
519485 {
......@@ -540,7 +506,7 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
540506 context.root = &context;
541507 context.parent = nullptr;
542508 TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry;
543 analyze_expression(g, &context, expected_type, node->data.fn_def.body);
509 analyze_expression(g, import, &context, expected_type, node->data.fn_def.body);
544510 }
545511 break;
546512
......@@ -576,37 +542,55 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
576542 }
577543}
578544
579static void analyze_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
545static void find_function_declarations_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
580546 assert(node->type == NodeTypeRoot);
581547
582 // find function declarations
583548 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
584549 AstNode *child = node->data.root.top_level_decls.at(i);
585550 preview_function_declarations(g, import, child);
586551 }
587552
553}
554
555static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
556 assert(node->type == NodeTypeRoot);
557
588558 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
589559 AstNode *child = node->data.root.top_level_decls.at(i);
590 analyze_top_level_declaration(g, child);
560 analyze_top_level_declaration(g, import, child);
591561 }
562}
563
564void semantic_analyze(CodeGen *g) {
565 {
566 auto it = g->import_table.entry_iterator();
567 for (;;) {
568 auto *entry = it.next();
569 if (!entry)
570 break;
571
572 ImportTableEntry *import = entry->value;
573 find_function_declarations_root(g, import, import->root);
574 }
575 }
576 {
577 auto it = g->import_table.entry_iterator();
578 for (;;) {
579 auto *entry = it.next();
580 if (!entry)
581 break;
582
583 ImportTableEntry *import = entry->value;
584 analyze_top_level_decls_root(g, import, import->root);
585 }
586 }
587
592588
593589 if (!g->root_out_name) {
594 add_node_error(g, node,
590 add_node_error(g, g->root_import->root,
595591 buf_sprintf("missing export declaration and output name not provided"));
596592 } else if (g->out_type == OutTypeUnknown) {
597 add_node_error(g, node,
593 add_node_error(g, g->root_import->root,
598594 buf_sprintf("missing export declaration and export type not provided"));
599595 }
600596}
601
602void semantic_analyze(CodeGen *g) {
603 auto it = g->import_table.entry_iterator();
604 for (;;) {
605 auto *entry = it.next();
606 if (!entry)
607 break;
608
609 ImportTableEntry *import = entry->value;
610 analyze_root(g, import, import->root);
611 }
612}
src/analyze.hpp+3
......@@ -9,7 +9,10 @@
99#define ZIG_ANALYZE_HPP
1010
1111struct CodeGen;
12struct AstNode;
13struct Buf;
1214
1315void semantic_analyze(CodeGen *g);
16void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
1417
1518#endif
src/buffer.cpp+10-4
......@@ -3,9 +3,8 @@
33#include <stdlib.h>
44#include <stdio.h>
55
6Buf *buf_sprintf(const char *format, ...) {
7 va_list ap, ap2;
8 va_start(ap, format);
6Buf *buf_vprintf(const char *format, va_list ap) {
7 va_list ap2;
98 va_copy(ap2, ap);
109
1110 int len1 = vsnprintf(nullptr, 0, format, ap);
......@@ -19,11 +18,18 @@ Buf *buf_sprintf(const char *format, ...) {
1918 assert(len2 == len1);
2019
2120 va_end(ap2);
22 va_end(ap);
2321
2422 return buf;
2523}
2624
25Buf *buf_sprintf(const char *format, ...) {
26 va_list ap;
27 va_start(ap, format);
28 Buf *result = buf_vprintf(format, ap);
29 va_end(ap);
30 return result;
31}
32
2733void buf_appendf(Buf *buf, const char *format, ...) {
2834 assert(buf->list.length);
2935 va_list ap, ap2;
src/buffer.hpp+2
......@@ -13,6 +13,7 @@
1313#include <assert.h>
1414#include <stdint.h>
1515#include <ctype.h>
16#include <stdarg.h>
1617
1718#define BUF_INIT {{0}}
1819
......@@ -24,6 +25,7 @@ struct Buf {
2425
2526Buf *buf_sprintf(const char *format, ...)
2627 __attribute__ ((format (printf, 1, 2)));
28Buf *buf_vprintf(const char *format, va_list ap);
2729
2830static inline int buf_len(Buf *buf) {
2931 assert(buf->list.length);
src/codegen.cpp+51-22
......@@ -13,6 +13,7 @@
1313#include "error.hpp"
1414#include "semantic_info.hpp"
1515#include "analyze.hpp"
16#include "errmsg.hpp"
1617
1718#include <stdio.h>
1819#include <errno.h>
......@@ -41,6 +42,10 @@ void codegen_set_verbose(CodeGen *g, bool verbose) {
4142 g->verbose = verbose;
4243}
4344
45void codegen_set_errmsg_color(CodeGen *g, ErrColor err_color) {
46 g->err_color = err_color;
47}
48
4449void codegen_set_strip(CodeGen *g, bool strip) {
4550 g->strip_debug_symbols = strip;
4651}
......@@ -120,7 +125,13 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
120125
121126 Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);
122127
123 FnTableEntry *fn_table_entry = g->fn_table.get(name);
128 FnTableEntry *fn_table_entry;
129 auto entry = g->cur_fn->import_entry->fn_table.maybe_get(name);
130 if (entry)
131 fn_table_entry = entry->value;
132 else
133 fn_table_entry = g->fn_table.get(name);
134
124135 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
125136 int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length;
126137 int actual_param_count = node->data.fn_call_expr.params.length;
......@@ -473,13 +484,8 @@ static void do_code_gen(CodeGen *g) {
473484
474485
475486 // Generate function prototypes
476 auto it = g->fn_table.entry_iterator();
477 for (;;) {
478 auto *entry = it.next();
479 if (!entry)
480 break;
481
482 FnTableEntry *fn_table_entry = entry->value;
487 for (int i = 0; i < g->fn_protos.length; i += 1) {
488 FnTableEntry *fn_table_entry = g->fn_protos.at(i);
483489
484490 AstNode *proto_node = fn_table_entry->proto_node;
485491 assert(proto_node->type == NodeTypeFnProto);
......@@ -542,6 +548,7 @@ static void do_code_gen(CodeGen *g) {
542548 assert(codegen_node);
543549
544550 FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node;
551 assert(codegen_fn_def);
545552 codegen_fn_def->params = allocate<LLVMValueRef>(LLVMCountParams(fn));
546553 LLVMGetParams(fn, codegen_fn_def->params);
547554
......@@ -664,7 +671,8 @@ static void init(CodeGen *g, Buf *source_path) {
664671
665672}
666673
667static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
674static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
675 int err;
668676 Buf full_path = BUF_INIT;
669677 os_path_join(g->root_source_dir, source_path, &full_path);
670678
......@@ -681,24 +689,42 @@ static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
681689 fprintf(stderr, "---------\n");
682690 }
683691
684 ZigList<Token> *tokens = tokenize(source_code);
692 Tokenization tokenization = {0};
693 tokenize(source_code, &tokenization);
694
695 if (tokenization.err) {
696 ErrorMsg *err = allocate<ErrorMsg>(1);
697 err->line_start = tokenization.err_line;
698 err->column_start = tokenization.err_column;
699 err->line_end = -1;
700 err->column_end = -1;
701 err->msg = tokenization.err;
702 err->path = source_path;
703 err->source = source_code;
704 err->line_offsets = tokenization.line_offsets;
705
706 print_err_msg(err, g->err_color);
707 exit(1);
708 }
685709
686710 if (g->verbose) {
687 print_tokens(source_code, tokens);
711 print_tokens(source_code, tokenization.tokens);
688712
689713 fprintf(stderr, "\nAST:\n");
690714 fprintf(stderr, "------\n");
691715 }
692716
693717 ImportTableEntry *import_entry = allocate<ImportTableEntry>(1);
718 import_entry->source_code = source_code;
719 import_entry->line_offsets = tokenization.line_offsets;
720 import_entry->path = source_path;
694721 import_entry->fn_table.init(32);
695 import_entry->root = ast_parse(source_code, tokens);
722 import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color);
696723 assert(import_entry->root);
697724 if (g->verbose) {
698725 ast_print(import_entry->root, 0);
699726 }
700727
701 import_entry->path = source_path;
702728 import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&basename), buf_ptr(&dirname));
703729 g->import_table.put(source_path, import_entry);
704730
......@@ -713,18 +739,23 @@ static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
713739 if (!entry) {
714740 Buf full_path = BUF_INIT;
715741 os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path);
716 Buf import_code = BUF_INIT;
717 os_fetch_file_path(&full_path, &import_code);
718 codegen_add_code(g, &top_level_decl->data.use.path, &import_code);
742 Buf *import_code = buf_alloc();
743 if ((err = os_fetch_file_path(&full_path, import_code))) {
744 add_node_error(g, top_level_decl,
745 buf_sprintf("unable to open \"%s\": %s", buf_ptr(&full_path), err_str(err)));
746 break;
747 }
748 codegen_add_code(g, &top_level_decl->data.use.path, import_code);
719749 }
720750 }
751
752 return import_entry;
721753}
722754
723755void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) {
724756 init(g, source_path);
725757
726 codegen_add_code(g, source_path, source_code);
727
758 g->root_import = codegen_add_code(g, source_path, source_code);
728759
729760 if (g->verbose) {
730761 fprintf(stderr, "\nSemantic Analysis:\n");
......@@ -738,10 +769,8 @@ void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) {
738769 }
739770 } else {
740771 for (int i = 0; i < g->errors.length; i += 1) {
741 ErrorMsg *err = &g->errors.at(i);
742 fprintf(stderr, "Error: Line %d, column %d: %s\n",
743 err->line_start + 1, err->column_start + 1,
744 buf_ptr(err->msg));
772 ErrorMsg *err = g->errors.at(i);
773 print_err_msg(err, g->err_color);
745774 }
746775 exit(1);
747776 }
src/codegen.hpp+2-10
......@@ -9,6 +9,7 @@
99#define ZIG_CODEGEN_HPP
1010
1111#include "parser.hpp"
12#include "errmsg.hpp"
1213
1314struct CodeGen;
1415
......@@ -19,16 +20,6 @@ enum OutType {
1920 OutTypeObj,
2021};
2122
22
23struct ErrorMsg {
24 int line_start;
25 int column_start;
26 int line_end;
27 int column_end;
28 Buf *msg;
29};
30
31
3223CodeGen *codegen_create(Buf *root_source_dir);
3324
3425enum CodeGenBuildType {
......@@ -39,6 +30,7 @@ void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type);
3930void codegen_set_is_static(CodeGen *codegen, bool is_static);
4031void codegen_set_strip(CodeGen *codegen, bool strip);
4132void codegen_set_verbose(CodeGen *codegen, bool verbose);
33void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color);
4234void codegen_set_out_type(CodeGen *codegen, OutType out_type);
4335void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
4436
src/errmsg.cpp created+38
......@@ -0,0 +1,38 @@
1#include "errmsg.hpp"
2#include "os.hpp"
3
4#include <stdio.h>
5
6#define RED "\x1b[31;1m"
7#define WHITE "\x1b[37;1m"
8#define GREEN "\x1b[32;1m"
9#define RESET "\x1b[0m"
10
11void print_err_msg(ErrorMsg *err, ErrColor color) {
12 if (color == ErrColorOn || (color == ErrColorAuto && os_stderr_tty())) {
13 fprintf(stderr, WHITE "%s:%d:%d: " RED "error:" WHITE " %s" RESET "\n",
14 buf_ptr(err->path),
15 err->line_start + 1, err->column_start + 1,
16 buf_ptr(err->msg));
17
18 assert(err->source);
19 assert(err->line_offsets);
20
21 int line_start_offset = err->line_offsets->at(err->line_start);
22 int line_end_offset = err->line_offsets->at(err->line_start + 1);
23
24 fwrite(buf_ptr(err->source) + line_start_offset, 1, line_end_offset - line_start_offset - 1, stderr);
25 fprintf(stderr, "\n");
26 for (int i = 0; i < err->column_start; i += 1) {
27 fprintf(stderr, " ");
28 }
29 fprintf(stderr, GREEN "^" RESET "\n");
30
31 } else {
32 fprintf(stderr, "%s:%d:%d: error: %s\n",
33 buf_ptr(err->path),
34 err->line_start + 1, err->column_start + 1,
35 buf_ptr(err->msg));
36 }
37}
38
src/errmsg.hpp created+33
......@@ -0,0 +1,33 @@
1/*
2 * Copyright (c) 2015 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_ERRMSG_HPP
9#define ZIG_ERRMSG_HPP
10
11#include "buffer.hpp"
12#include "list.hpp"
13
14enum ErrColor {
15 ErrColorAuto,
16 ErrColorOff,
17 ErrColorOn,
18};
19
20struct ErrorMsg {
21 int line_start;
22 int column_start;
23 int line_end;
24 int column_end;
25 Buf *msg;
26 Buf *path;
27 Buf *source;
28 ZigList<int> *line_offsets;
29};
30
31void print_err_msg(ErrorMsg *msg, ErrColor color);
32
33#endif
src/error.cpp+6
......@@ -6,6 +6,12 @@ const char *err_str(int err) {
66 case ErrorNoMem: return "out of memory";
77 case ErrorInvalidFormat: return "invalid format";
88 case ErrorSemanticAnalyzeFail: return "semantic analyze failed";
9 case ErrorAccess: return "access denied";
10 case ErrorInterrupted: return "interrupted";
11 case ErrorSystemResources: return "lack of system resources";
12 case ErrorFileNotFound: return "file not found";
13 case ErrorFileSystem: return "file system error";
14 case ErrorFileTooBig: return "file too big";
915 }
1016 return "(invalid error)";
1117}
src/error.hpp+6
......@@ -13,6 +13,12 @@ enum Error {
1313 ErrorNoMem,
1414 ErrorInvalidFormat,
1515 ErrorSemanticAnalyzeFail,
16 ErrorAccess,
17 ErrorInterrupted,
18 ErrorSystemResources,
19 ErrorFileNotFound,
20 ErrorFileSystem,
21 ErrorFileTooBig,
1622};
1723
1824const char *err_str(int err);
src/main.cpp+16-1
......@@ -25,6 +25,7 @@ static int usage(const char *arg0) {
2525 " --name [name] override output name\n"
2626 " --output [file] override destination path\n"
2727 " --verbose turn on compiler debug output\n"
28 " --color [auto|off|on] enable or disable colored error messages\n"
2829 , arg0);
2930 return EXIT_FAILURE;
3031}
......@@ -43,6 +44,7 @@ struct Build {
4344 OutType out_type;
4445 const char *out_name;
4546 bool verbose;
47 ErrColor color;
4648};
4749
4850static int build(const char *arg0, Build *b) {
......@@ -73,6 +75,7 @@ static int build(const char *arg0, Build *b) {
7375 if (b->out_name)
7476 codegen_set_out_name(g, buf_create_from_str(b->out_name));
7577 codegen_set_verbose(g, b->verbose);
78 codegen_set_errmsg_color(g, b->color);
7679 codegen_add_root_code(g, &root_source_name, &root_source_code);
7780 codegen_link(g, b->out_file);
7881
......@@ -106,7 +109,9 @@ int main(int argc, char **argv) {
106109 return usage(arg0);
107110 } else {
108111 i += 1;
109 if (strcmp(arg, "--output") == 0) {
112 if (i >= argc) {
113 return usage(arg0);
114 } else if (strcmp(arg, "--output") == 0) {
110115 b.out_file = argv[i];
111116 } else if (strcmp(arg, "--export") == 0) {
112117 if (strcmp(argv[i], "exe") == 0) {
......@@ -118,6 +123,16 @@ int main(int argc, char **argv) {
118123 } else {
119124 return usage(arg0);
120125 }
126 } else if (strcmp(arg, "--color") == 0) {
127 if (strcmp(argv[i], "auto") == 0) {
128 b.color = ErrColorAuto;
129 } else if (strcmp(argv[i], "on") == 0) {
130 b.color = ErrColorOn;
131 } else if (strcmp(argv[i], "off") == 0) {
132 b.color = ErrColorOff;
133 } else {
134 return usage(arg0);
135 }
121136 } else if (strcmp(arg, "--name") == 0) {
122137 b.out_name = argv[i];
123138 } else {
src/os.cpp+52-8
......@@ -7,6 +7,7 @@
77
88#include "os.hpp"
99#include "util.hpp"
10#include "error.hpp"
1011
1112#include <unistd.h>
1213#include <errno.h>
......@@ -143,26 +144,65 @@ void os_write_file(Buf *full_path, Buf *contents) {
143144int os_fetch_file(FILE *f, Buf *out_contents) {
144145 int fd = fileno(f);
145146 struct stat st;
146 if (fstat(fd, &st))
147 zig_panic("unable to stat file: %s", strerror(errno));
147 if (fstat(fd, &st)) {
148 switch (errno) {
149 case EACCES:
150 return ErrorAccess;
151 case ENOENT:
152 return ErrorFileNotFound;
153 case ENOMEM:
154 return ErrorSystemResources;
155 case EINTR:
156 return ErrorInterrupted;
157 case EINVAL:
158 zig_unreachable();
159 default:
160 return ErrorFileSystem;
161 }
162 }
148163 off_t big_size = st.st_size;
149 if (big_size > INT_MAX)
150 zig_panic("file too big");
164 if (big_size > INT_MAX) {
165 return ErrorFileTooBig;
166 }
151167 int size = (int)big_size;
152168
153169 buf_resize(out_contents, size);
154170 ssize_t ret = read(fd, buf_ptr(out_contents), size);
155171
156 if (ret != size)
157 zig_panic("unable to read file: %s", strerror(errno));
172 if (ret != size) {
173 switch (errno) {
174 case EINTR:
175 return ErrorInterrupted;
176 case EINVAL:
177 case EISDIR:
178 zig_unreachable();
179 default:
180 return ErrorFileSystem;
181 }
182 }
158183
159184 return 0;
160185}
161186
162187int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
163188 FILE *f = fopen(buf_ptr(full_path), "rb");
164 if (!f)
165 zig_panic("unable to open %s: %s\n", buf_ptr(full_path), strerror(errno));
189 if (!f) {
190 switch (errno) {
191 case EACCES:
192 return ErrorAccess;
193 case EINTR:
194 return ErrorInterrupted;
195 case EINVAL:
196 zig_unreachable();
197 case ENFILE:
198 case ENOMEM:
199 return ErrorSystemResources;
200 case ENOENT:
201 return ErrorFileNotFound;
202 default:
203 return ErrorFileSystem;
204 }
205 }
166206 int result = os_fetch_file(f, out_contents);
167207 fclose(f);
168208 return result;
......@@ -180,3 +220,7 @@ int os_get_cwd(Buf *out_cwd) {
180220
181221 return 0;
182222}
223
224bool os_stderr_tty(void) {
225 return isatty(STDERR_FILENO);
226}
src/os.hpp+2
......@@ -29,4 +29,6 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents);
2929int os_get_cwd(Buf *out_cwd);
3030
3131
32bool os_stderr_tty(void);
33
3234#endif
src/parser.cpp+67-53
......@@ -6,6 +6,8 @@
66 */
77
88#include "parser.hpp"
9#include "errmsg.hpp"
10#include "semantic_info.hpp"
911
1012#include <stdarg.h>
1113#include <stdio.h>
......@@ -45,21 +47,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
4547 zig_unreachable();
4648}
4749
48__attribute__ ((format (printf, 2, 3)))
49__attribute__ ((noreturn))
50static void ast_error(Token *token, const char *format, ...) {
51 int line = token->start_line + 1;
52 int column = token->start_column + 1;
53
54 va_list ap;
55 va_start(ap, format);
56 fprintf(stderr, "Error: Line %d, column %d: ", line, column);
57 vfprintf(stderr, format, ap);
58 fprintf(stderr, "\n");
59 va_end(ap);
60 exit(EXIT_FAILURE);
61}
62
6350const char *node_type_str(NodeType node_type) {
6451 switch (node_type) {
6552 case NodeTypeRoot:
......@@ -254,11 +241,36 @@ struct ParseContext {
254241 AstNode *root;
255242 ZigList<Token> *tokens;
256243 ZigList<AstNode *> *directive_list;
244 ImportTableEntry *owner;
245 ErrColor err_color;
257246};
258247
259static AstNode *ast_create_node_no_line_info(NodeType type) {
248__attribute__ ((format (printf, 3, 4)))
249__attribute__ ((noreturn))
250static void ast_error(ParseContext *pc, Token *token, const char *format, ...) {
251 ErrorMsg *err = allocate<ErrorMsg>(1);
252 err->line_start = token->start_line;
253 err->column_start = token->start_column;
254 err->line_end = -1;
255 err->column_end = -1;
256
257 va_list ap;
258 va_start(ap, format);
259 err->msg = buf_vprintf(format, ap);
260 va_end(ap);
261
262 err->path = pc->owner->path;
263 err->source = pc->owner->source_code;
264 err->line_offsets = pc->owner->line_offsets;
265
266 print_err_msg(err, pc->err_color);
267 exit(EXIT_FAILURE);
268}
269
270static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) {
260271 AstNode *node = allocate<AstNode>(1);
261272 node->type = type;
273 node->owner = pc->owner;
262274 return node;
263275}
264276
......@@ -267,21 +279,21 @@ static void ast_update_node_line_info(AstNode *node, Token *first_token) {
267279 node->column = first_token->start_column;
268280}
269281
270static AstNode *ast_create_node(NodeType type, Token *first_token) {
271 AstNode *node = ast_create_node_no_line_info(type);
282static AstNode *ast_create_node(ParseContext *pc, NodeType type, Token *first_token) {
283 AstNode *node = ast_create_node_no_line_info(pc, type);
272284 ast_update_node_line_info(node, first_token);
273285 return node;
274286}
275287
276static AstNode *ast_create_node_with_node(NodeType type, AstNode *other_node) {
277 AstNode *node = ast_create_node_no_line_info(type);
288static AstNode *ast_create_node_with_node(ParseContext *pc, NodeType type, AstNode *other_node) {
289 AstNode *node = ast_create_node_no_line_info(pc, type);
278290 node->line = other_node->line;
279291 node->column = other_node->column;
280292 return node;
281293}
282294
283295static AstNode *ast_create_void_type_node(ParseContext *pc, Token *token) {
284 AstNode *node = ast_create_node(NodeTypeType, token);
296 AstNode *node = ast_create_node(pc, NodeTypeType, token);
285297 node->data.type.type = AstNodeTypeTypePrimitive;
286298 buf_init_from_str(&node->data.type.primitive_name, "void");
287299 return node;
......@@ -331,7 +343,7 @@ __attribute__ ((noreturn))
331343static void ast_invalid_token_error(ParseContext *pc, Token *token) {
332344 Buf token_value = BUF_INIT;
333345 ast_buf_from_token(pc, token, &token_value);
334 ast_error(token, "invalid token: '%s'", buf_ptr(&token_value));
346 ast_error(pc, token, "invalid token: '%s'", buf_ptr(&token_value));
335347}
336348
337349static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool mandatory);
......@@ -349,7 +361,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_
349361 token_index += 1;
350362 ast_expect_token(pc, number_sign, TokenIdNumberSign);
351363
352 AstNode *node = ast_create_node(NodeTypeDirective, number_sign);
364 AstNode *node = ast_create_node(pc, NodeTypeDirective, number_sign);
353365
354366 Token *name_symbol = &pc->tokens->at(token_index);
355367 token_index += 1;
......@@ -399,7 +411,7 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token
399411 Token *token = &pc->tokens->at(token_index);
400412 token_index += 1;
401413
402 AstNode *node = ast_create_node(NodeTypeType, token);
414 AstNode *node = ast_create_node(pc, NodeTypeType, token);
403415
404416 if (token->id == TokenIdKeywordUnreachable) {
405417 node->data.type.type = AstNodeTypeTypePrimitive;
......@@ -437,7 +449,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new
437449 token_index += 1;
438450 ast_expect_token(pc, param_name, TokenIdSymbol);
439451
440 AstNode *node = ast_create_node(NodeTypeParamDecl, param_name);
452 AstNode *node = ast_create_node(pc, NodeTypeParamDecl, param_name);
441453
442454
443455 ast_buf_from_token(pc, param_name, &node->data.param_decl.name);
......@@ -544,21 +556,21 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
544556 Token *token = &pc->tokens->at(*token_index);
545557
546558 if (token->id == TokenIdNumberLiteral) {
547 AstNode *node = ast_create_node(NodeTypeNumberLiteral, token);
559 AstNode *node = ast_create_node(pc, NodeTypeNumberLiteral, token);
548560 ast_buf_from_token(pc, token, &node->data.number);
549561 *token_index += 1;
550562 return node;
551563 } else if (token->id == TokenIdStringLiteral) {
552 AstNode *node = ast_create_node(NodeTypeStringLiteral, token);
564 AstNode *node = ast_create_node(pc, NodeTypeStringLiteral, token);
553565 parse_string_literal(pc, token, &node->data.string);
554566 *token_index += 1;
555567 return node;
556568 } else if (token->id == TokenIdKeywordUnreachable) {
557 AstNode *node = ast_create_node(NodeTypeUnreachable, token);
569 AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token);
558570 *token_index += 1;
559571 return node;
560572 } else if (token->id == TokenIdSymbol) {
561 AstNode *node = ast_create_node(NodeTypeSymbol, token);
573 AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
562574 ast_buf_from_token(pc, token, &node->data.symbol);
563575 *token_index += 1;
564576 return node;
......@@ -592,7 +604,7 @@ static AstNode *ast_parse_fn_call_expr(ParseContext *pc, int *token_index, bool
592604 if (l_paren->id != TokenIdLParen)
593605 return primary_expr;
594606
595 AstNode *node = ast_create_node_with_node(NodeTypeFnCallExpr, primary_expr);
607 AstNode *node = ast_create_node_with_node(pc, NodeTypeFnCallExpr, primary_expr);
596608 node->data.fn_call_expr.fn_ref_expr = primary_expr;
597609 ast_parse_fn_call_param_list(pc, *token_index, token_index, &node->data.fn_call_expr.params);
598610
......@@ -635,7 +647,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo
635647 return ast_parse_fn_call_expr(pc, token_index, mandatory);
636648
637649 AstNode *primary_expr = ast_parse_fn_call_expr(pc, token_index, true);
638 AstNode *node = ast_create_node(NodeTypePrefixOpExpr, token);
650 AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
639651 node->data.prefix_op_expr.primary_expr = primary_expr;
640652 node->data.prefix_op_expr.prefix_op = prefix_op;
641653
......@@ -656,7 +668,7 @@ static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bo
656668 return prefix_op_expr;
657669 *token_index += 1;
658670
659 AstNode *node = ast_create_node(NodeTypeCastExpr, as_kw);
671 AstNode *node = ast_create_node(pc, NodeTypeCastExpr, as_kw);
660672 node->data.cast_expr.prefix_op_expr = prefix_op_expr;
661673
662674 node->data.cast_expr.type = ast_parse_type(pc, *token_index, token_index);
......@@ -705,7 +717,7 @@ static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool man
705717
706718 AstNode *operand_2 = ast_parse_cast_expression(pc, token_index, true);
707719
708 AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
720 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
709721 node->data.bin_op_expr.op1 = operand_1;
710722 node->data.bin_op_expr.bin_op = mult_op;
711723 node->data.bin_op_expr.op2 = operand_2;
......@@ -753,7 +765,7 @@ static AstNode *ast_parse_add_expr(ParseContext *pc, int *token_index, bool mand
753765
754766 AstNode *operand_2 = ast_parse_mult_expr(pc, token_index, true);
755767
756 AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
768 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
757769 node->data.bin_op_expr.op1 = operand_1;
758770 node->data.bin_op_expr.bin_op = add_op;
759771 node->data.bin_op_expr.op2 = operand_2;
......@@ -801,7 +813,7 @@ static AstNode *ast_parse_bit_shift_expr(ParseContext *pc, int *token_index, boo
801813
802814 AstNode *operand_2 = ast_parse_add_expr(pc, token_index, true);
803815
804 AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
816 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
805817 node->data.bin_op_expr.op1 = operand_1;
806818 node->data.bin_op_expr.bin_op = bit_shift_op;
807819 node->data.bin_op_expr.op2 = operand_2;
......@@ -825,7 +837,7 @@ static AstNode *ast_parse_bin_and_expr(ParseContext *pc, int *token_index, bool
825837
826838 AstNode *operand_2 = ast_parse_bit_shift_expr(pc, token_index, true);
827839
828 AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
840 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
829841 node->data.bin_op_expr.op1 = operand_1;
830842 node->data.bin_op_expr.bin_op = BinOpTypeBinAnd;
831843 node->data.bin_op_expr.op2 = operand_2;
......@@ -848,7 +860,7 @@ static AstNode *ast_parse_bin_xor_expr(ParseContext *pc, int *token_index, bool
848860
849861 AstNode *operand_2 = ast_parse_bin_and_expr(pc, token_index, true);
850862
851 AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
863 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
852864 node->data.bin_op_expr.op1 = operand_1;
853865 node->data.bin_op_expr.bin_op = BinOpTypeBinXor;
854866 node->data.bin_op_expr.op2 = operand_2;
......@@ -871,7 +883,7 @@ static AstNode *ast_parse_bin_or_expr(ParseContext *pc, int *token_index, bool m
871883
872884 AstNode *operand_2 = ast_parse_bin_xor_expr(pc, token_index, true);
873885
874 AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
886 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
875887 node->data.bin_op_expr.op1 = operand_1;
876888 node->data.bin_op_expr.bin_op = BinOpTypeBinOr;
877889 node->data.bin_op_expr.op2 = operand_2;
......@@ -920,7 +932,7 @@ static AstNode *ast_parse_comparison_expr(ParseContext *pc, int *token_index, bo
920932
921933 AstNode *operand_2 = ast_parse_bin_or_expr(pc, token_index, true);
922934
923 AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
935 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
924936 node->data.bin_op_expr.op1 = operand_1;
925937 node->data.bin_op_expr.bin_op = cmp_op;
926938 node->data.bin_op_expr.op2 = operand_2;
......@@ -943,7 +955,7 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc, int *token_index, bool
943955
944956 AstNode *operand_2 = ast_parse_comparison_expr(pc, token_index, true);
945957
946 AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
958 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
947959 node->data.bin_op_expr.op1 = operand_1;
948960 node->data.bin_op_expr.bin_op = BinOpTypeBoolAnd;
949961 node->data.bin_op_expr.op2 = operand_2;
......@@ -958,7 +970,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
958970 Token *return_tok = &pc->tokens->at(*token_index);
959971 if (return_tok->id == TokenIdKeywordReturn) {
960972 *token_index += 1;
961 AstNode *node = ast_create_node(NodeTypeReturnExpr, return_tok);
973 AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, return_tok);
962974 node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);
963975 return node;
964976 } else if (mandatory) {
......@@ -983,7 +995,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool
983995
984996 AstNode *operand_2 = ast_parse_bool_and_expr(pc, token_index, true);
985997
986 AstNode *node = ast_create_node(NodeTypeBinOpExpr, token);
998 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
987999 node->data.bin_op_expr.op1 = operand_1;
9881000 node->data.bin_op_expr.bin_op = BinOpTypeBoolOr;
9891001 node->data.bin_op_expr.op2 = operand_2;
......@@ -1046,7 +1058,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
10461058 }
10471059 *token_index += 1;
10481060
1049 AstNode *node = ast_create_node(NodeTypeBlock, l_brace);
1061 AstNode *node = ast_create_node(pc, NodeTypeBlock, l_brace);
10501062
10511063 for (;;) {
10521064 Token *token = &pc->tokens->at(*token_index);
......@@ -1092,7 +1104,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
10921104 return nullptr;
10931105 }
10941106
1095 AstNode *node = ast_create_node(NodeTypeFnProto, token);
1107 AstNode *node = ast_create_node(pc, NodeTypeFnProto, token);
10961108 node->data.fn_proto.visib_mod = visib_mod;
10971109 node->data.fn_proto.directives = pc->directive_list;
10981110 pc->directive_list = nullptr;
......@@ -1125,7 +1137,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandat
11251137 AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory);
11261138 if (!fn_proto)
11271139 return nullptr;
1128 AstNode *node = ast_create_node_with_node(NodeTypeFnDef, fn_proto);
1140 AstNode *node = ast_create_node_with_node(pc, NodeTypeFnDef, fn_proto);
11291141
11301142 node->data.fn_def.fn_proto = fn_proto;
11311143 node->data.fn_def.body = ast_parse_block(pc, token_index, true);
......@@ -1138,7 +1150,7 @@ FnDecl : FnProto token(Semicolon)
11381150*/
11391151static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) {
11401152 AstNode *fn_proto = ast_parse_fn_proto(pc, &token_index, true);
1141 AstNode *node = ast_create_node_with_node(NodeTypeFnDecl, fn_proto);
1153 AstNode *node = ast_create_node_with_node(pc, NodeTypeFnDecl, fn_proto);
11421154
11431155 node->data.fn_decl.fn_proto = fn_proto;
11441156
......@@ -1166,7 +1178,7 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool
11661178 }
11671179 *token_index += 1;
11681180
1169 AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw);
1181 AstNode *node = ast_create_node(pc, NodeTypeExternBlock, extern_kw);
11701182
11711183 node->data.extern_block.directives = pc->directive_list;
11721184 pc->directive_list = nullptr;
......@@ -1184,7 +1196,7 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool
11841196 Token *token = &pc->tokens->at(*token_index);
11851197 if (token->id == TokenIdRBrace) {
11861198 if (pc->directive_list->length > 0) {
1187 ast_error(directive_token, "invalid directive");
1199 ast_error(pc, directive_token, "invalid directive");
11881200 }
11891201 pc->directive_list = nullptr;
11901202
......@@ -1216,7 +1228,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
12161228
12171229 *token_index += 2;
12181230
1219 AstNode *node = ast_create_node(NodeTypeRootExportDecl, export_kw);
1231 AstNode *node = ast_create_node(pc, NodeTypeRootExportDecl, export_kw);
12201232 node->data.root_export_decl.directives = pc->directive_list;
12211233 pc->directive_list = nullptr;
12221234
......@@ -1254,7 +1266,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory
12541266 *token_index += 1;
12551267 ast_expect_token(pc, semicolon, TokenIdSemicolon);
12561268
1257 AstNode *node = ast_create_node(NodeTypeUse, use_kw);
1269 AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw);
12581270
12591271 parse_string_literal(pc, use_name, &node->data.use.path);
12601272
......@@ -1299,7 +1311,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
12991311 }
13001312
13011313 if (pc->directive_list->length > 0) {
1302 ast_error(directive_token, "invalid directive");
1314 ast_error(pc, directive_token, "invalid directive");
13031315 }
13041316 pc->directive_list = nullptr;
13051317
......@@ -1312,7 +1324,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
13121324Root : many(TopLevelDecl) token(EOF)
13131325 */
13141326static AstNode *ast_parse_root(ParseContext *pc, int *token_index) {
1315 AstNode *node = ast_create_node(NodeTypeRoot, &pc->tokens->at(*token_index));
1327 AstNode *node = ast_create_node(pc, NodeTypeRoot, &pc->tokens->at(*token_index));
13161328
13171329 ast_parse_top_level_decls(pc, token_index, &node->data.root.top_level_decls);
13181330
......@@ -1323,8 +1335,10 @@ static AstNode *ast_parse_root(ParseContext *pc, int *token_index) {
13231335 return node;
13241336}
13251337
1326AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) {
1338AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color) {
13271339 ParseContext pc = {0};
1340 pc.err_color = err_color;
1341 pc.owner = owner;
13281342 pc.buf = buf;
13291343 pc.tokens = tokens;
13301344 int token_index = 0;
src/parser.hpp+4-2
......@@ -11,9 +11,11 @@
1111#include "list.hpp"
1212#include "buffer.hpp"
1313#include "tokenizer.hpp"
14#include "errmsg.hpp"
1415
1516struct AstNode;
1617struct CodeGenNode;
18struct ImportTableEntry;
1719
1820enum NodeType {
1921 NodeTypeRoot,
......@@ -166,10 +168,10 @@ struct AstNodeUse {
166168
167169struct AstNode {
168170 enum NodeType type;
169 AstNode *parent;
170171 int line;
171172 int column;
172173 CodeGenNode *codegen_node;
174 ImportTableEntry *owner;
173175 union {
174176 AstNodeRoot root;
175177 AstNodeRootExportDecl root_export_decl;
......@@ -198,7 +200,7 @@ void ast_token_error(Token *token, const char *format, ...);
198200
199201
200202// This function is provided by generated code, generated by parsergen.cpp
201AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens);
203AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color);
202204
203205const char *node_type_str(NodeType node_type);
204206
src/semantic_info.hpp+13-1
......@@ -11,6 +11,7 @@
1111#include "codegen.hpp"
1212#include "hash_map.hpp"
1313#include "zig_llvm.hpp"
14#include "errmsg.hpp"
1415
1516struct FnTableEntry;
1617
......@@ -30,6 +31,8 @@ struct ImportTableEntry {
3031 AstNode *root;
3132 Buf *path; // relative to root_source_dir
3233 LLVMZigDIFile *di_file;
34 Buf *source_code;
35 ZigList<int> *line_offsets;
3336
3437 // reminder: hash tables must be initialized before use
3538 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
......@@ -47,7 +50,7 @@ struct FnTableEntry {
4750
4851struct CodeGen {
4952 LLVMModuleRef module;
50 ZigList<ErrorMsg> errors;
53 ZigList<ErrorMsg*> errors;
5154 LLVMBuilderRef builder;
5255 LLVMZigDIBuilder *dbuilder;
5356 LLVMZigDICompileUnit *compile_unit;
......@@ -77,7 +80,14 @@ struct CodeGen {
7780 Buf *root_source_dir;
7881 Buf *root_out_name;
7982 ZigList<LLVMZigDIScope *> block_scopes;
83
84 // The function definitions this module includes. There must be a corresponding
85 // fn_protos entry.
8086 ZigList<FnTableEntry *> fn_defs;
87 // The function prototypes this module includes. In the case of external declarations,
88 // there will not be a corresponding fn_defs entry.
89 ZigList<FnTableEntry *> fn_protos;
90
8191 OutType out_type;
8292 FnTableEntry *cur_fn;
8393 bool c_stdint_used;
......@@ -86,6 +96,8 @@ struct CodeGen {
8696 int version_minor;
8797 int version_patch;
8898 bool verbose;
99 ErrColor err_color;
100 ImportTableEntry *root_import;
89101};
90102
91103struct TypeNode {
src/tokenizer.cpp+26-17
......@@ -104,6 +104,7 @@ enum TokenizeState {
104104 TokenizeStateBang,
105105 TokenizeStateLessThan,
106106 TokenizeStateGreaterThan,
107 TokenizeStateError,
107108};
108109
109110
......@@ -116,27 +117,25 @@ struct Tokenize {
116117 int column;
117118 Token *cur_tok;
118119 int multi_line_comment_count;
120 Tokenization *out;
119121};
120122
121123__attribute__ ((format (printf, 2, 3)))
122124static void tokenize_error(Tokenize *t, const char *format, ...) {
123 int line;
124 int column;
125 t->state = TokenizeStateError;
126
125127 if (t->cur_tok) {
126 line = t->cur_tok->start_line + 1;
127 column = t->cur_tok->start_column + 1;
128 t->out->err_line = t->cur_tok->start_line;
129 t->out->err_column = t->cur_tok->start_column;
128130 } else {
129 line = t->line + 1;
130 column = t->column + 1;
131 t->out->err_line = t->line;
132 t->out->err_column = t->column;
131133 }
132134
133135 va_list ap;
134136 va_start(ap, format);
135 fprintf(stderr, "Error: Line %d, column %d: ", line, column);
136 vfprintf(stderr, format, ap);
137 fprintf(stderr, "\n");
137 t->out->err = buf_vprintf(format, ap);
138138 va_end(ap);
139 exit(EXIT_FAILURE);
140139}
141140
142141static void begin_token(Tokenize *t, TokenId id) {
......@@ -187,13 +186,20 @@ static void end_token(Tokenize *t) {
187186 t->cur_tok = nullptr;
188187}
189188
190ZigList<Token> *tokenize(Buf *buf) {
189void tokenize(Buf *buf, Tokenization *out) {
191190 Tokenize t = {0};
192 t.tokens = allocate<ZigList<Token>>(1);
191 t.out = out;
192 t.tokens = out->tokens = allocate<ZigList<Token>>(1);
193193 t.buf = buf;
194
195 out->line_offsets = allocate<ZigList<int>>(1);
196
197 out->line_offsets->append(0);
194198 for (t.pos = 0; t.pos < buf_len(t.buf); t.pos += 1) {
195199 uint8_t c = buf_ptr(t.buf)[t.pos];
196200 switch (t.state) {
201 case TokenizeStateError:
202 break;
197203 case TokenizeStateStart:
198204 switch (c) {
199205 case WHITESPACE:
......@@ -509,6 +515,7 @@ ZigList<Token> *tokenize(Buf *buf) {
509515 break;
510516 }
511517 if (c == '\n') {
518 out->line_offsets->append(t.pos + 1);
512519 t.line += 1;
513520 t.column = 0;
514521 } else {
......@@ -518,6 +525,7 @@ ZigList<Token> *tokenize(Buf *buf) {
518525 // EOF
519526 switch (t.state) {
520527 case TokenizeStateStart:
528 case TokenizeStateError:
521529 break;
522530 case TokenizeStateString:
523531 tokenize_error(&t, "unterminated string");
......@@ -544,11 +552,12 @@ ZigList<Token> *tokenize(Buf *buf) {
544552 tokenize_error(&t, "unterminated multi-line comment");
545553 break;
546554 }
547 t.pos = -1;
548 begin_token(&t, TokenIdEof);
549 end_token(&t);
550 assert(!t.cur_tok);
551 return t.tokens;
555 if (t.state != TokenizeStateError) {
556 t.pos = -1;
557 begin_token(&t, TokenIdEof);
558 end_token(&t);
559 assert(!t.cur_tok);
560 }
552561}
553562
554563static const char * token_name(Token *token) {
src/tokenizer.hpp+11-1
......@@ -65,7 +65,17 @@ struct Token {
6565 int start_column;
6666};
6767
68ZigList<Token> *tokenize(Buf *buf);
68struct Tokenization {
69 ZigList<Token> *tokens;
70 ZigList<int> *line_offsets;
71
72 // if an error occurred
73 Buf *err;
74 int err_line;
75 int err_column;
76};
77
78void tokenize(Buf *buf, Tokenization *out_tokenization);
6979
7080void print_tokens(Buf *buf, ZigList<Token> *tokens);
7181
src/util.hpp-2
......@@ -16,8 +16,6 @@
1616
1717#define BREAKPOINT __asm("int $0x03")
1818
19static const int COMPILE_FAILED_ERR_CODE = 10; // chosen with a random number generator
20
2119void zig_panic(const char *format, ...)
2220 __attribute__((cold))
2321 __attribute__ ((noreturn))
test/run_tests.cpp+88-18
......@@ -14,13 +14,13 @@
1414
1515struct TestSourceFile {
1616 const char *relative_path;
17 const char *text;
17 const char *source_code;
1818};
1919
2020struct TestCase {
2121 const char *case_name;
2222 const char *output;
23 const char *source;
23 ZigList<TestSourceFile> source_files;
2424 ZigList<const char *> compile_errors;
2525 ZigList<const char *> compiler_args;
2626 ZigList<const char *> program_args;
......@@ -31,11 +31,20 @@ static const char *tmp_source_path = ".tmp_source.zig";
3131static const char *tmp_exe_path = "./.tmp_exe";
3232static const char *zig_exe = "./zig";
3333
34static void add_simple_case(const char *case_name, const char *source, const char *output) {
34static void add_source_file(TestCase *test_case, const char *path, const char *source) {
35 test_case->source_files.add_one();
36 test_case->source_files.last().relative_path = path;
37 test_case->source_files.last().source_code = source;
38}
39
40static TestCase *add_simple_case(const char *case_name, const char *source, const char *output) {
3541 TestCase *test_case = allocate<TestCase>(1);
3642 test_case->case_name = case_name;
3743 test_case->output = output;
38 test_case->source = source;
44
45 test_case->source_files.resize(1);
46 test_case->source_files.at(0).relative_path = tmp_source_path;
47 test_case->source_files.at(0).source_code = source;
3948
4049 test_case->compiler_args.append("build");
4150 test_case->compiler_args.append(tmp_source_path);
......@@ -48,17 +57,23 @@ static void add_simple_case(const char *case_name, const char *source, const cha
4857 test_case->compiler_args.append("--release");
4958 test_case->compiler_args.append("--strip");
5059 test_case->compiler_args.append("--verbose");
60 test_case->compiler_args.append("--color");
61 test_case->compiler_args.append("on");
5162
5263 test_cases.append(test_case);
64
65 return test_case;
5366}
5467
55static void add_compile_fail_case(const char *case_name, const char *source, int count, ...) {
68static TestCase *add_compile_fail_case(const char *case_name, const char *source, int count, ...) {
5669 va_list ap;
5770 va_start(ap, count);
5871
5972 TestCase *test_case = allocate<TestCase>(1);
6073 test_case->case_name = case_name;
61 test_case->source = source;
74 test_case->source_files.resize(1);
75 test_case->source_files.at(0).relative_path = tmp_source_path;
76 test_case->source_files.at(0).source_code = source;
6277
6378 for (int i = 0; i < count; i += 1) {
6479 const char *arg = va_arg(ap, const char *);
......@@ -76,6 +91,8 @@ static void add_compile_fail_case(const char *case_name, const char *source, int
7691 test_cases.append(test_case);
7792
7893 va_end(ap);
94
95 return test_case;
7996}
8097
8198static void add_compiling_test_cases(void) {
......@@ -133,13 +150,52 @@ static void add_compiling_test_cases(void) {
133150 exit(0);
134151 }
135152 )SOURCE", "OK\n");
153
154 {
155 TestCase *tc = add_simple_case("multiple files with private function", R"SOURCE(
156 use "libc.zig";
157 use "foo.zig";
158
159 export fn _start() -> unreachable {
160 private_function();
161 }
162
163 fn private_function() -> unreachable {
164 print_text();
165 exit(0);
166 }
167 )SOURCE", "OK\n");
168
169 add_source_file(tc, "libc.zig", R"SOURCE(
170 #link("c")
171 extern {
172 pub fn puts(s: *mut u8) -> i32;
173 pub fn exit(code: i32) -> unreachable;
174 }
175 )SOURCE");
176
177 add_source_file(tc, "foo.zig", R"SOURCE(
178 use "libc.zig";
179
180 // purposefully conflicting function with main source file
181 // but it's private so it should be OK
182 fn private_function() {
183 puts("OK");
184 }
185
186 pub fn print_text() {
187 private_function();
188 }
189 )SOURCE");
190 }
191
136192}
137193
138194static void add_compile_failure_test_cases(void) {
139195 add_compile_fail_case("multiple function definitions", R"SOURCE(
140196fn a() {}
141197fn a() {}
142 )SOURCE", 1, "Line 3, column 1: redefinition of 'a'");
198 )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'a'");
143199
144200 add_compile_fail_case("bad directive", R"SOURCE(
145201#bogus1("")
......@@ -148,37 +204,37 @@ extern {
148204}
149205#bogus2("")
150206fn a() {}
151 )SOURCE", 2, "Line 2, column 1: invalid directive: 'bogus1'",
152 "Line 6, column 1: invalid directive: 'bogus2'");
207 )SOURCE", 2, ".tmp_source.zig:2:1: error: invalid directive: 'bogus1'",
208 ".tmp_source.zig:6:1: error: invalid directive: 'bogus2'");
153209
154210 add_compile_fail_case("unreachable with return", R"SOURCE(
155211fn a() -> unreachable {return;}
156 )SOURCE", 1, "Line 2, column 24: return statement in function with unreachable return type");
212 )SOURCE", 1, ".tmp_source.zig:2:24: error: return statement in function with unreachable return type");
157213
158214 add_compile_fail_case("control reaches end of non-void function", R"SOURCE(
159215fn a() -> i32 {}
160 )SOURCE", 1, "Line 2, column 1: control reaches end of non-void function");
216 )SOURCE", 1, ".tmp_source.zig:2:1: error: control reaches end of non-void function");
161217
162218 add_compile_fail_case("undefined function call", R"SOURCE(
163219fn a() {
164220 b();
165221}
166 )SOURCE", 1, "Line 3, column 5: undefined function: 'b'");
222 )SOURCE", 1, ".tmp_source.zig:3:5: error: undefined function: 'b'");
167223
168224 add_compile_fail_case("wrong number of arguments", R"SOURCE(
169225fn a() {
170226 b(1);
171227}
172228fn b(a: i32, b: i32, c: i32) { }
173 )SOURCE", 1, "Line 3, column 5: wrong number of arguments. Expected 3, got 1.");
229 )SOURCE", 1, ".tmp_source.zig:3:5: error: wrong number of arguments. Expected 3, got 1.");
174230
175231 add_compile_fail_case("invalid type", R"SOURCE(
176232fn a() -> bogus {}
177 )SOURCE", 1, "Line 2, column 11: invalid type name: 'bogus'");
233 )SOURCE", 1, ".tmp_source.zig:2:11: error: invalid type name: 'bogus'");
178234
179235 add_compile_fail_case("pointer to unreachable", R"SOURCE(
180236fn a() -> *mut unreachable {}
181 )SOURCE", 1, "Line 2, column 11: pointer to unreachable not allowed");
237 )SOURCE", 1, ".tmp_source.zig:2:11: error: pointer to unreachable not allowed");
182238
183239 add_compile_fail_case("unreachable code", R"SOURCE(
184240fn a() {
......@@ -187,12 +243,16 @@ fn a() {
187243}
188244
189245fn b() {}
190 )SOURCE", 1, "Line 4, column 5: unreachable code");
246 )SOURCE", 1, ".tmp_source.zig:4:5: error: unreachable code");
191247
192248 add_compile_fail_case("bad version string", R"SOURCE(
193249#version("aoeu")
194250export executable "test";
195 )SOURCE", 1, "Line 2, column 1: invalid version string");
251 )SOURCE", 1, ".tmp_source.zig:2:1: error: invalid version string");
252
253 add_compile_fail_case("bad import", R"SOURCE(
254use "bogus-does-not-exist.zig";
255 )SOURCE", 1, ".tmp_source.zig:2:1: error: unable to open \"./bogus-does-not-exist.zig\": file not found");
196256}
197257
198258static void print_compiler_invokation(TestCase *test_case, Buf *zig_stderr) {
......@@ -205,7 +265,12 @@ static void print_compiler_invokation(TestCase *test_case, Buf *zig_stderr) {
205265}
206266
207267static void run_test(TestCase *test_case) {
208 os_write_file(buf_create_from_str(tmp_source_path), buf_create_from_str(test_case->source));
268 for (int i = 0; i < test_case->source_files.length; i += 1) {
269 TestSourceFile *test_source = &test_case->source_files.at(i);
270 os_write_file(
271 buf_create_from_str(test_source->relative_path),
272 buf_create_from_str(test_source->source_code));
273 }
209274
210275 Buf zig_stderr = BUF_INIT;
211276 Buf zig_stdout = BUF_INIT;
......@@ -263,6 +328,11 @@ static void run_test(TestCase *test_case) {
263328 printf("=======================================\n");
264329 exit(1);
265330 }
331
332 for (int i = 0; i < test_case->source_files.length; i += 1) {
333 TestSourceFile *test_source = &test_case->source_files.at(i);
334 remove(test_source->relative_path);
335 }
266336}
267337
268338static void run_all_tests(void) {