Commit f1c5d3d3a1

Andrew Kelley <superjoe30@gmail.com>
2016-01-28 19:54:34
add parseh tests
1 parent 474340a
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.
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:
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<AstNode *> 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<const EnumDecl *>(decl));
             break;
+        case Decl::Record:
+            visit_record_decl(c, static_cast<const RecordDecl *>(decl));
+            break;
         default:
             emit_warning(c, decl, "ignoring %s decl\n", decl->getDeclKindName());
     }
test/run_tests.cpp
@@ -24,10 +24,12 @@ struct TestCase {
     ZigList<const char *> compile_errors;
     ZigList<const char *> compiler_args;
     ZigList<const char *> program_args;
+    bool is_parseh;
 };
 
 static ZigList<TestCase*> 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<TestCase>(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 <stdint.h>
+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 (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);
+        }
 
-    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 (!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);
         }
-        printf("\n");
-        printf("%s\n", buf_ptr(&program_stderr));
-        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 (!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 (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();
 }