Commit 4dae70e702

Vexu <git@vexu.eu>
2019-12-14 12:09:35
translate-c-2 container aliases
1 parent a4ac6d1
Changed files (4)
lib
std
src-self-hosted
test
lib/std/zig/render.zig
@@ -193,7 +193,6 @@ fn renderRoot(
 fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Child.Error!void {
     const first_token = node.firstToken();
     var prev_token = first_token;
-    if (prev_token == 0) return;
     while (tree.tokens.at(prev_token - 1).id == .DocComment) {
         prev_token -= 1;
     }
@@ -2175,7 +2174,8 @@ fn renderTokenOffset(
     }
 
     while (true) {
-        const newline_count = if (loc.line < 2) @as(u8, 1) else @as(u8, 2);
+        assert(loc.line != 0);
+        const newline_count = if (loc.line == 1) @as(u8, 1) else @as(u8, 2);
         try stream.writeByteNTimes('\n', newline_count);
         try stream.writeByteNTimes(' ', indent);
         try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));
src-self-hosted/clang.zig
@@ -713,16 +713,6 @@ pub const ZigClangRecordDecl_field_iterator = extern struct {
     opaque: *c_void,
 };
 
-pub const  ZigClangElaboratedTypeKeyword = extern enum {
-    Struct,
-    Interface,
-    Union,
-    Class,
-    Enum,
-    Typename,
-    None,
-};
-
 pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;
 pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;
 pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;
@@ -967,7 +957,6 @@ pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const Zig
 
 pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType;
 
-pub extern fn ZigClangElaboratedType_getKeyword(*const struct_ZigClangElaboratedType) ZigClangElaboratedTypeKeyword;
 pub extern fn ZigClangElaboratedType_getNamedType(*const ZigClangElaboratedType) ZigClangQualType;
 
 pub extern fn ZigClangAttributedType_getEquivalentType(*const ZigClangAttributedType) ZigClangQualType;
src-self-hosted/translate_c.zig
@@ -15,7 +15,7 @@ pub const Error = error{OutOfMemory};
 const TypeError = Error || error{UnsupportedType};
 const TransError = TypeError || error{UnsupportedTranslation};
 
-const DeclTable = std.HashMap(usize, []const u8, addrHash, addrEql);
+const DeclTable = std.HashMap(usize, void, addrHash, addrEql);
 
 fn addrHash(x: usize) u32 {
     switch (@typeInfo(usize).Int.bits) {
@@ -31,6 +31,12 @@ fn addrEql(a: usize, b: usize) bool {
     return a == b;
 }
 
+const SymbolTable = std.StringHashMap(void);
+const AliasList = std.SegmentedList(struct {
+    alias: []const u8,
+    name: []const u8,
+}, 4);
+
 const Scope = struct {
     id: Id,
     parent: ?*Scope,
@@ -98,6 +104,8 @@ const Context = struct {
     err: Error,
     source_manager: *ZigClangSourceManager,
     decl_table: DeclTable,
+    alias_list: AliasList,
+    sym_table: SymbolTable,
     global_scope: *Scope.Root,
     ptr_params: std.BufSet,
     clang_context: *ZigClangASTContext,
@@ -177,6 +185,8 @@ pub fn translate(
         .source_manager = ZigClangASTUnit_getSourceManager(ast_unit),
         .err = undefined,
         .decl_table = DeclTable.init(arena),
+        .alias_list = AliasList.init(arena),
+        .sym_table = SymbolTable.init(arena),
         .global_scope = try arena.create(Scope.Root),
         .ptr_params = std.BufSet.init(arena),
         .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,
@@ -191,10 +201,15 @@ pub fn translate(
     if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {
         return context.err;
     }
+    var it = context.alias_list.iterator(0);
+    while (it.next()) |alias| {
+        if (!context.sym_table.contains(alias.alias)) {
+            try createAlias(&context, alias);
+        }
+    }
 
     tree.root_node.eof_token = try appendToken(&context, .Eof, "");
     tree.source = source_buffer.toOwnedSlice();
-
     if (false) {
         std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", tree.source);
         var i: usize = 0;
@@ -240,10 +255,9 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
 }
 
 fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
-    if (c.decl_table.contains(@ptrToInt(fn_decl))) return; // Avoid processing this decl twice
+    if (try c.decl_table.put(@ptrToInt(fn_decl), {})) |_| return; // Avoid processing this decl twice
     const rp = makeRestorePoint(c);
     const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl)));
-    _ = try c.decl_table.put(@ptrToInt(fn_decl), fn_name);
     const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl);
     const fn_qt = ZigClangFunctionDecl_getType(fn_decl);
     const fn_type = ZigClangQualType_getTypePtr(fn_qt);
@@ -305,7 +319,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
 }
 
 fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
-    if (c.decl_table.contains(@ptrToInt(var_decl))) return; // Avoid processing this decl twice
+    if (try c.decl_table.put(@ptrToInt(var_decl), {})) |_| return; // Avoid processing this decl twice
     const rp = makeRestorePoint(c);
     const visib_tok = try appendToken(c, .Keyword_pub, "pub");
 
@@ -316,7 +330,6 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
 
     var scope = &c.global_scope.base;
     const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl)));
