diff --git a/doc/targets.md b/doc/targets.md index eb856a3d53..fb1b32e499 100644 --- a/doc/targets.md +++ b/doc/targets.md @@ -14,3 +14,6 @@ Update the C integer types to be the correct size for the target. Add the conditional compilation code for the page size global. It is hardcoded for each target. + +Make sure that parseh sends the correct command line parameters to libclang for +the given target. diff --git a/src/ast_render.cpp b/src/ast_render.cpp index a1043377c8..8ddfe03e34 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -672,7 +672,7 @@ static void render_node(AstRender *ar, AstNode *node) { } ar->indent -= ar->indent_size; - fprintf(ar->f, "}\n"); + fprintf(ar->f, "}"); break; } case NodeTypeStructField: diff --git a/src/parseh.cpp b/src/parseh.cpp index 0cf1b570c7..e0b3506e12 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -397,6 +397,9 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { if (!enum_def) { // this is a type that we can point to but that's it, same as `struct Foo;`. add_typedef_node(c, type_name, create_symbol_node(c, "u8")); + AstNode *alias_node = create_var_decl_node(c, buf_ptr(&bare_name), + create_symbol_node(c, buf_ptr(type_name))); + c->aliases.append(alias_node); return; } @@ -404,7 +407,7 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { buf_init_from_buf(&node->data.struct_decl.name, type_name); node->data.struct_decl.kind = ContainerKindEnum; - node->data.struct_decl.visib_mod = c->visib_mod; + node->data.struct_decl.visib_mod = VisibModExport; node->data.struct_decl.directives = create_empty_directives(c); ZigList var_decls = {0}; @@ -465,6 +468,43 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { } +static void visit_record_decl(Context *c, const RecordDecl *record_decl) { + Buf bare_name = BUF_INIT; + buf_init_from_str(&bare_name, decl_name(record_decl)); + + Buf *type_name = buf_alloc(); + buf_appendf(type_name, "struct_%s", buf_ptr(&bare_name)); + + if (c->type_table.maybe_get(type_name)) { + // we've already seen it + return; + } + + RecordDecl *record_def = record_decl->getDefinition(); + if (!record_def) { + // this is a type that we can point to but that's it, such as `struct Foo;`. + add_typedef_node(c, type_name, create_symbol_node(c, "u8")); + AstNode *alias_node = create_var_decl_node(c, buf_ptr(&bare_name), + create_symbol_node(c, buf_ptr(type_name))); + c->aliases.append(alias_node); + return; + } + + emit_warning(c, record_decl, "skipping record %s, TODO", buf_ptr(&bare_name)); + + /* + AstNode *node = create_node(c, NodeTypeStructDecl); + buf_init_from_buf(&node->data.struct_decl.name, type_name); + + node->data.struct_decl.kind = ContainerKindStruct; + node->data.struct_decl.visib_mod = VisibModExport; + node->data.struct_decl.directives = create_empty_directives(c); + + normalize_parent_ptrs(node); + c->root->data.root.top_level_decls.append(node); + */ +} + static bool decl_visitor(void *context, const Decl *decl) { Context *c = (Context*)context; @@ -478,6 +518,9 @@ static bool decl_visitor(void *context, const Decl *decl) { case Decl::Enum: visit_enum_decl(c, static_cast(decl)); break; + case Decl::Record: + visit_record_decl(c, static_cast(decl)); + break; default: emit_warning(c, decl, "ignoring %s decl\n", decl->getDeclKindName()); } diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 17d45d1203..b15d3411af 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -24,10 +24,12 @@ struct TestCase { ZigList compile_errors; ZigList compiler_args; ZigList program_args; + bool is_parseh; }; static ZigList test_cases = {0}; static const char *tmp_source_path = ".tmp_source.zig"; +static const char *tmp_h_path = ".tmp_header.h"; static const char *tmp_exe_path = "./.tmp_exe"; static const char *zig_exe = "./zig"; @@ -94,6 +96,24 @@ static TestCase *add_compile_fail_case(const char *case_name, const char *source return test_case; } +static TestCase *add_parseh_case(const char *case_name, const char *source, const char *output) { + TestCase *test_case = allocate(1); + test_case->case_name = case_name; + test_case->output = output; + test_case->is_parseh = true; + + test_case->source_files.resize(1); + test_case->source_files.at(0).relative_path = tmp_h_path; + test_case->source_files.at(0).source_code = source; + + test_case->compiler_args.append("parseh"); + test_case->compiler_args.append(tmp_h_path); + test_case->compiler_args.append("--c-import-warnings"); + + test_cases.append(test_case); + return test_case; +} + static void add_compiling_test_cases(void) { add_simple_case("hello world with libc", R"SOURCE( #link("c") @@ -1771,6 +1791,39 @@ const x = 2 == 2.0; } +////////////////////////////////////////////////////////////////////////////// + +static void add_parseh_test_cases(void) { + add_parseh_case("simple data types", R"SOURCE( +#include +int foo(char a, unsigned char b, signed char c); +void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d); +void baz(int8_t a, int16_t b, int32_t c, int64_t d); + )SOURCE", R"OUTPUT(pub extern fn foo(a: u8, b: u8, c: i8) -> c_int; +pub extern fn bar(a: u8, b: u16, c: u32, d: u64); +pub extern fn baz(a: i8, b: i16, c: i32, d: i64);)OUTPUT"); + + add_parseh_case("noreturn attribute", R"SOURCE( +void foo(void) __attribute__((noreturn)); + )SOURCE", R"OUTPUT(pub extern fn foo() -> unreachable;)OUTPUT"); + + add_parseh_case("enums", R"SOURCE( +enum Foo { + FooA, + FooB, + Foo1, +}; + )SOURCE", R"OUTPUT(export enum enum_Foo { + A, + B, + _1, +} +pub const FooA = enum_Foo.A; +pub const FooB = enum_Foo.B; +pub const Foo1 = enum_Foo._1; +pub const Foo = enum_Foo;)OUTPUT"); +} + static void print_compiler_invocation(TestCase *test_case) { printf("%s", zig_exe); for (int i = 0; i < test_case->compiler_args.length; i += 1) { @@ -1822,36 +1875,55 @@ static void run_test(TestCase *test_case) { exit(1); } - Buf program_stderr = BUF_INIT; - Buf program_stdout = BUF_INIT; - os_exec_process(tmp_exe_path, test_case->program_args, &return_code, &program_stderr, &program_stdout); - - if (return_code != 0) { - printf("\nProgram exited with return code %d:\n", return_code); - print_compiler_invocation(test_case); - printf("%s", tmp_exe_path); - for (int i = 0; i < test_case->program_args.length; i += 1) { - printf(" %s", test_case->program_args.at(i)); + if (test_case->is_parseh) { + if (buf_len(&zig_stderr) > 0) { + printf("\nparseh emitted warnings:\n"); + print_compiler_invocation(test_case); + printf("%s\n", buf_ptr(&zig_stderr)); + exit(1); } - printf("\n"); - printf("%s\n", buf_ptr(&program_stderr)); - exit(1); - } - if (!buf_eql_str(&program_stdout, test_case->output)) { - printf("\n"); - print_compiler_invocation(test_case); - printf("%s", tmp_exe_path); - for (int i = 0; i < test_case->program_args.length; i += 1) { - printf(" %s", test_case->program_args.at(i)); + if (!strstr(buf_ptr(&zig_stdout), test_case->output)) { + printf("\n"); + printf("========= Expected this output: =========\n"); + printf("%s\n", test_case->output); + printf("================================================\n"); + print_compiler_invocation(test_case); + printf("%s\n", buf_ptr(&zig_stdout)); + exit(1); + } + } else { + Buf program_stderr = BUF_INIT; + Buf program_stdout = BUF_INIT; + os_exec_process(tmp_exe_path, test_case->program_args, &return_code, &program_stderr, &program_stdout); + + if (return_code != 0) { + printf("\nProgram exited with return code %d:\n", return_code); + print_compiler_invocation(test_case); + printf("%s", tmp_exe_path); + for (int i = 0; i < test_case->program_args.length; i += 1) { + printf(" %s", test_case->program_args.at(i)); + } + printf("\n"); + printf("%s\n", buf_ptr(&program_stderr)); + exit(1); + } + + if (!buf_eql_str(&program_stdout, test_case->output)) { + printf("\n"); + print_compiler_invocation(test_case); + printf("%s", tmp_exe_path); + for (int i = 0; i < test_case->program_args.length; i += 1) { + printf(" %s", test_case->program_args.at(i)); + } + printf("\n"); + printf("==== Test failed. Expected output: ====\n"); + printf("%s\n", test_case->output); + printf("========= Actual output: ==============\n"); + printf("%s\n", buf_ptr(&program_stdout)); + printf("=======================================\n"); + exit(1); } - printf("\n"); - printf("==== Test failed. Expected output: ====\n"); - printf("%s\n", test_case->output); - printf("========= Actual output: ==============\n"); - printf("%s\n", buf_ptr(&program_stdout)); - printf("=======================================\n"); - exit(1); } for (int i = 0; i < test_case->source_files.length; i += 1) { @@ -1881,6 +1953,7 @@ static void run_all_tests(bool reverse) { static void cleanup(void) { remove(tmp_source_path); + remove(tmp_h_path); remove(tmp_exe_path); } @@ -1900,6 +1973,7 @@ int main(int argc, char **argv) { } add_compiling_test_cases(); add_compile_failure_test_cases(); + add_parseh_test_cases(); run_all_tests(reverse); cleanup(); }