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...@@ -31,6 +31,7 @@ set(ZIG_SOURCES
31 "${CMAKE_SOURCE_DIR}/src/main.cpp"31 "${CMAKE_SOURCE_DIR}/src/main.cpp"
32 "${CMAKE_SOURCE_DIR}/src/os.cpp"32 "${CMAKE_SOURCE_DIR}/src/os.cpp"
33 "${CMAKE_SOURCE_DIR}/src/util.cpp"33 "${CMAKE_SOURCE_DIR}/src/util.cpp"
34 "${CMAKE_SOURCE_DIR}/src/errmsg.cpp"
34 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"35 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
35)36)
3637
README.md-1
...@@ -43,7 +43,6 @@ make...@@ -43,7 +43,6 @@ make
43## Roadmap43## Roadmap
4444
45 * variable declarations and assignment expressions45 * variable declarations and assignment expressions
46 * Multiple files
47 * Type checking46 * Type checking
48 * inline assembly and syscalls47 * inline assembly and syscalls
49 * running code at compile time48 * running code at compile time
example/multiple_files/foo.zig+1-1
...@@ -6,6 +6,6 @@ fn private_function() {...@@ -6,6 +6,6 @@ fn private_function() {
6 puts("it works!");6 puts("it works!");
7}7}
88
9fn print_text() {9pub fn print_text() {
10 private_function();10 private_function();
11}11}
example/multiple_files/libc.zig+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1#link("c")1#link("c")
2extern {2extern {
3 fn puts(s: *mut u8) -> i32;3 pub fn puts(s: *mut u8) -> i32;
4 fn exit(code: i32) -> unreachable;4 pub fn exit(code: i32) -> unreachable;
5}5}
example/multiple_files/main.zig+2-2
...@@ -1,9 +1,9 @@...@@ -1,9 +1,9 @@
1export executable "test";1export executable "test-multiple-files";
22
3use "libc.zig";3use "libc.zig";
4use "foo.zig";4use "foo.zig";
55
6fn _start() -> unreachable {6export fn _start() -> unreachable {
7 private_function();7 private_function();
8}8}
99
src/analyze.cpp+129-145
...@@ -17,14 +17,18 @@ struct BlockContext {...@@ -17,14 +17,18 @@ struct BlockContext {
17 BlockContext *parent;17 BlockContext *parent;
18};18};
1919
20static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {20void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
21 g->errors.add_one();21 ErrorMsg *err = allocate<ErrorMsg>(1);
22 ErrorMsg *last_msg = &g->errors.last();22 err->line_start = node->line;
23 last_msg->line_start = node->line;23 err->column_start = node->column;
24 last_msg->column_start = node->column;24 err->line_end = -1;
25 last_msg->line_end = -1;25 err->column_end = -1;
26 last_msg->column_end = -1;26 err->msg = msg;
27 last_msg->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);
28}32}
2933
30static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) {34static 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,...@@ -139,6 +143,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
139 AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);143 AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
140 assert(fn_decl->type == NodeTypeFnDecl);144 assert(fn_decl->type == NodeTypeFnDecl);
141 AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto;145 AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto;
146 bool is_pub = (fn_proto->data.fn_proto.visib_mod == FnProtoVisibModPub);
142 resolve_function_proto(g, fn_proto);147 resolve_function_proto(g, fn_proto);
143 Buf *name = &fn_proto->data.fn_proto.name;148 Buf *name = &fn_proto->data.fn_proto.name;
144149
...@@ -147,7 +152,12 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -147,7 +152,12 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
147 fn_table_entry->is_extern = true;152 fn_table_entry->is_extern = true;
148 fn_table_entry->calling_convention = LLVMCCallConv;153 fn_table_entry->calling_convention = LLVMCCallConv;
149 fn_table_entry->import_entry = import;154 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 }
151 }161 }
152 break;162 break;
153 case NodeTypeFnDef:163 case NodeTypeFnDef:
...@@ -155,67 +165,89 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -155,67 +165,89 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
155 AstNode *proto_node = node->data.fn_def.fn_proto;165 AstNode *proto_node = node->data.fn_def.fn_proto;
156 assert(proto_node->type == NodeTypeFnProto);166 assert(proto_node->type == NodeTypeFnProto);
157 Buf *proto_name = &proto_node->data.fn_proto.name;167 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);
159 if (entry) {172 if (entry) {
160 add_node_error(g, node,173 add_node_error(g, node,
161 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));174 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
162 assert(!node->codegen_node);175 assert(!node->codegen_node);
163 node->codegen_node = allocate<CodeGenNode>(1);176 node->codegen_node = allocate<CodeGenNode>(1);
164 node->codegen_node->data.fn_def_node.skip = true;177 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) {
166 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);191 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
167 fn_table_entry->import_entry = import;192 fn_table_entry->import_entry = import;
168 fn_table_entry->proto_node = proto_node;193 fn_table_entry->proto_node = proto_node;
169 fn_table_entry->fn_def_node = node;194 fn_table_entry->fn_def_node = node;
170 fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport;195 fn_table_entry->internal_linkage = is_internal;
171 if (fn_table_entry->internal_linkage) {196 fn_table_entry->calling_convention = is_internal ? LLVMFastCallConv : LLVMCCallConv;
172 fn_table_entry->calling_convention = LLVMFastCallConv;197
173 } else {198 g->fn_protos.append(fn_table_entry);
174 fn_table_entry->calling_convention = LLVMCCallConv;
175 }
176 g->fn_table.put(proto_name, fn_table_entry);
177 g->fn_defs.append(fn_table_entry);199 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
179 resolve_function_proto(g, proto_node);206 resolve_function_proto(g, proto_node);
180 }207 }
181 }208 }
182 break;209 break;
183 case NodeTypeRootExportDecl:210 case NodeTypeRootExportDecl:
184 for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) {211 if (import == g->root_import) {
185 AstNode *directive_node = node->data.root_export_decl.directives->at(i);212 for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) {
186 Buf *name = &directive_node->data.directive.name;213 AstNode *directive_node = node->data.root_export_decl.directives->at(i);
187 Buf *param = &directive_node->data.directive.param;214 Buf *name = &directive_node->data.directive.name;
188 if (buf_eql_str(name, "version")) {215 Buf *param = &directive_node->data.directive.param;
189 set_root_export_version(g, param, directive_node);216 if (buf_eql_str(name, "version")) {
190 } else {217 set_root_export_version(g, param, directive_node);
191 add_node_error(g, directive_node,218 } else {
192 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));219 add_node_error(g, directive_node,
220 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
221 }
193 }222 }
194 }
195223
196 if (g->root_export_decl) {224 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 {
214 add_node_error(g, node,225 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;
216 }247 }
217 if (g->out_type == OutTypeUnknown)248 } else {
218 g->out_type = export_out_type;249 add_node_error(g, node,
250 buf_sprintf("root export declaration only valid in root source file"));
219 }251 }
220 break;252 break;
221 case NodeTypeUse:253 case NodeTypeUse:
...@@ -263,7 +295,7 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *...@@ -263,7 +295,7 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *
263 add_node_error(g, node, buf_sprintf("type mismatch."));295 add_node_error(g, node, buf_sprintf("type mismatch."));
264}296}
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) {
267 switch (node->type) {299 switch (node->type) {
268 case NodeTypeBlock:300 case NodeTypeBlock:
269 {301 {
...@@ -276,7 +308,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty...@@ -276,7 +308,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
276 buf_sprintf("unreachable code"));308 buf_sprintf("unreachable code"));
277 break;309 break;
278 }310 }
279 return_type = analyze_expression(g, context, nullptr, child);311 return_type = analyze_expression(g, import, context, nullptr, child);
280 }312 }
281 return return_type;313 return return_type;
282 }314 }
...@@ -286,7 +318,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty...@@ -286,7 +318,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
286 TypeTableEntry *expected_return_type = get_return_type(context);318 TypeTableEntry *expected_return_type = get_return_type(context);
287 TypeTableEntry *actual_return_type;319 TypeTableEntry *actual_return_type;
288 if (node->data.return_expr.expr) {320 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);
290 } else {322 } else {
291 actual_return_type = g->builtin_types.entry_void;323 actual_return_type = g->builtin_types.entry_void;
292 }324 }
...@@ -304,8 +336,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty...@@ -304,8 +336,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
304 case NodeTypeBinOpExpr:336 case NodeTypeBinOpExpr:
305 {337 {
306 // TODO: think about expected types338 // TODO: think about expected types
307 analyze_expression(g, context, expected_type, node->data.bin_op_expr.op1);339 analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op1);
308 analyze_expression(g, context, expected_type, node->data.bin_op_expr.op2);340 analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op2);
309 return expected_type;341 return expected_type;
310 }342 }
311343
...@@ -313,14 +345,17 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty...@@ -313,14 +345,17 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
313 {345 {
314 Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);346 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
317 if (!entry) {352 if (!entry) {
318 add_node_error(g, node,353 add_node_error(g, node,
319 buf_sprintf("undefined function: '%s'", buf_ptr(name)));354 buf_sprintf("undefined function: '%s'", buf_ptr(name)));
320 // still analyze the parameters, even though we don't know what to expect355 // still analyze the parameters, even though we don't know what to expect
321 for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {356 for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
322 AstNode *child = node->data.fn_call_expr.params.at(i);357 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);
324 }359 }
325360
326 return g->builtin_types.entry_invalid;361 return g->builtin_types.entry_invalid;
...@@ -350,7 +385,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty...@@ -350,7 +385,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
350 if (param_type_node->codegen_node)385 if (param_type_node->codegen_node)
351 expected_param_type = param_type_node->codegen_node->data.type_node.entry;386 expected_param_type = param_type_node->codegen_node->data.type_node.entry;
352 }387 }
353 analyze_expression(g, context, expected_param_type, child);388 analyze_expression(g, import, context, expected_param_type, child);
354 }389 }
355390
356 TypeTableEntry *return_type = fn_proto->return_type->codegen_node->data.type_node.entry;391 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) {...@@ -444,76 +479,7 @@ static void check_fn_def_control_flow(CodeGen *g, AstNode *node) {
444 }479 }
445}480}
446481
447static void analyze_expression(CodeGen *g, AstNode *node) {482static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, 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) {
517 switch (node->type) {483 switch (node->type) {
518 case NodeTypeFnDef:484 case NodeTypeFnDef:
519 {485 {
...@@ -540,7 +506,7 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {...@@ -540,7 +506,7 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
540 context.root = &context;506 context.root = &context;
541 context.parent = nullptr;507 context.parent = nullptr;
542 TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry;508 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);
544 }510 }
545 break;511 break;
546512
...@@ -576,37 +542,55 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {...@@ -576,37 +542,55 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
576 }542 }
577}543}
578544
579static void analyze_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {545static void find_function_declarations_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
580 assert(node->type == NodeTypeRoot);546 assert(node->type == NodeTypeRoot);
581547
582 // find function declarations
583 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {548 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
584 AstNode *child = node->data.root.top_level_decls.at(i);549 AstNode *child = node->data.root.top_level_decls.at(i);
585 preview_function_declarations(g, import, child);550 preview_function_declarations(g, import, child);
586 }551 }
587552
553}
554
555static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
556 assert(node->type == NodeTypeRoot);
557
588 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {558 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
589 AstNode *child = node->data.root.top_level_decls.at(i);559 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);
591 }561 }
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
593 if (!g->root_out_name) {589 if (!g->root_out_name) {
594 add_node_error(g, node,590 add_node_error(g, g->root_import->root,
595 buf_sprintf("missing export declaration and output name not provided"));591 buf_sprintf("missing export declaration and output name not provided"));
596 } else if (g->out_type == OutTypeUnknown) {592 } else if (g->out_type == OutTypeUnknown) {
597 add_node_error(g, node,593 add_node_error(g, g->root_import->root,
598 buf_sprintf("missing export declaration and export type not provided"));594 buf_sprintf("missing export declaration and export type not provided"));
599 }595 }
600}596}
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 @@...@@ -9,7 +9,10 @@
9#define ZIG_ANALYZE_HPP9#define ZIG_ANALYZE_HPP
1010
11struct CodeGen;11struct CodeGen;
12struct AstNode;
13struct Buf;
1214
13void semantic_analyze(CodeGen *g);15void semantic_analyze(CodeGen *g);
16void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
1417
15#endif18#endif
src/buffer.cpp+10-4
...@@ -3,9 +3,8 @@...@@ -3,9 +3,8 @@
3#include <stdlib.h>3#include <stdlib.h>
4#include <stdio.h>4#include <stdio.h>
55
6Buf *buf_sprintf(const char *format, ...) {6Buf *buf_vprintf(const char *format, va_list ap) {
7 va_list ap, ap2;7 va_list ap2;
8 va_start(ap, format);
9 va_copy(ap2, ap);8 va_copy(ap2, ap);
109
11 int len1 = vsnprintf(nullptr, 0, format, ap);10 int len1 = vsnprintf(nullptr, 0, format, ap);
...@@ -19,11 +18,18 @@ Buf *buf_sprintf(const char *format, ...) {...@@ -19,11 +18,18 @@ Buf *buf_sprintf(const char *format, ...) {
19 assert(len2 == len1);18 assert(len2 == len1);
2019
21 va_end(ap2);20 va_end(ap2);
22 va_end(ap);
2321
24 return buf;22 return buf;
25}23}
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
27void buf_appendf(Buf *buf, const char *format, ...) {33void buf_appendf(Buf *buf, const char *format, ...) {
28 assert(buf->list.length);34 assert(buf->list.length);
29 va_list ap, ap2;35 va_list ap, ap2;
src/buffer.hpp+2
...@@ -13,6 +13,7 @@...@@ -13,6 +13,7 @@
13#include <assert.h>13#include <assert.h>
14#include <stdint.h>14#include <stdint.h>
15#include <ctype.h>15#include <ctype.h>
16#include <stdarg.h>
1617
17#define BUF_INIT {{0}}18#define BUF_INIT {{0}}
1819
...@@ -24,6 +25,7 @@ struct Buf {...@@ -24,6 +25,7 @@ struct Buf {
2425
25Buf *buf_sprintf(const char *format, ...)26Buf *buf_sprintf(const char *format, ...)
26 __attribute__ ((format (printf, 1, 2)));27 __attribute__ ((format (printf, 1, 2)));
28Buf *buf_vprintf(const char *format, va_list ap);
2729
28static inline int buf_len(Buf *buf) {30static inline int buf_len(Buf *buf) {
29 assert(buf->list.length);31 assert(buf->list.length);
src/codegen.cpp+51-22
...@@ -13,6 +13,7 @@...@@ -13,6 +13,7 @@
13#include "error.hpp"13#include "error.hpp"
14#include "semantic_info.hpp"14#include "semantic_info.hpp"
15#include "analyze.hpp"15#include "analyze.hpp"
16#include "errmsg.hpp"
1617
17#include <stdio.h>18#include <stdio.h>
18#include <errno.h>19#include <errno.h>
...@@ -41,6 +42,10 @@ void codegen_set_verbose(CodeGen *g, bool verbose) {...@@ -41,6 +42,10 @@ void codegen_set_verbose(CodeGen *g, bool verbose) {
41 g->verbose = verbose;42 g->verbose = verbose;
42}43}
4344
45void codegen_set_errmsg_color(CodeGen *g, ErrColor err_color) {
46 g->err_color = err_color;
47}
48
44void codegen_set_strip(CodeGen *g, bool strip) {49void codegen_set_strip(CodeGen *g, bool strip) {
45 g->strip_debug_symbols = strip;50 g->strip_debug_symbols = strip;
46}51}
...@@ -120,7 +125,13 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -120,7 +125,13 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
120125
121 Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);126 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
124 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);135 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
125 int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length;136 int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length;
126 int actual_param_count = node->data.fn_call_expr.params.length;137 int actual_param_count = node->data.fn_call_expr.params.length;
...@@ -473,13 +484,8 @@ static void do_code_gen(CodeGen *g) {...@@ -473,13 +484,8 @@ static void do_code_gen(CodeGen *g) {
473484
474485
475 // Generate function prototypes486 // Generate function prototypes
476 auto it = g->fn_table.entry_iterator();487 for (int i = 0; i < g->fn_protos.length; i += 1) {
477 for (;;) {488 FnTableEntry *fn_table_entry = g->fn_protos.at(i);
478 auto *entry = it.next();
479 if (!entry)
480 break;
481
482 FnTableEntry *fn_table_entry = entry->value;
483489
484 AstNode *proto_node = fn_table_entry->proto_node;490 AstNode *proto_node = fn_table_entry->proto_node;
485 assert(proto_node->type == NodeTypeFnProto);491 assert(proto_node->type == NodeTypeFnProto);
...@@ -542,6 +548,7 @@ static void do_code_gen(CodeGen *g) {...@@ -542,6 +548,7 @@ static void do_code_gen(CodeGen *g) {
542 assert(codegen_node);548 assert(codegen_node);
543549
544 FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node;550 FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node;
551 assert(codegen_fn_def);
545 codegen_fn_def->params = allocate<LLVMValueRef>(LLVMCountParams(fn));552 codegen_fn_def->params = allocate<LLVMValueRef>(LLVMCountParams(fn));
546 LLVMGetParams(fn, codegen_fn_def->params);553 LLVMGetParams(fn, codegen_fn_def->params);
547554
...@@ -664,7 +671,8 @@ static void init(CodeGen *g, Buf *source_path) {...@@ -664,7 +671,8 @@ static void init(CodeGen *g, Buf *source_path) {
664671
665}672}
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;
668 Buf full_path = BUF_INIT;676 Buf full_path = BUF_INIT;
669 os_path_join(g->root_source_dir, source_path, &full_path);677 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) {...@@ -681,24 +689,42 @@ static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
681 fprintf(stderr, "---------\n");689 fprintf(stderr, "---------\n");
682 }690 }
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
686 if (g->verbose) {710 if (g->verbose) {
687 print_tokens(source_code, tokens);711 print_tokens(source_code, tokenization.tokens);
688712
689 fprintf(stderr, "\nAST:\n");713 fprintf(stderr, "\nAST:\n");
690 fprintf(stderr, "------\n");714 fprintf(stderr, "------\n");
691 }715 }
692716
693 ImportTableEntry *import_entry = allocate<ImportTableEntry>(1);717 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;
694 import_entry->fn_table.init(32);721 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);
696 assert(import_entry->root);723 assert(import_entry->root);
697 if (g->verbose) {724 if (g->verbose) {
698 ast_print(import_entry->root, 0);725 ast_print(import_entry->root, 0);
699 }726 }
700727
701 import_entry->path = source_path;
702 import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&basename), buf_ptr(&dirname));728 import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&basename), buf_ptr(&dirname));
703 g->import_table.put(source_path, import_entry);729 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) {...@@ -713,18 +739,23 @@ static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
713 if (!entry) {739 if (!entry) {
714 Buf full_path = BUF_INIT;740 Buf full_path = BUF_INIT;
715 os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path);741 os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path);
716 Buf import_code = BUF_INIT;742 Buf *import_code = buf_alloc();
717 os_fetch_file_path(&full_path, &import_code);743 if ((err = os_fetch_file_path(&full_path, import_code))) {
718 codegen_add_code(g, &top_level_decl->data.use.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);
719 }749 }
720 }750 }
751
752 return import_entry;
721}753}
722754
723void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) {755void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) {
724 init(g, source_path);756 init(g, source_path);
725757
726 codegen_add_code(g, source_path, source_code);758 g->root_import = codegen_add_code(g, source_path, source_code);
727
728759
729 if (g->verbose) {760 if (g->verbose) {
730 fprintf(stderr, "\nSemantic Analysis:\n");761 fprintf(stderr, "\nSemantic Analysis:\n");
...@@ -738,10 +769,8 @@ void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) {...@@ -738,10 +769,8 @@ void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) {
738 }769 }
739 } else {770 } else {
740 for (int i = 0; i < g->errors.length; i += 1) {771 for (int i = 0; i < g->errors.length; i += 1) {
741 ErrorMsg *err = &g->errors.at(i);772 ErrorMsg *err = g->errors.at(i);
742 fprintf(stderr, "Error: Line %d, column %d: %s\n",773 print_err_msg(err, g->err_color);
743 err->line_start + 1, err->column_start + 1,
744 buf_ptr(err->msg));
745 }774 }
746 exit(1);775 exit(1);
747 }776 }
src/codegen.hpp+2-10
...@@ -9,6 +9,7 @@...@@ -9,6 +9,7 @@
9#define ZIG_CODEGEN_HPP9#define ZIG_CODEGEN_HPP
1010
11#include "parser.hpp"11#include "parser.hpp"
12#include "errmsg.hpp"
1213
13struct CodeGen;14struct CodeGen;
1415
...@@ -19,16 +20,6 @@ enum OutType {...@@ -19,16 +20,6 @@ enum OutType {
19 OutTypeObj,20 OutTypeObj,
20};21};
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
32CodeGen *codegen_create(Buf *root_source_dir);23CodeGen *codegen_create(Buf *root_source_dir);
3324
34enum CodeGenBuildType {25enum CodeGenBuildType {
...@@ -39,6 +30,7 @@ void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type);...@@ -39,6 +30,7 @@ void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type);
39void codegen_set_is_static(CodeGen *codegen, bool is_static);30void codegen_set_is_static(CodeGen *codegen, bool is_static);
40void codegen_set_strip(CodeGen *codegen, bool strip);31void codegen_set_strip(CodeGen *codegen, bool strip);
41void codegen_set_verbose(CodeGen *codegen, bool verbose);32void codegen_set_verbose(CodeGen *codegen, bool verbose);
33void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color);
42void codegen_set_out_type(CodeGen *codegen, OutType out_type);34void codegen_set_out_type(CodeGen *codegen, OutType out_type);
43void codegen_set_out_name(CodeGen *codegen, Buf *out_name);35void 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) {...@@ -6,6 +6,12 @@ const char *err_str(int err) {
6 case ErrorNoMem: return "out of memory";6 case ErrorNoMem: return "out of memory";
7 case ErrorInvalidFormat: return "invalid format";7 case ErrorInvalidFormat: return "invalid format";
8 case ErrorSemanticAnalyzeFail: return "semantic analyze failed";8 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";
9 }15 }
10 return "(invalid error)";16 return "(invalid error)";
11}17}
src/error.hpp+6
...@@ -13,6 +13,12 @@ enum Error {...@@ -13,6 +13,12 @@ enum Error {
13 ErrorNoMem,13 ErrorNoMem,
14 ErrorInvalidFormat,14 ErrorInvalidFormat,
15 ErrorSemanticAnalyzeFail,15 ErrorSemanticAnalyzeFail,
16 ErrorAccess,
17 ErrorInterrupted,
18 ErrorSystemResources,
19 ErrorFileNotFound,
20 ErrorFileSystem,
21 ErrorFileTooBig,
16};22};
1723
18const char *err_str(int err);24const char *err_str(int err);
src/main.cpp+16-1
...@@ -25,6 +25,7 @@ static int usage(const char *arg0) {...@@ -25,6 +25,7 @@ static int usage(const char *arg0) {
25 " --name [name] override output name\n"25 " --name [name] override output name\n"
26 " --output [file] override destination path\n"26 " --output [file] override destination path\n"
27 " --verbose turn on compiler debug output\n"27 " --verbose turn on compiler debug output\n"
28 " --color [auto|off|on] enable or disable colored error messages\n"
28 , arg0);29 , arg0);
29 return EXIT_FAILURE;30 return EXIT_FAILURE;
30}31}
...@@ -43,6 +44,7 @@ struct Build {...@@ -43,6 +44,7 @@ struct Build {
43 OutType out_type;44 OutType out_type;
44 const char *out_name;45 const char *out_name;
45 bool verbose;46 bool verbose;
47 ErrColor color;
46};48};
4749
48static int build(const char *arg0, Build *b) {50static int build(const char *arg0, Build *b) {
...@@ -73,6 +75,7 @@ static int build(const char *arg0, Build *b) {...@@ -73,6 +75,7 @@ static int build(const char *arg0, Build *b) {
73 if (b->out_name)75 if (b->out_name)
74 codegen_set_out_name(g, buf_create_from_str(b->out_name));76 codegen_set_out_name(g, buf_create_from_str(b->out_name));
75 codegen_set_verbose(g, b->verbose);77 codegen_set_verbose(g, b->verbose);
78 codegen_set_errmsg_color(g, b->color);
76 codegen_add_root_code(g, &root_source_name, &root_source_code);79 codegen_add_root_code(g, &root_source_name, &root_source_code);
77 codegen_link(g, b->out_file);80 codegen_link(g, b->out_file);
7881
...@@ -106,7 +109,9 @@ int main(int argc, char **argv) {...@@ -106,7 +109,9 @@ int main(int argc, char **argv) {
106 return usage(arg0);109 return usage(arg0);
107 } else {110 } else {
108 i += 1;111 i += 1;
109 if (strcmp(arg, "--output") == 0) {112 if (i >= argc) {
113 return usage(arg0);
114 } else if (strcmp(arg, "--output") == 0) {
110 b.out_file = argv[i];115 b.out_file = argv[i];
111 } else if (strcmp(arg, "--export") == 0) {116 } else if (strcmp(arg, "--export") == 0) {
112 if (strcmp(argv[i], "exe") == 0) {117 if (strcmp(argv[i], "exe") == 0) {
...@@ -118,6 +123,16 @@ int main(int argc, char **argv) {...@@ -118,6 +123,16 @@ int main(int argc, char **argv) {
118 } else {123 } else {
119 return usage(arg0);124 return usage(arg0);
120 }125 }
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 }
121 } else if (strcmp(arg, "--name") == 0) {136 } else if (strcmp(arg, "--name") == 0) {
122 b.out_name = argv[i];137 b.out_name = argv[i];
123 } else {138 } else {
src/os.cpp+52-8
...@@ -7,6 +7,7 @@...@@ -7,6 +7,7 @@
77
8#include "os.hpp"8#include "os.hpp"
9#include "util.hpp"9#include "util.hpp"
10#include "error.hpp"
1011
11#include <unistd.h>12#include <unistd.h>
12#include <errno.h>13#include <errno.h>
...@@ -143,26 +144,65 @@ void os_write_file(Buf *full_path, Buf *contents) {...@@ -143,26 +144,65 @@ void os_write_file(Buf *full_path, Buf *contents) {
143int os_fetch_file(FILE *f, Buf *out_contents) {144int os_fetch_file(FILE *f, Buf *out_contents) {
144 int fd = fileno(f);145 int fd = fileno(f);
145 struct stat st;146 struct stat st;
146 if (fstat(fd, &st))147 if (fstat(fd, &st)) {
147 zig_panic("unable to stat file: %s", strerror(errno));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 }
148 off_t big_size = st.st_size;163 off_t big_size = st.st_size;
149 if (big_size > INT_MAX)164 if (big_size > INT_MAX) {
150 zig_panic("file too big");165 return ErrorFileTooBig;
166 }
151 int size = (int)big_size;167 int size = (int)big_size;
152168
153 buf_resize(out_contents, size);169 buf_resize(out_contents, size);
154 ssize_t ret = read(fd, buf_ptr(out_contents), size);170 ssize_t ret = read(fd, buf_ptr(out_contents), size);
155171
156 if (ret != size)172 if (ret != size) {
157 zig_panic("unable to read file: %s", strerror(errno));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
159 return 0;184 return 0;
160}185}
161186
162int os_fetch_file_path(Buf *full_path, Buf *out_contents) {187int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
163 FILE *f = fopen(buf_ptr(full_path), "rb");188 FILE *f = fopen(buf_ptr(full_path), "rb");
164 if (!f)189 if (!f) {
165 zig_panic("unable to open %s: %s\n", buf_ptr(full_path), strerror(errno));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 }
166 int result = os_fetch_file(f, out_contents);206 int result = os_fetch_file(f, out_contents);
167 fclose(f);207 fclose(f);
168 return result;208 return result;
...@@ -180,3 +220,7 @@ int os_get_cwd(Buf *out_cwd) {...@@ -180,3 +220,7 @@ int os_get_cwd(Buf *out_cwd) {
180220
181 return 0;221 return 0;
182}222}
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);...@@ -29,4 +29,6 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents);
29int os_get_cwd(Buf *out_cwd);29int os_get_cwd(Buf *out_cwd);
3030
3131
32bool os_stderr_tty(void);
33
32#endif34#endif
src/parser.cpp+67-53
...@@ -6,6 +6,8 @@...@@ -6,6 +6,8 @@
6 */6 */
77
8#include "parser.hpp"8#include "parser.hpp"
9#include "errmsg.hpp"
10#include "semantic_info.hpp"
911
10#include <stdarg.h>12#include <stdarg.h>
11#include <stdio.h>13#include <stdio.h>
...@@ -45,21 +47,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {...@@ -45,21 +47,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
45 zig_unreachable();47 zig_unreachable();
46}48}
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
63const char *node_type_str(NodeType node_type) {50const char *node_type_str(NodeType node_type) {
64 switch (node_type) {51 switch (node_type) {
65 case NodeTypeRoot:52 case NodeTypeRoot:
...@@ -254,11 +241,36 @@ struct ParseContext {...@@ -254,11 +241,36 @@ struct ParseContext {
254 AstNode *root;241 AstNode *root;
255 ZigList<Token> *tokens;242 ZigList<Token> *tokens;
256 ZigList<AstNode *> *directive_list;243 ZigList<AstNode *> *directive_list;
244 ImportTableEntry *owner;
245 ErrColor err_color;
257};246};
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) {
260 AstNode *node = allocate<AstNode>(1);271 AstNode *node = allocate<AstNode>(1);
261 node->type = type;272 node->type = type;
273 node->owner = pc->owner;
262 return node;274 return node;
263}275}
264276
...@@ -267,21 +279,21 @@ static void ast_update_node_line_info(AstNode *node, Token *first_token) {...@@ -267,21 +279,21 @@ static void ast_update_node_line_info(AstNode *node, Token *first_token) {
267 node->column = first_token->start_column;279 node->column = first_token->start_column;
268}280}
269281
270static AstNode *ast_create_node(NodeType type, Token *first_token) {282static AstNode *ast_create_node(ParseContext *pc, NodeType type, Token *first_token) {
271 AstNode *node = ast_create_node_no_line_info(type);283 AstNode *node = ast_create_node_no_line_info(pc, type);
272 ast_update_node_line_info(node, first_token);284 ast_update_node_line_info(node, first_token);
273 return node;285 return node;
274}286}
275287
276static AstNode *ast_create_node_with_node(NodeType type, AstNode *other_node) {288static AstNode *ast_create_node_with_node(ParseContext *pc, NodeType type, AstNode *other_node) {
277 AstNode *node = ast_create_node_no_line_info(type);289 AstNode *node = ast_create_node_no_line_info(pc, type);
278 node->line = other_node->line;290 node->line = other_node->line;
279 node->column = other_node->column;291 node->column = other_node->column;
280 return node;292 return node;
281}293}
282294
283static AstNode *ast_create_void_type_node(ParseContext *pc, Token *token) {295static 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);
285 node->data.type.type = AstNodeTypeTypePrimitive;297 node->data.type.type = AstNodeTypeTypePrimitive;
286 buf_init_from_str(&node->data.type.primitive_name, "void");298 buf_init_from_str(&node->data.type.primitive_name, "void");
287 return node;299 return node;
...@@ -331,7 +343,7 @@ __attribute__ ((noreturn))...@@ -331,7 +343,7 @@ __attribute__ ((noreturn))
331static void ast_invalid_token_error(ParseContext *pc, Token *token) {343static void ast_invalid_token_error(ParseContext *pc, Token *token) {
332 Buf token_value = BUF_INIT;344 Buf token_value = BUF_INIT;
333 ast_buf_from_token(pc, token, &token_value);345 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));
335}347}
336348
337static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool mandatory);349static 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_...@@ -349,7 +361,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_
349 token_index += 1;361 token_index += 1;
350 ast_expect_token(pc, number_sign, TokenIdNumberSign);362 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
354 Token *name_symbol = &pc->tokens->at(token_index);366 Token *name_symbol = &pc->tokens->at(token_index);
355 token_index += 1;367 token_index += 1;
...@@ -399,7 +411,7 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token...@@ -399,7 +411,7 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token
399 Token *token = &pc->tokens->at(token_index);411 Token *token = &pc->tokens->at(token_index);
400 token_index += 1;412 token_index += 1;
401413
402 AstNode *node = ast_create_node(NodeTypeType, token);414 AstNode *node = ast_create_node(pc, NodeTypeType, token);
403415
404 if (token->id == TokenIdKeywordUnreachable) {416 if (token->id == TokenIdKeywordUnreachable) {
405 node->data.type.type = AstNodeTypeTypePrimitive;417 node->data.type.type = AstNodeTypeTypePrimitive;
...@@ -437,7 +449,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new...@@ -437,7 +449,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new
437 token_index += 1;449 token_index += 1;
438 ast_expect_token(pc, param_name, TokenIdSymbol);450 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
443 ast_buf_from_token(pc, param_name, &node->data.param_decl.name);455 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...@@ -544,21 +556,21 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
544 Token *token = &pc->tokens->at(*token_index);556 Token *token = &pc->tokens->at(*token_index);
545557
546 if (token->id == TokenIdNumberLiteral) {558 if (token->id == TokenIdNumberLiteral) {
547 AstNode *node = ast_create_node(NodeTypeNumberLiteral, token);559 AstNode *node = ast_create_node(pc, NodeTypeNumberLiteral, token);
548 ast_buf_from_token(pc, token, &node->data.number);560 ast_buf_from_token(pc, token, &node->data.number);
549 *token_index += 1;561 *token_index += 1;
550 return node;562 return node;
551 } else if (token->id == TokenIdStringLiteral) {563 } else if (token->id == TokenIdStringLiteral) {
552 AstNode *node = ast_create_node(NodeTypeStringLiteral, token);564 AstNode *node = ast_create_node(pc, NodeTypeStringLiteral, token);
553 parse_string_literal(pc, token, &node->data.string);565 parse_string_literal(pc, token, &node->data.string);
554 *token_index += 1;566 *token_index += 1;
555 return node;567 return node;
556 } else if (token->id == TokenIdKeywordUnreachable) {568 } else if (token->id == TokenIdKeywordUnreachable) {
557 AstNode *node = ast_create_node(NodeTypeUnreachable, token);569 AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token);
558 *token_index += 1;570 *token_index += 1;
559 return node;571 return node;
560 } else if (token->id == TokenIdSymbol) {572 } else if (token->id == TokenIdSymbol) {
561 AstNode *node = ast_create_node(NodeTypeSymbol, token);573 AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
562 ast_buf_from_token(pc, token, &node->data.symbol);574 ast_buf_from_token(pc, token, &node->data.symbol);
563 *token_index += 1;575 *token_index += 1;
564 return node;576 return node;
...@@ -592,7 +604,7 @@ static AstNode *ast_parse_fn_call_expr(ParseContext *pc, int *token_index, bool...@@ -592,7 +604,7 @@ static AstNode *ast_parse_fn_call_expr(ParseContext *pc, int *token_index, bool
592 if (l_paren->id != TokenIdLParen)604 if (l_paren->id != TokenIdLParen)
593 return primary_expr;605 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);
596 node->data.fn_call_expr.fn_ref_expr = primary_expr;608 node->data.fn_call_expr.fn_ref_expr = primary_expr;
597 ast_parse_fn_call_param_list(pc, *token_index, token_index, &node->data.fn_call_expr.params);609 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...@@ -635,7 +647,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo
635 return ast_parse_fn_call_expr(pc, token_index, mandatory);647 return ast_parse_fn_call_expr(pc, token_index, mandatory);
636648
637 AstNode *primary_expr = ast_parse_fn_call_expr(pc, token_index, true);649 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);
639 node->data.prefix_op_expr.primary_expr = primary_expr;651 node->data.prefix_op_expr.primary_expr = primary_expr;
640 node->data.prefix_op_expr.prefix_op = prefix_op;652 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...@@ -656,7 +668,7 @@ static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bo
656 return prefix_op_expr;668 return prefix_op_expr;
657 *token_index += 1;669 *token_index += 1;
658670
659 AstNode *node = ast_create_node(NodeTypeCastExpr, as_kw);671 AstNode *node = ast_create_node(pc, NodeTypeCastExpr, as_kw);
660 node->data.cast_expr.prefix_op_expr = prefix_op_expr;672 node->data.cast_expr.prefix_op_expr = prefix_op_expr;
661673
662 node->data.cast_expr.type = ast_parse_type(pc, *token_index, token_index);674 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...@@ -705,7 +717,7 @@ static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool man
705717
706 AstNode *operand_2 = ast_parse_cast_expression(pc, token_index, true);718 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);
709 node->data.bin_op_expr.op1 = operand_1;721 node->data.bin_op_expr.op1 = operand_1;
710 node->data.bin_op_expr.bin_op = mult_op;722 node->data.bin_op_expr.bin_op = mult_op;
711 node->data.bin_op_expr.op2 = operand_2;723 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...@@ -753,7 +765,7 @@ static AstNode *ast_parse_add_expr(ParseContext *pc, int *token_index, bool mand
753765
754 AstNode *operand_2 = ast_parse_mult_expr(pc, token_index, true);766 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);
757 node->data.bin_op_expr.op1 = operand_1;769 node->data.bin_op_expr.op1 = operand_1;
758 node->data.bin_op_expr.bin_op = add_op;770 node->data.bin_op_expr.bin_op = add_op;
759 node->data.bin_op_expr.op2 = operand_2;771 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...@@ -801,7 +813,7 @@ static AstNode *ast_parse_bit_shift_expr(ParseContext *pc, int *token_index, boo
801813
802 AstNode *operand_2 = ast_parse_add_expr(pc, token_index, true);814 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);
805 node->data.bin_op_expr.op1 = operand_1;817 node->data.bin_op_expr.op1 = operand_1;
806 node->data.bin_op_expr.bin_op = bit_shift_op;818 node->data.bin_op_expr.bin_op = bit_shift_op;
807 node->data.bin_op_expr.op2 = operand_2;819 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...@@ -825,7 +837,7 @@ static AstNode *ast_parse_bin_and_expr(ParseContext *pc, int *token_index, bool
825837
826 AstNode *operand_2 = ast_parse_bit_shift_expr(pc, token_index, true);838 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);
829 node->data.bin_op_expr.op1 = operand_1;841 node->data.bin_op_expr.op1 = operand_1;
830 node->data.bin_op_expr.bin_op = BinOpTypeBinAnd;842 node->data.bin_op_expr.bin_op = BinOpTypeBinAnd;
831 node->data.bin_op_expr.op2 = operand_2;843 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...@@ -848,7 +860,7 @@ static AstNode *ast_parse_bin_xor_expr(ParseContext *pc, int *token_index, bool
848860
849 AstNode *operand_2 = ast_parse_bin_and_expr(pc, token_index, true);861 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);
852 node->data.bin_op_expr.op1 = operand_1;864 node->data.bin_op_expr.op1 = operand_1;
853 node->data.bin_op_expr.bin_op = BinOpTypeBinXor;865 node->data.bin_op_expr.bin_op = BinOpTypeBinXor;
854 node->data.bin_op_expr.op2 = operand_2;866 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...@@ -871,7 +883,7 @@ static AstNode *ast_parse_bin_or_expr(ParseContext *pc, int *token_index, bool m
871883
872 AstNode *operand_2 = ast_parse_bin_xor_expr(pc, token_index, true);884 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);
875 node->data.bin_op_expr.op1 = operand_1;887 node->data.bin_op_expr.op1 = operand_1;
876 node->data.bin_op_expr.bin_op = BinOpTypeBinOr;888 node->data.bin_op_expr.bin_op = BinOpTypeBinOr;
877 node->data.bin_op_expr.op2 = operand_2;889 node->data.bin_op_expr.op2 = operand_2;
...@@ -920,7 +932,7 @@ static AstNode *ast_parse_comparison_expr(ParseContext *pc, int *token_index, bo...@@ -920,7 +932,7 @@ static AstNode *ast_parse_comparison_expr(ParseContext *pc, int *token_index, bo
920932
921 AstNode *operand_2 = ast_parse_bin_or_expr(pc, token_index, true);933 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);
924 node->data.bin_op_expr.op1 = operand_1;936 node->data.bin_op_expr.op1 = operand_1;
925 node->data.bin_op_expr.bin_op = cmp_op;937 node->data.bin_op_expr.bin_op = cmp_op;
926 node->data.bin_op_expr.op2 = operand_2;938 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...@@ -943,7 +955,7 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc, int *token_index, bool
943955
944 AstNode *operand_2 = ast_parse_comparison_expr(pc, token_index, true);956 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);
947 node->data.bin_op_expr.op1 = operand_1;959 node->data.bin_op_expr.op1 = operand_1;
948 node->data.bin_op_expr.bin_op = BinOpTypeBoolAnd;960 node->data.bin_op_expr.bin_op = BinOpTypeBoolAnd;
949 node->data.bin_op_expr.op2 = operand_2;961 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...@@ -958,7 +970,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
958 Token *return_tok = &pc->tokens->at(*token_index);970 Token *return_tok = &pc->tokens->at(*token_index);
959 if (return_tok->id == TokenIdKeywordReturn) {971 if (return_tok->id == TokenIdKeywordReturn) {
960 *token_index += 1;972 *token_index += 1;
961 AstNode *node = ast_create_node(NodeTypeReturnExpr, return_tok);973 AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, return_tok);
962 node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);974 node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);
963 return node;975 return node;
964 } else if (mandatory) {976 } else if (mandatory) {
...@@ -983,7 +995,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool...@@ -983,7 +995,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool
983995
984 AstNode *operand_2 = ast_parse_bool_and_expr(pc, token_index, true);996 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);
987 node->data.bin_op_expr.op1 = operand_1;999 node->data.bin_op_expr.op1 = operand_1;
988 node->data.bin_op_expr.bin_op = BinOpTypeBoolOr;1000 node->data.bin_op_expr.bin_op = BinOpTypeBoolOr;
989 node->data.bin_op_expr.op2 = operand_2;1001 node->data.bin_op_expr.op2 = operand_2;
...@@ -1046,7 +1058,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato...@@ -1046,7 +1058,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
1046 }1058 }
1047 *token_index += 1;1059 *token_index += 1;
10481060
1049 AstNode *node = ast_create_node(NodeTypeBlock, l_brace);1061 AstNode *node = ast_create_node(pc, NodeTypeBlock, l_brace);
10501062
1051 for (;;) {1063 for (;;) {
1052 Token *token = &pc->tokens->at(*token_index);1064 Token *token = &pc->tokens->at(*token_index);
...@@ -1092,7 +1104,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand...@@ -1092,7 +1104,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
1092 return nullptr;1104 return nullptr;
1093 }1105 }
10941106
1095 AstNode *node = ast_create_node(NodeTypeFnProto, token);1107 AstNode *node = ast_create_node(pc, NodeTypeFnProto, token);
1096 node->data.fn_proto.visib_mod = visib_mod;1108 node->data.fn_proto.visib_mod = visib_mod;
1097 node->data.fn_proto.directives = pc->directive_list;1109 node->data.fn_proto.directives = pc->directive_list;
1098 pc->directive_list = nullptr;1110 pc->directive_list = nullptr;
...@@ -1125,7 +1137,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandat...@@ -1125,7 +1137,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandat
1125 AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory);1137 AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory);
1126 if (!fn_proto)1138 if (!fn_proto)
1127 return nullptr;1139 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
1130 node->data.fn_def.fn_proto = fn_proto;1142 node->data.fn_def.fn_proto = fn_proto;
1131 node->data.fn_def.body = ast_parse_block(pc, token_index, true);1143 node->data.fn_def.body = ast_parse_block(pc, token_index, true);
...@@ -1138,7 +1150,7 @@ FnDecl : FnProto token(Semicolon)...@@ -1138,7 +1150,7 @@ FnDecl : FnProto token(Semicolon)
1138*/1150*/
1139static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) {1151static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) {
1140 AstNode *fn_proto = ast_parse_fn_proto(pc, &token_index, true);1152 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
1143 node->data.fn_decl.fn_proto = fn_proto;1155 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...@@ -1166,7 +1178,7 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool
1166 }1178 }
1167 *token_index += 1;1179 *token_index += 1;
11681180
1169 AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw);1181 AstNode *node = ast_create_node(pc, NodeTypeExternBlock, extern_kw);
11701182
1171 node->data.extern_block.directives = pc->directive_list;1183 node->data.extern_block.directives = pc->directive_list;
1172 pc->directive_list = nullptr;1184 pc->directive_list = nullptr;
...@@ -1184,7 +1196,7 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool...@@ -1184,7 +1196,7 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool
1184 Token *token = &pc->tokens->at(*token_index);1196 Token *token = &pc->tokens->at(*token_index);
1185 if (token->id == TokenIdRBrace) {1197 if (token->id == TokenIdRBrace) {
1186 if (pc->directive_list->length > 0) {1198 if (pc->directive_list->length > 0) {
1187 ast_error(directive_token, "invalid directive");1199 ast_error(pc, directive_token, "invalid directive");
1188 }1200 }
1189 pc->directive_list = nullptr;1201 pc->directive_list = nullptr;
11901202
...@@ -1216,7 +1228,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b...@@ -1216,7 +1228,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
12161228
1217 *token_index += 2;1229 *token_index += 2;
12181230
1219 AstNode *node = ast_create_node(NodeTypeRootExportDecl, export_kw);1231 AstNode *node = ast_create_node(pc, NodeTypeRootExportDecl, export_kw);
1220 node->data.root_export_decl.directives = pc->directive_list;1232 node->data.root_export_decl.directives = pc->directive_list;
1221 pc->directive_list = nullptr;1233 pc->directive_list = nullptr;
12221234
...@@ -1254,7 +1266,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory...@@ -1254,7 +1266,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory
1254 *token_index += 1;1266 *token_index += 1;
1255 ast_expect_token(pc, semicolon, TokenIdSemicolon);1267 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
1259 parse_string_literal(pc, use_name, &node->data.use.path);1271 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...@@ -1299,7 +1311,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
1299 }1311 }
13001312
1301 if (pc->directive_list->length > 0) {1313 if (pc->directive_list->length > 0) {
1302 ast_error(directive_token, "invalid directive");1314 ast_error(pc, directive_token, "invalid directive");
1303 }1315 }
1304 pc->directive_list = nullptr;1316 pc->directive_list = nullptr;
13051317
...@@ -1312,7 +1324,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis...@@ -1312,7 +1324,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
1312Root : many(TopLevelDecl) token(EOF)1324Root : many(TopLevelDecl) token(EOF)
1313 */1325 */
1314static AstNode *ast_parse_root(ParseContext *pc, int *token_index) {1326static 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
1317 ast_parse_top_level_decls(pc, token_index, &node->data.root.top_level_decls);1329 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) {...@@ -1323,8 +1335,10 @@ static AstNode *ast_parse_root(ParseContext *pc, int *token_index) {
1323 return node;1335 return node;
1324}1336}
13251337
1326AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) {1338AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color) {
1327 ParseContext pc = {0};1339 ParseContext pc = {0};
1340 pc.err_color = err_color;
1341 pc.owner = owner;
1328 pc.buf = buf;1342 pc.buf = buf;
1329 pc.tokens = tokens;1343 pc.tokens = tokens;
1330 int token_index = 0;1344 int token_index = 0;
src/parser.hpp+4-2
...@@ -11,9 +11,11 @@...@@ -11,9 +11,11 @@
11#include "list.hpp"11#include "list.hpp"
12#include "buffer.hpp"12#include "buffer.hpp"
13#include "tokenizer.hpp"13#include "tokenizer.hpp"
14#include "errmsg.hpp"
1415
15struct AstNode;16struct AstNode;
16struct CodeGenNode;17struct CodeGenNode;
18struct ImportTableEntry;
1719
18enum NodeType {20enum NodeType {
19 NodeTypeRoot,21 NodeTypeRoot,
...@@ -166,10 +168,10 @@ struct AstNodeUse {...@@ -166,10 +168,10 @@ struct AstNodeUse {
166168
167struct AstNode {169struct AstNode {
168 enum NodeType type;170 enum NodeType type;
169 AstNode *parent;
170 int line;171 int line;
171 int column;172 int column;
172 CodeGenNode *codegen_node;173 CodeGenNode *codegen_node;
174 ImportTableEntry *owner;
173 union {175 union {
174 AstNodeRoot root;176 AstNodeRoot root;
175 AstNodeRootExportDecl root_export_decl;177 AstNodeRootExportDecl root_export_decl;
...@@ -198,7 +200,7 @@ void ast_token_error(Token *token, const char *format, ...);...@@ -198,7 +200,7 @@ void ast_token_error(Token *token, const char *format, ...);
198200
199201
200// This function is provided by generated code, generated by parsergen.cpp202// 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
203const char *node_type_str(NodeType node_type);205const char *node_type_str(NodeType node_type);
204206
src/semantic_info.hpp+13-1
...@@ -11,6 +11,7 @@...@@ -11,6 +11,7 @@
11#include "codegen.hpp"11#include "codegen.hpp"
12#include "hash_map.hpp"12#include "hash_map.hpp"
13#include "zig_llvm.hpp"13#include "zig_llvm.hpp"
14#include "errmsg.hpp"
1415
15struct FnTableEntry;16struct FnTableEntry;
1617
...@@ -30,6 +31,8 @@ struct ImportTableEntry {...@@ -30,6 +31,8 @@ struct ImportTableEntry {
30 AstNode *root;31 AstNode *root;
31 Buf *path; // relative to root_source_dir32 Buf *path; // relative to root_source_dir
32 LLVMZigDIFile *di_file;33 LLVMZigDIFile *di_file;
34 Buf *source_code;
35 ZigList<int> *line_offsets;
3336
34 // reminder: hash tables must be initialized before use37 // reminder: hash tables must be initialized before use
35 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;38 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
...@@ -47,7 +50,7 @@ struct FnTableEntry {...@@ -47,7 +50,7 @@ struct FnTableEntry {
4750
48struct CodeGen {51struct CodeGen {
49 LLVMModuleRef module;52 LLVMModuleRef module;
50 ZigList<ErrorMsg> errors;53 ZigList<ErrorMsg*> errors;
51 LLVMBuilderRef builder;54 LLVMBuilderRef builder;
52 LLVMZigDIBuilder *dbuilder;55 LLVMZigDIBuilder *dbuilder;
53 LLVMZigDICompileUnit *compile_unit;56 LLVMZigDICompileUnit *compile_unit;
...@@ -77,7 +80,14 @@ struct CodeGen {...@@ -77,7 +80,14 @@ struct CodeGen {
77 Buf *root_source_dir;80 Buf *root_source_dir;
78 Buf *root_out_name;81 Buf *root_out_name;
79 ZigList<LLVMZigDIScope *> block_scopes;82 ZigList<LLVMZigDIScope *> block_scopes;
83
84 // The function definitions this module includes. There must be a corresponding
85 // fn_protos entry.
80 ZigList<FnTableEntry *> fn_defs;86 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
81 OutType out_type;91 OutType out_type;
82 FnTableEntry *cur_fn;92 FnTableEntry *cur_fn;
83 bool c_stdint_used;93 bool c_stdint_used;
...@@ -86,6 +96,8 @@ struct CodeGen {...@@ -86,6 +96,8 @@ struct CodeGen {
86 int version_minor;96 int version_minor;
87 int version_patch;97 int version_patch;
88 bool verbose;98 bool verbose;
99 ErrColor err_color;
100 ImportTableEntry *root_import;
89};101};
90102
91struct TypeNode {103struct TypeNode {
src/tokenizer.cpp+26-17
...@@ -104,6 +104,7 @@ enum TokenizeState {...@@ -104,6 +104,7 @@ enum TokenizeState {
104 TokenizeStateBang,104 TokenizeStateBang,
105 TokenizeStateLessThan,105 TokenizeStateLessThan,
106 TokenizeStateGreaterThan,106 TokenizeStateGreaterThan,
107 TokenizeStateError,
107};108};
108109
109110
...@@ -116,27 +117,25 @@ struct Tokenize {...@@ -116,27 +117,25 @@ struct Tokenize {
116 int column;117 int column;
117 Token *cur_tok;118 Token *cur_tok;
118 int multi_line_comment_count;119 int multi_line_comment_count;
120 Tokenization *out;
119};121};
120122
121__attribute__ ((format (printf, 2, 3)))123__attribute__ ((format (printf, 2, 3)))
122static void tokenize_error(Tokenize *t, const char *format, ...) {124static void tokenize_error(Tokenize *t, const char *format, ...) {
123 int line;125 t->state = TokenizeStateError;
124 int column;126
125 if (t->cur_tok) {127 if (t->cur_tok) {
126 line = t->cur_tok->start_line + 1;128 t->out->err_line = t->cur_tok->start_line;
127 column = t->cur_tok->start_column + 1;129 t->out->err_column = t->cur_tok->start_column;
128 } else {130 } else {
129 line = t->line + 1;131 t->out->err_line = t->line;
130 column = t->column + 1;132 t->out->err_column = t->column;
131 }133 }
132134
133 va_list ap;135 va_list ap;
134 va_start(ap, format);136 va_start(ap, format);
135 fprintf(stderr, "Error: Line %d, column %d: ", line, column);137 t->out->err = buf_vprintf(format, ap);
136 vfprintf(stderr, format, ap);
137 fprintf(stderr, "\n");
138 va_end(ap);138 va_end(ap);
139 exit(EXIT_FAILURE);
140}139}
141140
142static void begin_token(Tokenize *t, TokenId id) {141static void begin_token(Tokenize *t, TokenId id) {
...@@ -187,13 +186,20 @@ static void end_token(Tokenize *t) {...@@ -187,13 +186,20 @@ static void end_token(Tokenize *t) {
187 t->cur_tok = nullptr;186 t->cur_tok = nullptr;
188}187}
189188
190ZigList<Token> *tokenize(Buf *buf) {189void tokenize(Buf *buf, Tokenization *out) {
191 Tokenize t = {0};190 Tokenize t = {0};
192 t.tokens = allocate<ZigList<Token>>(1);191 t.out = out;
192 t.tokens = out->tokens = allocate<ZigList<Token>>(1);
193 t.buf = buf;193 t.buf = buf;
194
195 out->line_offsets = allocate<ZigList<int>>(1);
196
197 out->line_offsets->append(0);
194 for (t.pos = 0; t.pos < buf_len(t.buf); t.pos += 1) {198 for (t.pos = 0; t.pos < buf_len(t.buf); t.pos += 1) {
195 uint8_t c = buf_ptr(t.buf)[t.pos];199 uint8_t c = buf_ptr(t.buf)[t.pos];
196 switch (t.state) {200 switch (t.state) {
201 case TokenizeStateError:
202 break;
197 case TokenizeStateStart:203 case TokenizeStateStart:
198 switch (c) {204 switch (c) {
199 case WHITESPACE:205 case WHITESPACE:
...@@ -509,6 +515,7 @@ ZigList<Token> *tokenize(Buf *buf) {...@@ -509,6 +515,7 @@ ZigList<Token> *tokenize(Buf *buf) {
509 break;515 break;
510 }516 }
511 if (c == '\n') {517 if (c == '\n') {
518 out->line_offsets->append(t.pos + 1);
512 t.line += 1;519 t.line += 1;
513 t.column = 0;520 t.column = 0;
514 } else {521 } else {
...@@ -518,6 +525,7 @@ ZigList<Token> *tokenize(Buf *buf) {...@@ -518,6 +525,7 @@ ZigList<Token> *tokenize(Buf *buf) {
518 // EOF525 // EOF
519 switch (t.state) {526 switch (t.state) {
520 case TokenizeStateStart:527 case TokenizeStateStart:
528 case TokenizeStateError:
521 break;529 break;
522 case TokenizeStateString:530 case TokenizeStateString:
523 tokenize_error(&t, "unterminated string");531 tokenize_error(&t, "unterminated string");
...@@ -544,11 +552,12 @@ ZigList<Token> *tokenize(Buf *buf) {...@@ -544,11 +552,12 @@ ZigList<Token> *tokenize(Buf *buf) {
544 tokenize_error(&t, "unterminated multi-line comment");552 tokenize_error(&t, "unterminated multi-line comment");
545 break;553 break;
546 }554 }
547 t.pos = -1;555 if (t.state != TokenizeStateError) {
548 begin_token(&t, TokenIdEof);556 t.pos = -1;
549 end_token(&t);557 begin_token(&t, TokenIdEof);
550 assert(!t.cur_tok);558 end_token(&t);
551 return t.tokens;559 assert(!t.cur_tok);
560 }
552}561}
553562
554static const char * token_name(Token *token) {563static const char * token_name(Token *token) {
src/tokenizer.hpp+11-1
...@@ -65,7 +65,17 @@ struct Token {...@@ -65,7 +65,17 @@ struct Token {
65 int start_column;65 int start_column;
66};66};
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
70void print_tokens(Buf *buf, ZigList<Token> *tokens);80void print_tokens(Buf *buf, ZigList<Token> *tokens);
7181
src/util.hpp-2
...@@ -16,8 +16,6 @@...@@ -16,8 +16,6 @@
1616
17#define BREAKPOINT __asm("int $0x03")17#define BREAKPOINT __asm("int $0x03")
1818
19static const int COMPILE_FAILED_ERR_CODE = 10; // chosen with a random number generator
20
21void zig_panic(const char *format, ...)19void zig_panic(const char *format, ...)
22 __attribute__((cold))20 __attribute__((cold))
23 __attribute__ ((noreturn))21 __attribute__ ((noreturn))
test/run_tests.cpp+88-18
...@@ -14,13 +14,13 @@...@@ -14,13 +14,13 @@
1414
15struct TestSourceFile {15struct TestSourceFile {
16 const char *relative_path;16 const char *relative_path;
17 const char *text;17 const char *source_code;
18};18};
1919
20struct TestCase {20struct TestCase {
21 const char *case_name;21 const char *case_name;
22 const char *output;22 const char *output;
23 const char *source;23 ZigList<TestSourceFile> source_files;
24 ZigList<const char *> compile_errors;24 ZigList<const char *> compile_errors;
25 ZigList<const char *> compiler_args;25 ZigList<const char *> compiler_args;
26 ZigList<const char *> program_args;26 ZigList<const char *> program_args;
...@@ -31,11 +31,20 @@ static const char *tmp_source_path = ".tmp_source.zig";...@@ -31,11 +31,20 @@ static const char *tmp_source_path = ".tmp_source.zig";
31static const char *tmp_exe_path = "./.tmp_exe";31static const char *tmp_exe_path = "./.tmp_exe";
32static const char *zig_exe = "./zig";32static 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) {
35 TestCase *test_case = allocate<TestCase>(1);41 TestCase *test_case = allocate<TestCase>(1);
36 test_case->case_name = case_name;42 test_case->case_name = case_name;
37 test_case->output = output;43 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
40 test_case->compiler_args.append("build");49 test_case->compiler_args.append("build");
41 test_case->compiler_args.append(tmp_source_path);50 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...@@ -48,17 +57,23 @@ static void add_simple_case(const char *case_name, const char *source, const cha
48 test_case->compiler_args.append("--release");57 test_case->compiler_args.append("--release");
49 test_case->compiler_args.append("--strip");58 test_case->compiler_args.append("--strip");
50 test_case->compiler_args.append("--verbose");59 test_case->compiler_args.append("--verbose");
60 test_case->compiler_args.append("--color");
61 test_case->compiler_args.append("on");
5162
52 test_cases.append(test_case);63 test_cases.append(test_case);
64
65 return test_case;
53}66}
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, ...) {
56 va_list ap;69 va_list ap;
57 va_start(ap, count);70 va_start(ap, count);
5871
59 TestCase *test_case = allocate<TestCase>(1);72 TestCase *test_case = allocate<TestCase>(1);
60 test_case->case_name = case_name;73 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
63 for (int i = 0; i < count; i += 1) {78 for (int i = 0; i < count; i += 1) {
64 const char *arg = va_arg(ap, const char *);79 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...@@ -76,6 +91,8 @@ static void add_compile_fail_case(const char *case_name, const char *source, int
76 test_cases.append(test_case);91 test_cases.append(test_case);
7792
78 va_end(ap);93 va_end(ap);
94
95 return test_case;
79}96}
8097
81static void add_compiling_test_cases(void) {98static void add_compiling_test_cases(void) {
...@@ -133,13 +150,52 @@ static void add_compiling_test_cases(void) {...@@ -133,13 +150,52 @@ static void add_compiling_test_cases(void) {
133 exit(0);150 exit(0);
134 }151 }
135 )SOURCE", "OK\n");152 )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
136}192}
137193
138static void add_compile_failure_test_cases(void) {194static void add_compile_failure_test_cases(void) {
139 add_compile_fail_case("multiple function definitions", R"SOURCE(195 add_compile_fail_case("multiple function definitions", R"SOURCE(
140fn a() {}196fn a() {}
141fn a() {}197fn a() {}
142 )SOURCE", 1, "Line 3, column 1: redefinition of 'a'");198 )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'a'");
143199
144 add_compile_fail_case("bad directive", R"SOURCE(200 add_compile_fail_case("bad directive", R"SOURCE(
145#bogus1("")201#bogus1("")
...@@ -148,37 +204,37 @@ extern {...@@ -148,37 +204,37 @@ extern {
148}204}
149#bogus2("")205#bogus2("")
150fn a() {}206fn a() {}
151 )SOURCE", 2, "Line 2, column 1: invalid directive: 'bogus1'",207 )SOURCE", 2, ".tmp_source.zig:2:1: error: invalid directive: 'bogus1'",
152 "Line 6, column 1: invalid directive: 'bogus2'");208 ".tmp_source.zig:6:1: error: invalid directive: 'bogus2'");
153209
154 add_compile_fail_case("unreachable with return", R"SOURCE(210 add_compile_fail_case("unreachable with return", R"SOURCE(
155fn a() -> unreachable {return;}211fn 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
158 add_compile_fail_case("control reaches end of non-void function", R"SOURCE(214 add_compile_fail_case("control reaches end of non-void function", R"SOURCE(
159fn a() -> i32 {}215fn 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
162 add_compile_fail_case("undefined function call", R"SOURCE(218 add_compile_fail_case("undefined function call", R"SOURCE(
163fn a() {219fn a() {
164 b();220 b();
165}221}
166 )SOURCE", 1, "Line 3, column 5: undefined function: 'b'");222 )SOURCE", 1, ".tmp_source.zig:3:5: error: undefined function: 'b'");
167223
168 add_compile_fail_case("wrong number of arguments", R"SOURCE(224 add_compile_fail_case("wrong number of arguments", R"SOURCE(
169fn a() {225fn a() {
170 b(1);226 b(1);
171}227}
172fn b(a: i32, b: i32, c: i32) { }228fn 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
175 add_compile_fail_case("invalid type", R"SOURCE(231 add_compile_fail_case("invalid type", R"SOURCE(
176fn a() -> bogus {}232fn 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
179 add_compile_fail_case("pointer to unreachable", R"SOURCE(235 add_compile_fail_case("pointer to unreachable", R"SOURCE(
180fn a() -> *mut unreachable {}236fn 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
183 add_compile_fail_case("unreachable code", R"SOURCE(239 add_compile_fail_case("unreachable code", R"SOURCE(
184fn a() {240fn a() {
...@@ -187,12 +243,16 @@ fn a() {...@@ -187,12 +243,16 @@ fn a() {
187}243}
188244
189fn b() {}245fn b() {}
190 )SOURCE", 1, "Line 4, column 5: unreachable code");246 )SOURCE", 1, ".tmp_source.zig:4:5: error: unreachable code");
191247
192 add_compile_fail_case("bad version string", R"SOURCE(248 add_compile_fail_case("bad version string", R"SOURCE(
193#version("aoeu")249#version("aoeu")
194export executable "test";250export 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");
196}256}
197257
198static void print_compiler_invokation(TestCase *test_case, Buf *zig_stderr) {258static 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) {...@@ -205,7 +265,12 @@ static void print_compiler_invokation(TestCase *test_case, Buf *zig_stderr) {
205}265}
206266
207static void run_test(TestCase *test_case) {267static 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
210 Buf zig_stderr = BUF_INIT;275 Buf zig_stderr = BUF_INIT;
211 Buf zig_stdout = BUF_INIT;276 Buf zig_stdout = BUF_INIT;
...@@ -263,6 +328,11 @@ static void run_test(TestCase *test_case) {...@@ -263,6 +328,11 @@ static void run_test(TestCase *test_case) {
263 printf("=======================================\n");328 printf("=======================================\n");
264 exit(1);329 exit(1);
265 }330 }
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 }
266}336}
267337
268static void run_all_tests(void) {338static void run_all_tests(void) {