-    _ = try c.decl_table.put(@ptrToInt(var_decl), var_name);
     const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);
 
     const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
@@ -388,13 +401,12 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
 }
 
 fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void {
-    if (c.decl_table.contains(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)))) return; // Avoid processing this decl twice
+    if (try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), {})) |_| return; // Avoid processing this decl twice
     const rp = makeRestorePoint(c);
     const visib_tok = try appendToken(c, .Keyword_pub, "pub");
     const const_tok = try appendToken(c, .Keyword_const, "const");
 
     const typedef_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
-    _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name);
     const name_tok = try appendToken(c, .Identifier, typedef_name);
     const eq_tok = try appendToken(c, .Equal, "=");
 
@@ -429,12 +441,9 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err
 }
 
 fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void {
-    if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) return; // Avoid processing this decl twice
+    if (try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), {})) |_| return; // Avoid processing this decl twice
     const rp = makeRestorePoint(c);
 
-    const visib_tok = try appendToken(c, .Keyword_pub, "pub");
-    const const_tok = try appendToken(c, .Keyword_const, "const");
-
     const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
 
     const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl))
@@ -447,8 +456,10 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!
     if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0)
         return;
 
+    const visib_tok = try appendToken(c, .Keyword_pub, "pub");
+    const const_tok = try appendToken(c, .Keyword_const, "const");
+
     const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
-    _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);
     const name_tok = try appendToken(c, .Identifier, name);
 
     const eq_tok = try appendToken(c, .Equal, "=");
@@ -480,6 +491,36 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!
     };
 
     try addTopLevelDecl(c, name, &node.base);
+    try c.alias_list.push(.{ .alias = bare_name, .name = name });
+}
+
+fn createAlias(c: *Context, alias: var) !void {
+    const visib_tok = try appendToken(c, .Keyword_pub, "pub");
+    const mut_tok = try appendToken(c, .Keyword_const, "const");
+    const name_tok = try appendToken(c, .Identifier, alias.alias);
+
+    const eq_tok = try appendToken(c, .Equal, "=");
+    const init_node = try appendIdentifier(c, alias.name);
+
+    const node = try c.a().create(ast.Node.VarDecl);
+    node.* = ast.Node.VarDecl{
+        .base = ast.Node{ .id = .VarDecl },
+        .doc_comments = null,
+        .visib_token = visib_tok,
+        .thread_local_token = null,
+        .name_token = name_tok,
+        .eq_token = eq_tok,
+        .mut_token = mut_tok,
+        .comptime_token = null,
+        .extern_export_token = null,
+        .lib_name = null,
+        .type_node = null,
+        .align_node = null,
+        .section_node = null,
+        .init_node = init_node,
+        .semicolon_token = try appendToken(c, .Semicolon, ";"),
+    };
+    return addTopLevelDecl(c, alias.alias, &node.base);
 }
 
 const ResultUsed = enum {
@@ -1063,9 +1104,9 @@ fn transInitListExpr(
     }
 
     const arr_type = ZigClangType_getAsArrayTypeUnsafe(qual_type);
-    const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, qual_type);
     const child_qt = ZigClangArrayType_getElementType(arr_type);
     const init_count = ZigClangInitListExpr_getNumInits(expr);
