diff --git a/ast/ast_evaluator.c2 b/ast/ast_evaluator.c2 index c24f19411..df854eeb5 100644 --- a/ast/ast_evaluator.c2 +++ b/ast/ast_evaluator.c2 @@ -408,7 +408,7 @@ fn Value Evaluator.eval_call(Evaluator* caller, const CallExpr* c) { // Create a new stack frame and link it to the caller's // TODO: handle Stack frames as separate allocated objects or fragments of a stack area - Evaluator eval; + Evaluator eval /*@(noinit)*/; if (num_args > elemsof(eval.args)) { return Value.error("too many arguments in pure function evaluation"); diff --git a/ast/var_decl.c2 b/ast/var_decl.c2 index 708e30123..a311540be 100644 --- a/ast/var_decl.c2 +++ b/ast/var_decl.c2 @@ -52,6 +52,7 @@ type VarDeclBits struct { AutoAttr auto_attr : 2; // for parameters only FormatAttr format_attr : 2; // for parameters only u32 is_tlocal : 1; // local or global variables with thread local storage + u32 attr_noinit : 1; } public type BitFieldLayout struct { @@ -315,6 +316,14 @@ public fn bool VarDecl.hasInitCall(const VarDecl* d) { return d.base.varDeclBits.has_init_call; } +public fn void VarDecl.setAttrNoInit(VarDecl* d) { + d.base.varDeclBits.attr_noinit = 1; +} + +public fn bool VarDecl.hasAttrNoInit(const VarDecl* d) { + return d.base.varDeclBits.attr_noinit; +} + public fn void VarDecl.setAttrWeak(VarDecl* d) { d.base.declBits.has_attr = 1; d.base.varDeclBits.attr_weak = 1; diff --git a/ast_utils/attr.c2 b/ast_utils/attr.c2 index c9116ab2c..cfb1a6f4b 100644 --- a/ast_utils/attr.c2 +++ b/ast_utils/attr.c2 @@ -44,6 +44,7 @@ public type AttrKind enum u8 (const char* const name, const AttrReq required_arg AutoFunc : { "auto_func", NoArg }, // Var, function param only Embed : { "embed", String }, // Var, globals only Deprecated : { "deprecated", String }, // Func + NoInit : { "noinit", NoArg }, // Var } public type AttrValueKind enum u8 { diff --git a/ast_utils/string_buffer.c2 b/ast_utils/string_buffer.c2 index 387aaf60d..6beb4edfe 100644 --- a/ast_utils/string_buffer.c2 +++ b/ast_utils/string_buffer.c2 @@ -169,7 +169,7 @@ public fn void Buf.stripTrailingSpaces(Buf* buf) { } public fn void Buf.print(Buf* buf, const char* format @(printf_format), ...) { - char[4096] tmp; + char[4096] tmp /*@(noinit)*/; // NOTE: no growing va_list args; va_start(args, format); @@ -180,7 +180,7 @@ public fn void Buf.print(Buf* buf, const char* format @(printf_format), ...) { } public fn void Buf.vprintf(Buf* buf, const char* format, va_list args) { - char[4096] tmp; + char[4096] tmp /*@(noinit)*/; // NOTE: no growing i32 len = vsnprintf(tmp, elemsof(tmp), format, args); assert(len < elemsof(tmp)); diff --git a/ast_utils/value_type.c2 b/ast_utils/value_type.c2 index 5c7f88d53..c57c83ce0 100644 --- a/ast_utils/value_type.c2 +++ b/ast_utils/value_type.c2 @@ -824,7 +824,7 @@ fn f64 fabs(f64 d) { // string and trying to avoid using exponential notation // TODO: should be in the C2 library as a type function f64.str() public fn char *ftoa(char *dest, usize size, f64 d) { - char[32] buf; + char[32] buf /*@(noinit)*/; usize pos = 0; if (size < 2) { diff --git a/common/ast_builder.c2 b/common/ast_builder.c2 index a2ab02ee2..c9fc67d04 100644 --- a/common/ast_builder.c2 +++ b/common/ast_builder.c2 @@ -660,6 +660,9 @@ fn void Builder.actOnVarAttr(Builder* b, Decl* d, const Attr* a) { if (!d.isPublic()) b.diags.error(a.loc, "weak declarations must be public"); vd.setAttrWeak(); break; + case NoInit: + vd.setAttrNoInit(); + break; default: b.diags.error(a.loc, "attribute '%s' is not applicable to variables", a.kind2name()); diff --git a/common/file/file_utils.c2 b/common/file/file_utils.c2 index 159173775..feb133f61 100644 --- a/common/file/file_utils.c2 +++ b/common/file/file_utils.c2 @@ -101,7 +101,7 @@ public fn const char* make_path3(char *buf, usize size, const char* dir, const c // returns 0 on success, errno on failure // create a directory path, OK if exists already public fn i32 create_path(const char* path) { - char[file_utils.Max_path] tmp; + char[file_utils.Max_path] tmp /*@(noinit)*/; char *p = tmp; if (!*path) return 0; *p++ = *path++; diff --git a/generator/c/c_generator_special.c2 b/generator/c/c_generator_special.c2 index 49939c8d3..90046b3e8 100644 --- a/generator/c/c_generator_special.c2 +++ b/generator/c/c_generator_special.c2 @@ -59,7 +59,7 @@ fn void Generator.createMakefile(Generator* gen, out.print("CC?=%s\n", cc); out.add("CFLAGS+=-Wall -Wextra -Wno-unused -Wno-switch\n"); - out.add("CFLAGS+=-Wno-unused-parameter -Wno-missing-field-initializers -Wno-format-zero-length\n"); + out.add("CFLAGS+=-Wno-unused-parameter -Wno-missing-field-initializers -Wno-missing-braces -Wno-format-zero-length\n"); out.add("CFLAGS+=-pipe -std=c99 -funsigned-char\n"); if (gen.fast_build) out.add("CFLAGS+=-O0 -g\n"); diff --git a/generator/c/c_generator_stmt.c2 b/generator/c/c_generator_stmt.c2 index d277b5857..6438c6a09 100644 --- a/generator/c/c_generator_stmt.c2 +++ b/generator/c/c_generator_stmt.c2 @@ -39,6 +39,10 @@ fn void Generator.emitVarDecl(Generator* gen, VarDecl* vd, string_buffer.Buf* ou out.add(" = "); } gen.emitExpr(out, ie); + } else { + if (!vd.hasAttrNoInit()) { + out.add(" = { 0 }"); + } } } diff --git a/parser/c2_parser.c2 b/parser/c2_parser.c2 index 22e8673da..1d261c292 100644 --- a/parser/c2_parser.c2 +++ b/parser/c2_parser.c2 @@ -447,6 +447,10 @@ fn bool findName(const u32* names, u32 count, u32 name) { // returns the number of attributes parsed and stored in Builder fn u32 Parser.parseOptionalAttributes(Parser* p) { if (p.tok.kind != At) return 0; + return p.parseAttributes(); +} + +fn u32 Parser.parseAttributes(Parser* p) { p.consumeToken(); p.expectAndConsume(LParen); diff --git a/parser/c2_parser_stmt.c2 b/parser/c2_parser_stmt.c2 index d7a107c4b..f39a8deea 100644 --- a/parser/c2_parser_stmt.c2 +++ b/parser/c2_parser_stmt.c2 @@ -21,6 +21,7 @@ import constants local; import token local; import src_loc local; import string_list; +import string local; import ctype; @@ -531,7 +532,7 @@ fn Stmt* Parser.parseWhileStmt(Parser* p) { } fn Stmt* Parser.parseDeclStmt(Parser* p, bool checkSemi, bool allowLocal, bool isCondition) { - VarDecl*[MaxMultiDecl] decls; + VarDecl*[MaxMultiDecl] decls /*@(noinit)*/; u32 num_decls = 0; bool is_static = p.tok.kind == KW_static; bool has_tlocal = (p.tok.kind == KW_tlocal); @@ -556,6 +557,7 @@ fn Stmt* Parser.parseDeclStmt(Parser* p, bool checkSemi, bool allowLocal, bool i p.consumeToken(); // TODO same as parseVarDecl() + bool has_noinit = false; bool has_init_call = false; need_semi = true; Expr* initValue = nil; @@ -570,7 +572,14 @@ fn Stmt* Parser.parseDeclStmt(Parser* p, bool checkSemi, bool allowLocal, bool i need_semi = checkSemi && initValue.needsSemi(); break; case At: - p.error("local variables cannot have attributes"); + // check for noinit attribute + p.consumeToken(); + p.expectAndConsume(Kind.LParen); + p.expectIdentifier(); + if (strcmp(p.pool.idx2str(p.tok.name_idx), "noinit")) + p.error("local variables cannot have attributes"); + has_noinit = true; + p.expectAndConsume(Kind.RParen); break; case Dot: if (p.peekToken(1) == Identifier @@ -600,6 +609,7 @@ fn Stmt* Parser.parseDeclStmt(Parser* p, bool checkSemi, bool allowLocal, bool i } VarDecl* vd = p.builder.actOnVarDecl(name, loc, &ref, assignLoc, initValue, is_static, has_init_call); if (has_tlocal) vd.setTLocal(); + if (has_noinit) vd.setAttrNoInit(); decls[num_decls++] = vd; if (p.tok.kind != Comma) break; diff --git a/parser/c2_tokenizer.c2 b/parser/c2_tokenizer.c2 index e3f6da760..e68467ec4 100644 --- a/parser/c2_tokenizer.c2 +++ b/parser/c2_tokenizer.c2 @@ -886,7 +886,7 @@ check_overflow: } fn void Tokenizer.lex_floating_point(Tokenizer* t, Token* result, const char* start) { - char[4096] buf; + char[128] buf /*@(noinit)*/; const char* p = start; usize pos = 0; u8 seen_dot = 0; @@ -941,7 +941,7 @@ too_large: } fn void Tokenizer.lex_floating_point_hex(Tokenizer* t, Token* result, const char* start) { - char[4096] buf; + char[128] buf /*@(noinit)*/; const char* p = start; usize pos = 0; u8 seen_dot = 0; diff --git a/test/auto_args/struct_function_before_self.c2t b/test/auto_args/struct_function_before_self.c2t index 68437bc78..f209a3e02 100644 --- a/test/auto_args/struct_function_before_self.c2t +++ b/test/auto_args/struct_function_before_self.c2t @@ -27,7 +27,7 @@ static void test_Foo_test(const char* file, u32 line, test_Foo* f, void* p) int main(void) { - test_Foo f; + test_Foo f = { 0 }; test_Foo_test("file1.c2", 11, &f, NULL); return 0; } diff --git a/test/auto_args/struct_function_ok.c2t b/test/auto_args/struct_function_ok.c2t index 413d774bf..238bcfbfb 100644 --- a/test/auto_args/struct_function_ok.c2t +++ b/test/auto_args/struct_function_ok.c2t @@ -27,7 +27,7 @@ static void test_Foo_test(test_Foo* f, const char* file, u32 line, void* p) int main(void) { - test_Foo f; + test_Foo f = { 0 }; test_Foo_test(&f, "file1.c2", 11, NULL); test_Foo_test(&f, "file1.c2", 12, NULL); return 0; diff --git a/test/c_generator/asm/gen_asm.c2t b/test/c_generator/asm/gen_asm.c2t index 946d30991..2c2061f5a 100644 --- a/test/c_generator/asm/gen_asm.c2t +++ b/test/c_generator/asm/gen_asm.c2t @@ -48,16 +48,16 @@ static void test_basic_asm(void); static int test_add(int x, int y) { - int result; + int result = { 0 }; __asm__ volatile ("add %[Rd], %[Rm], %[Rn]" : [Rd] "=r" (result) : [Rm] "r" (x), [Rn] "r" (y)); return result; } static void test_clobbers(void) { - int from; - int to; - int count; + int from = { 0 }; + int to = { 0 }; + int count = { 0 }; __asm__ volatile ("movc3 %0, %1, %2" : : "g" (from), "g" (to), "g" (count) @@ -67,8 +67,8 @@ static void test_clobbers(void) static inline u64 test_rdtsc(void) { - u32 lo; - u32 hi; + u32 lo = { 0 }; + u32 hi = { 0 }; __asm__ volatile ("rdtsc" : "=a" (lo), "=d" (hi)); u64 res = hi; res <<= 32; diff --git a/test/c_generator/expr/prec_expr.c2t b/test/c_generator/expr/prec_expr.c2t index 77afeee57..4dd2ab264 100644 --- a/test/c_generator/expr/prec_expr.c2t +++ b/test/c_generator/expr/prec_expr.c2t @@ -30,7 +30,7 @@ public fn i32 main(i32 argc, const char** argv) { int main(int argc, const char** argv) { - int a; + int a = { 0 }; a = (1 << 2) + 3; a = ((1 ^ 2) | 3) & 4; diff --git a/test/c_generator/functions/inline/inline_prefix.c2t b/test/c_generator/functions/inline/inline_prefix.c2t index 95cb2f710..af7849e3c 100644 --- a/test/c_generator/functions/inline/inline_prefix.c2t +++ b/test/c_generator/functions/inline/inline_prefix.c2t @@ -47,7 +47,7 @@ type Point struct { static inline void test1_myfunc(const test2_Point* p) { - test2_Point points[3]; + test2_Point points[3] = { 0 }; points[1] = *p; } diff --git a/test/c_generator/functions/inline/inline_stmts.c2t b/test/c_generator/functions/inline/inline_stmts.c2t index 00038dd8b..1d49ab01b 100644 --- a/test/c_generator/functions/inline/inline_stmts.c2t +++ b/test/c_generator/functions/inline/inline_stmts.c2t @@ -114,7 +114,7 @@ next: static inline int test1_test_fn(const char* format, ...) { - const char* p; + const char* p = { 0 }; { const char* q = format; if (q) { @@ -137,7 +137,7 @@ int test1_test_fn(const char* format, ...) if (format) p = format; else p = format; { - const char* q; + const char* q = { 0 }; while ((q = format)) { } } diff --git a/test/c_generator/functions/inline/lib_public_inline.c2t b/test/c_generator/functions/inline/lib_public_inline.c2t index 431e2ac27..eefa1c44c 100644 --- a/test/c_generator/functions/inline/lib_public_inline.c2t +++ b/test/c_generator/functions/inline/lib_public_inline.c2t @@ -41,7 +41,7 @@ typedef void (*test1_Handler)(int* _arg0); static inline int test1_test_fn(test1_Handler a, int** b) { - int c[4]; + int c[4] = { 0 }; a(*b); return 123; } diff --git a/test/c_generator/functions/inline/nonpublic_inline.c2t b/test/c_generator/functions/inline/nonpublic_inline.c2t index 18c6a03fb..5883aceed 100644 --- a/test/c_generator/functions/inline/nonpublic_inline.c2t +++ b/test/c_generator/functions/inline/nonpublic_inline.c2t @@ -42,6 +42,6 @@ void test1_test_fn(void) { test1_non_public(); test1_num++; - test1_Priv p; + test1_Priv p = { 0 }; test1_Handler h = test1_non_public; } diff --git a/test/c_generator/functions/struct_functions/chained_struct_calls.c2t b/test/c_generator/functions/struct_functions/chained_struct_calls.c2t index 449906fa0..053c69224 100644 --- a/test/c_generator/functions/struct_functions/chained_struct_calls.c2t +++ b/test/c_generator/functions/struct_functions/chained_struct_calls.c2t @@ -73,7 +73,7 @@ static test_B* test_C_getB(test_C* c) static void test_test1(void) { - test_C c; + test_C c = { 0 }; u32 n = test_A_run(test_B_getA(test_C_getB(&c))); } diff --git a/test/c_generator/functions/struct_functions/local.c2t b/test/c_generator/functions/struct_functions/local.c2t index a879cda42..8403b8ce3 100644 --- a/test/c_generator/functions/struct_functions/local.c2t +++ b/test/c_generator/functions/struct_functions/local.c2t @@ -33,7 +33,7 @@ static void test_Type_init(test_Type* _arg0) int main(void) { - test_Type t; + test_Type t = { 0 }; test_Type_init(&t); return 0; } diff --git a/test/c_generator/functions/struct_functions/local_arg.c2t b/test/c_generator/functions/struct_functions/local_arg.c2t index 59e64c320..cfb66ad3a 100644 --- a/test/c_generator/functions/struct_functions/local_arg.c2t +++ b/test/c_generator/functions/struct_functions/local_arg.c2t @@ -33,7 +33,7 @@ static void test_Type_init(test_Type* _arg0, int _arg1) int main(void) { - test_Type t; + test_Type t = { 0 }; test_Type_init(&t, 4); return 0; } diff --git a/test/c_generator/functions/struct_functions/local_member.c2t b/test/c_generator/functions/struct_functions/local_member.c2t index 8cac42351..da987dbac 100644 --- a/test/c_generator/functions/struct_functions/local_member.c2t +++ b/test/c_generator/functions/struct_functions/local_member.c2t @@ -31,7 +31,7 @@ static void test_Type_init(test_Type* _arg0) int main(void) { - test_Outer o; + test_Outer o = { 0 }; test_Type_init(&o.t); return 0; } diff --git a/test/c_generator/functions/struct_functions/local_normal_callback.c2t b/test/c_generator/functions/struct_functions/local_normal_callback.c2t index 3b81ca9c4..a48948490 100644 --- a/test/c_generator/functions/struct_functions/local_normal_callback.c2t +++ b/test/c_generator/functions/struct_functions/local_normal_callback.c2t @@ -28,7 +28,7 @@ struct test_Type_ { int main(void) { - test_Type t; + test_Type t = { 0 }; t.init(1); return 0; } diff --git a/test/c_generator/functions/struct_functions/local_ptr.c2t b/test/c_generator/functions/struct_functions/local_ptr.c2t index 455079994..f76d587e1 100644 --- a/test/c_generator/functions/struct_functions/local_ptr.c2t +++ b/test/c_generator/functions/struct_functions/local_ptr.c2t @@ -33,7 +33,7 @@ static void test_Type_init(test_Type* _arg0) int main(void) { - test_Type* t; + test_Type* t = { 0 }; test_Type_init(t); return 0; } diff --git a/test/c_generator/stmts/local_array_decl.c2t b/test/c_generator/stmts/local_array_decl.c2t index d8c43522d..4adb76596 100644 --- a/test/c_generator/stmts/local_array_decl.c2t +++ b/test/c_generator/stmts/local_array_decl.c2t @@ -26,6 +26,6 @@ static void test_func1(void); static void test_func1(void) { - int board2[20][20]; + int board2[20][20] = { 0 }; } diff --git a/test/c_generator/stmts/while_stmt_expr.c2t b/test/c_generator/stmts/while_stmt_expr.c2t index b39cf5b54..8886dc6b1 100644 --- a/test/c_generator/stmts/while_stmt_expr.c2t +++ b/test/c_generator/stmts/while_stmt_expr.c2t @@ -30,7 +30,7 @@ int main(int argc, const char** argv) } { - int b; + int b = { 0 }; while ((b = 0)) { } } diff --git a/test/expr/assign_list.c2t b/test/expr/assign_list.c2t index 553777d20..6b1790084 100644 --- a/test/expr/assign_list.c2t +++ b/test/expr/assign_list.c2t @@ -44,7 +44,7 @@ static test_Point test_new_point(int x, int y) int main(void) { printf("p0={ %d, %d }\n", test_p0.x, test_p0.y); - test_Point p1; + test_Point p1 = { 0 }; p1 = (test_Point){ 3, 4 }; printf("p1={ %d, %d }\n", p1.x, p1.y); test_print_point("p2", (test_Point){ 5, 6 }); diff --git a/test/types/const/multi_const.c2t b/test/types/const/multi_const.c2t index d0e367859..81faa1f76 100644 --- a/test/types/const/multi_const.c2t +++ b/test/types/const/multi_const.c2t @@ -60,7 +60,7 @@ int main(void) const void* q = (const char* const*)p; test_A* const cc = NULL; q = (test_A* const*)&cc; - test_A aa[1]; + test_A aa[1] = { 0 }; { test_A* const b = aa; if (b) return 0; diff --git a/tools/tester/expect_file.c2 b/tools/tester/expect_file.c2 index 0a18cc0e2..d64eeffeb 100644 --- a/tools/tester/expect_file.c2 +++ b/tools/tester/expect_file.c2 @@ -51,21 +51,24 @@ public type ExpectFile struct @(opaque) { ExpectMode mode; string_buffer.Buf* output; // will be set in check() + const char* testFilename; // during analysis u32 lastLineNr; u32 expIndex; // cache for Lines[expIndex] const char* expectedLine; + u32 expectedLineNr; bool consecutive; line_db.Db* lines; } -public fn ExpectFile* create(const char* name, ExpectMode m) { +public fn ExpectFile* create(const char* name, ExpectMode m, const char* testFilename) { ExpectFile* f = calloc(1, sizeof(ExpectFile)); strcpy(f.filename, name); f.mode = m; + f.testFilename = testFilename; f.lines = line_db.create(); return f; } @@ -84,7 +87,7 @@ public fn void ExpectFile.addLine(ExpectFile* f, u32 line_nr, const char* start, if (strncmp(start, "//", 2) == 0) return; // ignore comments f.lastLineNr = line_nr; - f.lines.add(start, end, consecutive); + f.lines.add(start, end, line_nr, consecutive); } fn bool ExpectFile.checkLine(ExpectFile* f, u32 line_nr, const char* start, const char* end) { @@ -92,30 +95,20 @@ fn bool ExpectFile.checkLine(ExpectFile* f, u32 line_nr, const char* start, cons skipInitialWhitespace(&start, end); skipTrailingWhitespace(start, &end); - char[EXPECT_MAX_LINE] line; u32 len = (u32)(end - start); if (len == 0) return true; // ignore empty lines - if (start[0] == '/' && start[1] == '/') return true; // ignore comment lines - - if (len >= EXPECT_MAX_LINE) { - color_print2(f.output, colError, " in file %s: line %d: line too long", f.filename, line_nr); - return false; - } - if (len != 0) memcpy(line, start, len); - line[len] = 0; -#if TesterDebug - printf("got %d [%s]\n", line_nr, line); -#endif + if (strncmp(start, "//", 2) == 0) return true; // ignore comment lines if (!f.expectedLine) { if (f.mode == COMPLETE) { - color_print2(f.output, colError, " in file %s: line %d\n unexpected line '%s'", f.filename, line_nr, line); + color_print2(f.output, colError, "%s:%d: unexpected '%.*s'", f.testFilename, f.expectedLineNr+1, (i32)len, start); + color_print2(f.output, colError, " in file %s: line %d\n unexpected line '%.*s'", f.filename, line_nr, (i32)len, start); return false; } else { return true; } } - if (strcmp(f.expectedLine, line) == 0) { + if (strncmp(f.expectedLine, start, len) == 0) { #if TesterDebug printf("-> match\n"); #endif @@ -123,7 +116,8 @@ fn bool ExpectFile.checkLine(ExpectFile* f, u32 line_nr, const char* start, cons f.setExpected(); } else { if (f.mode == COMPLETE || f.consecutive) { - color_print2(f.output, colError, " in file %s: line %d\n expected '%s'\n got '%s'", f.filename, line_nr, f.expectedLine, line); + color_print2(f.output, colError, "%s:%d: expected '%s', got '%.*s'", f.testFilename, f.expectedLineNr, f.expectedLine, (i32)len, start); + color_print2(f.output, colError, " in file %s: line %d\n expected '%s'\n got '%.*s'", f.filename, line_nr, f.expectedLine, (i32)len, start); return false; } } @@ -136,6 +130,7 @@ fn void ExpectFile.setExpected(ExpectFile* f) { f.consecutive = false; } else { f.expectedLine = f.lines.getLine(f.expIndex); + f.expectedLineNr = f.lines.getLineNr(f.expIndex); f.consecutive = f.lines.getConsecutive(f.expIndex); } #if TesterDebug @@ -164,29 +159,26 @@ public fn bool ExpectFile.check(ExpectFile* f, string_buffer.Buf* output, const f.setExpected(); u32 line_nr = 1; - while (1) { + while (*lineStart) { // cut it up into lines (even if empty) const char* cp = lineStart; while (*cp) { if (*cp == '\n') break; cp++; } - - if (*cp == 0) break; if (!f.checkLine(line_nr, lineStart, cp)) { result = false; - goto out; + break; } line_nr++; - cp++; // skip newline + if (*cp == '\n') cp++; // skip newline lineStart = cp; } - - if (f.expectedLine != nil) { + if (!*lineStart && f.expectedLine != nil) { + color_print2(f.output, colError, "%s:%d: expected '%s'", f.testFilename, f.expectedLineNr, f.expectedLine); color_print2(f.output, colError, " in file %s: expected '%s'", f.filename, f.expectedLine); result = false; } -out: file.close(); return result; } diff --git a/tools/tester/line_db.c2 b/tools/tester/line_db.c2 index 7b484e83f..2f0e8d12d 100644 --- a/tools/tester/line_db.c2 +++ b/tools/tester/line_db.c2 @@ -20,6 +20,7 @@ import string local; type Entry struct { char* line; + u32 line_nr; bool consecutive; } @@ -57,7 +58,7 @@ fn void Db.resize(Db* db, u32 capacity) { db.entries = entries2; } -public fn void Db.add(Db* db, const char* start, const char* end, bool consecutive) { +public fn void Db.add(Db* db, const char* start, const char* end, u32 line_nr, bool consecutive) { u32 len = (u32)(end - start); if (db.count == db.capacity) { db.resize((u32)(db.capacity ? db.capacity * 2 : 4)); @@ -68,6 +69,7 @@ public fn void Db.add(Db* db, const char* start, const char* end, bool consecuti entry.line = malloc(len + 1); // add 0-terminator memcpy(entry.line, start, len); entry.line[len] = 0; + entry.line_nr = line_nr; entry.consecutive = consecutive; } @@ -75,6 +77,10 @@ public fn const char* Db.getLine(const Db* db, u32 idx) { return db.entries[idx].line; } +public fn u32 Db.getLineNr(const Db* db, u32 idx) { + return db.entries[idx].line_nr; +} + public fn bool Db.getConsecutive(const Db* db, u32 idx) { return db.entries[idx].consecutive; } diff --git a/tools/tester/test_db.c2 b/tools/tester/test_db.c2 index be57c243f..26a85a7c0 100644 --- a/tools/tester/test_db.c2 +++ b/tools/tester/test_db.c2 @@ -391,7 +391,7 @@ fn bool Db.parseExpect(Db* db) { } db.skipLine(); // skip rest of the line - db.currentExpect = expect_file.create(filename, em); + db.currentExpect = expect_file.create(filename, em, db.filename); // TODO check for name duplicates db.addExpected(db.currentExpect); while (*db.cur != 0 && !strstart(db.cur, "// @", nil)) { @@ -582,7 +582,7 @@ fn void Db.parseLineOutside(Db* db, const char* start, const char* end) { char[128] name; if (!db.readUntil(name, elemsof(name), cp, '}', "filename")) return; - db.currentExpect = expect_file.create(name, ATLEAST); + db.currentExpect = expect_file.create(name, ATLEAST, db.filename); // TODO check for name duplicates db.addExpected(db.currentExpect); db.mode = InExpectFile;