authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-27 18:55:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-27 18:55:06-07:00
log4cc95174a77f7cbb42b371bb892c55a8349bc7fa
treeb147a81dc7630c5c0dc4686c3ad7705cd0dd0e01
parent4068897b6b167569718c61efcb4371693fe89b74

add tests for compile errors


5 files changed, 147 insertions(+), 15 deletions(-)

README.md+5-1
...@@ -32,11 +32,15 @@ readable, safe, optimal, and concise code to solve any computing problem....@@ -32,11 +32,15 @@ readable, safe, optimal, and concise code to solve any computing problem.
3232
33## Roadmap33## Roadmap
3434
35 * test framework to test for compile errors
36 * Simple .so library35 * Simple .so library
37 * Multiple files36 * Multiple files
38 * inline assembly and syscalls37 * inline assembly and syscalls
39 * running code at compile time38 * running code at compile time
39 * print! macro that takes var args
40 * panic! macro that prints a stack trace to stderr in debug mode and calls
41 abort() in release mode
42 * unreachable codegen to panic("unreachable") in debug mode, and nothing in
43 release mode
40 * implement a simple game using SDL244 * implement a simple game using SDL2
41 * How should the Widget use case be solved? In Genesis I'm using C++ and inheritance.45 * How should the Widget use case be solved? In Genesis I'm using C++ and inheritance.
4246
doc/vim/syntax/zig.vim+3-1
...@@ -1,14 +1,16 @@...@@ -1,14 +1,16 @@
1" Vim syntax file1" Vim syntax file
2" Language: Zig2" Language: Zig
3" Maintainer: Andrew Kelley3" Maintainer: Andrew Kelley
4" Latest Revision: 24 November 20154" Latest Revision: 27 November 2015
55
6if exists("b:current_syntax")6if exists("b:current_syntax")
7 finish7 finish
8endif8endif
99
10syn keyword zigKeyword fn return mut const extern unreachable export pub10syn keyword zigKeyword fn return mut const extern unreachable export pub
11syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void
1112
12let b:current_syntax = "zig"13let b:current_syntax = "zig"
1314
14hi def link zigKeyword Keyword15hi def link zigKeyword Keyword
16hi def link zigType Type
src/codegen.cpp+18-1
...@@ -83,6 +83,7 @@ struct TypeNode {...@@ -83,6 +83,7 @@ struct TypeNode {
8383
84struct FnDefNode {84struct FnDefNode {
85 bool add_implicit_return;85 bool add_implicit_return;
86 bool skip;
86};87};
8788
88struct CodeGenNode {89struct CodeGenNode {
...@@ -214,7 +215,7 @@ static void find_declarations(CodeGen *g, AstNode *node) {...@@ -214,7 +215,7 @@ static void find_declarations(CodeGen *g, AstNode *node) {
214 if (buf_eql_str(name, "link")) {215 if (buf_eql_str(name, "link")) {
215 g->link_table.put(param, true);216 g->link_table.put(param, true);
216 } else {217 } else {
217 add_node_error(g, node,218 add_node_error(g, directive_node,
218 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));219 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
219 }220 }
220 }221 }
...@@ -242,6 +243,9 @@ static void find_declarations(CodeGen *g, AstNode *node) {...@@ -242,6 +243,9 @@ static void find_declarations(CodeGen *g, AstNode *node) {
242 if (entry) {243 if (entry) {
243 add_node_error(g, node,244 add_node_error(g, node,
244 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));245 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
246 assert(!node->codegen_node);
247 node->codegen_node = allocate<CodeGenNode>(1);
248 node->codegen_node->data.fn_def_node.skip = true;
245 } else {249 } else {
246 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);250 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
247 fn_table_entry->proto_node = proto_node;251 fn_table_entry->proto_node = proto_node;
...@@ -261,6 +265,12 @@ static void find_declarations(CodeGen *g, AstNode *node) {...@@ -261,6 +265,12 @@ static void find_declarations(CodeGen *g, AstNode *node) {
261 }265 }
262 case NodeTypeFnProto:266 case NodeTypeFnProto:
263 {267 {
268 for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {
269 AstNode *directive_node = node->data.fn_proto.directives->at(i);
270 Buf *name = &directive_node->data.directive.name;
271 add_node_error(g, directive_node,
272 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
273 }
264 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {274 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
265 AstNode *child = node->data.fn_proto.params.at(i);275 AstNode *child = node->data.fn_proto.params.at(i);
266 find_declarations(g, child);276 find_declarations(g, child);
...@@ -363,11 +373,18 @@ static void analyze_node(CodeGen *g, AstNode *node) {...@@ -363,11 +373,18 @@ static void analyze_node(CodeGen *g, AstNode *node) {
363 break;373 break;
364 case NodeTypeFnDef:374 case NodeTypeFnDef:
365 {375 {
376 if (node->codegen_node && node->codegen_node->data.fn_def_node.skip) {
377 // we detected an error with this function definition which prevents us
378 // from further analyzing it.
379 break;
380 }
381
366 AstNode *proto_node = node->data.fn_def.fn_proto;382 AstNode *proto_node = node->data.fn_def.fn_proto;
367 assert(proto_node->type == NodeTypeFnProto);383 assert(proto_node->type == NodeTypeFnProto);
368 analyze_node(g, proto_node);384 analyze_node(g, proto_node);
369385
370 check_fn_def_control_flow(g, node);386 check_fn_def_control_flow(g, node);
387 analyze_node(g, node->data.fn_def.body);
371 break;388 break;
372 }389 }
373 case NodeTypeFnDecl:390 case NodeTypeFnDecl:
src/util.hpp+2
...@@ -16,6 +16,8 @@...@@ -16,6 +16,8 @@
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
19void zig_panic(const char *format, ...)21void zig_panic(const char *format, ...)
20 __attribute__((cold))22 __attribute__((cold))
21 __attribute__ ((noreturn))23 __attribute__ ((noreturn))
test/run_tests.cpp+119-12
...@@ -10,6 +10,7 @@...@@ -10,6 +10,7 @@
10#include "os.hpp"10#include "os.hpp"
1111
12#include <stdio.h>12#include <stdio.h>
13#include <stdarg.h>
1314
14struct TestSourceFile {15struct TestSourceFile {
15 const char *relative_path;16 const char *relative_path;
...@@ -25,9 +26,10 @@ struct TestCase {...@@ -25,9 +26,10 @@ struct TestCase {
25 ZigList<const char *> program_args;26 ZigList<const char *> program_args;
26};27};
2728
28ZigList<TestCase*> test_cases = {0};29static ZigList<TestCase*> test_cases = {0};
29const char *tmp_source_path = ".tmp_source.zig";30static const char *tmp_source_path = ".tmp_source.zig";
30const char *tmp_exe_path = "./.tmp_exe";31static const char *tmp_exe_path = "./.tmp_exe";
32static const char *zig_exe = "./zig";
3133
32static void add_simple_case(const char *case_name, const char *source, const char *output) {34static void add_simple_case(const char *case_name, const char *source, const char *output) {
33 TestCase *test_case = allocate<TestCase>(1);35 TestCase *test_case = allocate<TestCase>(1);
...@@ -45,7 +47,32 @@ static void add_simple_case(const char *case_name, const char *source, const cha...@@ -45,7 +47,32 @@ static void add_simple_case(const char *case_name, const char *source, const cha
45 test_cases.append(test_case);47 test_cases.append(test_case);
46}48}
4749
48static void add_all_test_cases(void) {50static void add_compile_fail_case(const char *case_name, const char *source, int count, ...) {
51 va_list ap;
52 va_start(ap, count);
53
54 TestCase *test_case = allocate<TestCase>(1);
55 test_case->case_name = case_name;
56 test_case->source = source;
57
58 for (int i = 0; i < count; i += 1) {
59 const char *arg = va_arg(ap, const char *);
60 test_case->compile_errors.append(arg);
61 }
62
63 test_case->compiler_args.append("build");
64 test_case->compiler_args.append(tmp_source_path);
65 test_case->compiler_args.append("--output");
66 test_case->compiler_args.append(tmp_exe_path);
67 test_case->compiler_args.append("--release");
68 test_case->compiler_args.append("--strip");
69
70 test_cases.append(test_case);
71
72 va_end(ap);
73}
74
75static void add_compiling_test_cases(void) {
49 add_simple_case("hello world with libc", R"SOURCE(76 add_simple_case("hello world with libc", R"SOURCE(
50 #link("c")77 #link("c")
51 extern {78 extern {
...@@ -102,23 +129,102 @@ static void add_all_test_cases(void) {...@@ -102,23 +129,102 @@ static void add_all_test_cases(void) {
102 )SOURCE", "OK\n");129 )SOURCE", "OK\n");
103}130}
104131
132static void add_compile_failure_test_cases(void) {
133 add_compile_fail_case("multiple function definitions", R"SOURCE(
134fn a() {}
135fn a() {}
136 )SOURCE", 1, "Line 3, column 1: redefinition of 'a'");
137
138 add_compile_fail_case("bad directive", R"SOURCE(
139#bogus1("")
140extern {
141 fn b();
142}
143#bogus2("")
144fn a() {}
145 )SOURCE", 2, "Line 2, column 1: invalid directive: 'bogus1'",
146 "Line 6, column 1: invalid directive: 'bogus2'");
147
148 add_compile_fail_case("unreachable with return", R"SOURCE(
149fn a() -> unreachable {return;}
150 )SOURCE", 1, "Line 2, column 24: return statement in function with unreachable return type");
151
152 add_compile_fail_case("control reaches end of non-void function", R"SOURCE(
153fn a() -> i32 {}
154 )SOURCE", 1, "Line 2, column 1: control reaches end of non-void function");
155
156 add_compile_fail_case("undefined function call", R"SOURCE(
157fn a() {
158 b();
159}
160 )SOURCE", 1, "Line 3, column 5: undefined function: 'b'");
161
162 add_compile_fail_case("wrong number of arguments", R"SOURCE(
163fn a() {
164 b(1);
165}
166fn b(a: i32, b: i32, c: i32) { }
167 )SOURCE", 1, "Line 3, column 5: wrong number of arguments. Expected 3, got 1.");
168
169 add_compile_fail_case("invalid type", R"SOURCE(
170fn a() -> bogus {}
171 )SOURCE", 1, "Line 2, column 11: invalid type name: 'bogus'");
172
173 add_compile_fail_case("pointer to unreachable", R"SOURCE(
174fn a() -> *mut unreachable {}
175 )SOURCE", 1, "Line 2, column 11: pointer to unreachable not allowed");
176
177 add_compile_fail_case("unreachable code", R"SOURCE(
178fn a() {
179 return;
180 b();
181}
182
183fn b() {}
184 )SOURCE", 1, "Line 4, column 5: unreachable code");
185}
186
187static void print_compiler_invokation(TestCase *test_case, Buf *zig_stderr) {
188 printf("%s", zig_exe);
189 for (int i = 0; i < test_case->compiler_args.length; i += 1) {
190 printf(" %s", test_case->compiler_args.at(i));
191 }
192 printf("\n");
193 printf("%s\n", buf_ptr(zig_stderr));
194}
195
105static void run_test(TestCase *test_case) {196static void run_test(TestCase *test_case) {
106 os_write_file(buf_create_from_str(tmp_source_path), buf_create_from_str(test_case->source));197 os_write_file(buf_create_from_str(tmp_source_path), buf_create_from_str(test_case->source));
107198
108 Buf zig_stderr = BUF_INIT;199 Buf zig_stderr = BUF_INIT;
109 Buf zig_stdout = BUF_INIT;200 Buf zig_stdout = BUF_INIT;
110 int return_code;201 int return_code;
111 static const char *zig_exe = "./zig";
112 os_exec_process(zig_exe, test_case->compiler_args, &return_code, &zig_stderr, &zig_stdout);202 os_exec_process(zig_exe, test_case->compiler_args, &return_code, &zig_stderr, &zig_stdout);
113203
204 if (test_case->compile_errors.length) {
205 if (return_code) {
206 for (int i = 0; i < test_case->compile_errors.length; i += 1) {
207 const char *err_text = test_case->compile_errors.at(i);
208 if (!strstr(buf_ptr(&zig_stderr), err_text)) {
209 printf("\n");
210 printf("========= Expected this compile error: =========\n");
211 printf("%s\n", err_text);
212 printf("================================================\n");
213 print_compiler_invokation(test_case, &zig_stderr);
214 exit(1);
215 }
216 }
217 return; // success
218 } else {
219 printf("\nCompile failed with return code 0 (Expected failure):\n");
220 print_compiler_invokation(test_case, &zig_stderr);
221 exit(1);
222 }
223 }
224
114 if (return_code != 0) {225 if (return_code != 0) {
115 printf("\nCompile failed with return code %d:\n", return_code);226 printf("\nCompile failed with return code %d:\n", return_code);
116 printf("%s", zig_exe);227 print_compiler_invokation(test_case, &zig_stderr);
117 for (int i = 0; i < test_case->compiler_args.length; i += 1) {
118 printf(" %s", test_case->compiler_args.at(i));
119 }
120 printf("\n");
121 printf("%s\n", buf_ptr(&zig_stderr));
122 exit(1);228 exit(1);
123 }229 }
124230
...@@ -164,7 +270,8 @@ static void cleanup(void) {...@@ -164,7 +270,8 @@ static void cleanup(void) {
164}270}
165271
166int main(int argc, char **argv) {272int main(int argc, char **argv) {
167 add_all_test_cases();273 add_compiling_test_cases();
274 add_compile_failure_test_cases();
168 run_all_tests();275 run_all_tests();
169 cleanup();276 cleanup();
170}277}