+    const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, qual_type);
     const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);
     const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, std.math.maxInt(usize));
     const leftover_count = all_count - init_count;
@@ -1270,6 +1311,7 @@ fn maybeSuppressResult(
 
 fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
     try c.tree.root_node.decls.push(decl_node);
+    _ = try c.sym_table.put(name, {});
 }
 
 fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node {
@@ -1316,7 +1358,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeErro
         .init_arg_expr = .None,
         .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
         .lbrace_token = lbrace_token,
-        .rbrace_token = undefined, // TODO
+        .rbrace_token = undefined,
     };
 
     var it = ZigClangRecordDecl_field_begin(record_def);
@@ -1855,17 +1897,14 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
             const record_ty = @ptrCast(*const ZigClangRecordType, ty);
 
             const record_decl = ZigClangRecordType_getDecl(record_ty);
-            if (rp.c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv|
-                return appendIdentifier(rp.c, kv.value)
+            if (try getContainerName(rp.c, record_decl)) |name|
+                return appendIdentifier(rp.c, name)
             else
                 return transRecordDecl(rp.c, record_decl);
         },
         .Elaborated => {
             const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty);
-            switch (ZigClangElaboratedType_getKeyword(elaborated_ty)) {
-                .Struct, .Enum, .Union => return try transQualType(rp, ZigClangElaboratedType_getNamedType(elaborated_ty), source_loc),
-                else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported elaborated type", .{}),
-            }
+            return transQualType(rp, ZigClangElaboratedType_getNamedType(elaborated_ty), source_loc);
         },
         else => {
             const type_name = rp.c.str(ZigClangType_getTypeClassName(ty));
@@ -1874,6 +1913,24 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
     }
 }
 
+fn getContainerName(c: *Context, record_decl: *const ZigClangRecordDecl) !?[]const u8 {
+    const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
+
+    const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl))
+        "union"
+    else if (ZigClangRecordDecl_isStruct(record_decl))
+        "struct"
+    else {
+        try emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name});
+        return null;
+    };
+
+    if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0)
+        return null;
+
+    return try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
+}
+
 fn isCVoid(qt: ZigClangQualType) bool {
     const ty = ZigClangQualType_getTypePtr(qt);
     if (ZigClangType_getTypeClass(ty) == .Builtin) {
test/translate_c.zig
@@ -186,72 +186,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub export var arr2: [*c]u8 = "hello";
     });
 
-    cases.add_2("pointer to struct demoted to opaque due to bit fields",
-        \\struct Foo {
-        \\    unsigned int: 1;
-        \\};
-        \\struct Bar {
-        \\    struct Foo *foo;
-        \\};
-    , &[_][]const u8{ // TODO that semicolon is hideous
-        \\pub const struct_Foo = @OpaqueType() // /home/vexu/Documents/zig/zig/zig-cache/source.h:2:5: warning: struct demoted to opaque type - has bitfield
-        \\    ;
-        \\pub const struct_Bar = extern struct {
-        \\    foo: ?*struct_Foo,
-        \\};
-    });
-
-    cases.add_2("double define struct",
-        \\typedef struct Bar Bar;
-        \\typedef struct Foo Foo;
-        \\
-        \\struct Foo {
-        \\    Foo *a;
-        \\};
-        \\
-        \\struct Bar {
-        \\    Foo *a;
-        \\};
-    , &[_][]const u8{
-        \\pub const struct_Bar = extern struct {
-        \\    a: [*c]Foo,
-        \\};
-        \\pub const Bar = struct_Bar;
-        \\pub const struct_Foo = extern struct {
-        \\    a: [*c]Foo,
-        \\};
-        \\pub const Foo = struct_Foo;
-    });
-
-    cases.add_2("simple struct",
-        \\struct Foo {
-        \\    int x;
-        \\    char *y;
-        \\};
-    , &[_][]const u8{
-        \\const struct_Foo = extern struct {
-        \\    x: c_int,
-        \\    y: [*c]u8,
-        \\};
-    });
-
-    cases.add_2("self referential struct with function pointer",
-        \\struct Foo {
-        \\    void (*derp)(struct Foo *foo);
-        \\};
-    , &[_][]const u8{
-        \\pub const struct_Foo = extern struct {
-        \\    derp: ?extern fn ([*c]struct_Foo) void,
-        \\};
-    });
-    cases.add_2("struct prototype used in func",
-        \\struct Foo;
-        \\struct Foo *some_func(struct Foo *foo, int x);
-    , &[_][]const u8{
-        \\pub const struct_Foo = @OpaqueType();
-        \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
-    });
-
     cases.add_2("array initializer expr",
         \\static void foo(void){
         \\    char arr[10] ={1};
@@ -268,6 +202,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
+    cases.add_2("field struct",
+        \\union OpenGLProcs {
+        \\    struct {
+        \\        int Clear;
+        \\    } gl;
+        \\};
+    , &[_][]const u8{
+        \\pub const union_OpenGLProcs = extern union {
+        \\    gl: extern struct {
+        \\        Clear: c_int,
+        \\    },
+        \\};
+        \\pub const OpenGLProcs = union_OpenGLProcs;
+    });
+
     /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
 
     cases.add_both("typedef of function in struct field",
@@ -284,7 +233,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\};
     });
 
-    cases.add("pointer to struct demoted to opaque due to bit fields",
+    cases.add_both("pointer to struct demoted to opaque due to bit fields",
         \\struct Foo {
         \\    unsigned int: 1;
         \\};
@@ -292,7 +241,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    struct Foo *foo;
         \\};
     , &[_][]const u8{
-        \\pub const struct_Foo = @OpaqueType();
+        \\pub const struct_Foo = @OpaqueType()
+    ,
         \\pub const struct_Bar = extern struct {
         \\    foo: ?*struct_Foo,
         \\};
@@ -441,7 +391,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add("double define struct",
+    cases.add_both("double define struct",
         \\typedef struct Bar Bar;
         \\typedef struct Foo Foo;
         \\
@@ -456,10 +406,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const struct_Foo = extern struct {
         \\    a: [*c]Foo,
         \\};
+    ,
         \\pub const Foo = struct_Foo;
+    ,
         \\pub const struct_Bar = extern struct {
         \\    a: [*c]Foo,
         \\};
+    ,
+        \\pub const Bar = struct_Bar;
     });
 
     cases.addAllowWarnings("simple data types",
@@ -536,7 +490,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;
     });
 
-    cases.add("simple struct",
+    cases.add_both("simple struct",
         \\struct Foo {
         \\    int x;
         \\    char *y;
@@ -588,7 +542,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub extern fn func(array: [*c]c_int) void;
     });
 
-    cases.add("self referential struct with function pointer",
+    cases.add_both("self referential struct with function pointer",
         \\struct Foo {
         \\    void (*derp)(struct Foo *foo);
         \\};
@@ -600,7 +554,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const Foo = struct_Foo;
     });
 
-    cases.add("struct prototype used in func",
+    cases.add_both("struct prototype used in func",
         \\struct Foo;
         \\struct Foo *some_func(struct Foo *foo, int x);
     , &[_][]const u8{
@@ -632,7 +586,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const THING2 = THING1;
     });
 
-    cases.add("circular struct definitions",
+    cases.add_both("circular struct definitions",
         \\struct Bar;
         \\
         \\struct Foo {