Commit 9d31b65b34

Vexu <git@vexu.eu>
2019-12-22 11:53:57
translate-c-2 various fixes - make non-namespaced enums ints - fix .used compound assignments not being grouped - fix macro calls with casts producing invalid Zig
1 parent 40f607d
Changed files (3)
src-self-hosted/c_tokenizer.zig
@@ -30,6 +30,7 @@ pub const CToken = struct {
         Arrow,
         LBrace,
         RBrace,
+        Pipe,
     };
 
     pub const NumLitSuffix = enum {
@@ -360,6 +361,10 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
                         result.id = .RBrace;
                         state = .Done;
                     },
+                    '|' => {
+                        result.id = .Pipe;
+                        state = .Done;
+                    },
                     else => return error.TokenizingFailed,
                 }
             },
src-self-hosted/translate_c.zig
@@ -781,7 +781,11 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
             _ = try appendToken(c, .Comma, ",");
             // In C each enum value is in the global namespace. So we put them there too.
             // At this point we can rely on the enum emitting successfully.
-            try addEnumTopLevel(c, name, field_name, enum_val_name);
+            const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name);
+            tld_node.eq_token = try appendToken(c, .Equal, "=");
+            tld_node.init_node = try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const));
+            tld_node.semicolon_token = try appendToken(c, .Semicolon, ";");
+            try addTopLevelDecl(c, field_name, &tld_node.base);
         }
         container_node.rbrace_token = try appendToken(c, .RBrace, "}");
 
@@ -797,25 +801,6 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
     return transCreateNodeIdentifier(c, name);
 }
 
-fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void {
-    const node = try transCreateNodeVarDecl(c, true, true, enum_val_name);
-    node.eq_token = try appendToken(c, .Equal, "=");
-    const enum_ident = try transCreateNodeIdentifier(c, enum_name);
-    const period_tok = try appendToken(c, .Period, ".");
-    const field_ident = try transCreateNodeIdentifier(c, field_name);
-    node.semicolon_token = try appendToken(c, .Semicolon, ";");
-
-    const field_access_node = try c.a().create(ast.Node.InfixOp);
-    field_access_node.* = .{
-        .op_token = period_tok,
-        .lhs = enum_ident,
-        .op = .Period,
-        .rhs = field_ident,
-    };
-    node.init_node = &field_access_node.base;
-    try addTopLevelDecl(c, field_name, &node.base);
-}
-
 fn createAlias(c: *Context, alias: var) !void {
     const node = try transCreateNodeVarDecl(c, true, true, alias.alias);
     node.eq_token = try appendToken(c, .Equal, "=");
@@ -1570,6 +1555,15 @@ fn transCCast(
         const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ZigClangQualType_getTypePtr(dst_type));
         return transCCast(rp, scope, loc, ZigClangElaboratedType_getNamedType(elaborated_ty), src_type, expr);
     }
+    if (ZigClangQualType_getTypeClass(dst_type) == .Enum)
+    {
+        const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToEnum");
+        try builtin_node.params.push(try transQualType(rp, dst_type, loc));
+        _ = try appendToken(rp.c, .Comma, ",");
+        try builtin_node.params.push(expr);
+        builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
+        return &builtin_node.base;
+    }
     if (ZigClangQualType_getTypeClass(src_type) == .Enum and
         ZigClangQualType_getTypeClass(dst_type) != .Enum)
     {
@@ -2326,7 +2320,13 @@ fn transCreatePreCrement(
     block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
     // semicolon must immediately follow rbrace because it is the last token in a block
     _ = try appendToken(rp.c, .Semicolon, ";");
-    return &block_scope.block_node.base;
+    const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
+    grouped_expr.* = .{
+        .lparen = try appendToken(rp.c, .LParen, "("),
+        .expr = &block_scope.block_node.base,
+        .rparen = try appendToken(rp.c, .RParen, ")"),
+    };
+    return &grouped_expr.base;
 }
 
 fn transCreatePostCrement(
@@ -2392,7 +2392,13 @@ fn transCreatePostCrement(
     try block_scope.block_node.statements.push(&break_node.base);
     _ = try appendToken(rp.c, .Semicolon, ";");
     block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
-    return &block_scope.block_node.base;
+    const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
+    grouped_expr.* = .{
+        .lparen = try appendToken(rp.c, .LParen, "("),
+        .expr = &block_scope.block_node.base,
+        .rparen = try appendToken(rp.c, .RParen, ")"),
+    };
+    return &grouped_expr.base;
 }
 
 fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundAssignOperator, used: ResultUsed) TransError!*ast.Node {
@@ -2508,7 +2514,13 @@ fn transCreateCompoundAssign(
     block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
     // semicolon must immediately follow rbrace because it is the last token in a block
     _ = try appendToken(rp.c, .Semicolon, ";");
-    return &block_scope.block_node.base;
+    const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
+    grouped_expr.* = .{
+        .lparen = try appendToken(rp.c, .LParen, "("),
+        .expr = &block_scope.block_node.base,
+        .rparen = try appendToken(rp.c, .RParen, ")"),
+    };
+    return &grouped_expr.base;
 }
 
 fn transCPtrCast(
@@ -4314,7 +4326,10 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc:
 
             if (it.peek().?.id == .RParen) {
                 _ = it.next();
-                return inner_node;
+                if (it.peek().?.id != .LParen) {
+                    return inner_node;
+                }
+                _ = it.next();
             }
 
             // hack to get zig fmt to render a comma in builtin calls
@@ -4458,7 +4473,7 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
             },
             .Shl => {
                 const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<");
-                const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope);
+                const rhs = try parseCExpr(rp, it, source_loc, scope);
                 const bitshift_node = try rp.c.a().create(ast.Node.InfixOp);
                 bitshift_node.* = .{
                     .op_token = op_token,
@@ -4468,9 +4483,21 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
                 };
                 node = &bitshift_node.base;
             },
+            .Pipe => {
+                const op_token = try appendToken(rp.c, .Pipe, "|");
+                const rhs = try parseCExpr(rp, it, source_loc, scope);
+                const or_node = try rp.c.a().create(ast.Node.InfixOp);
+                or_node.* = .{
+                    .op_token = op_token,
+                    .lhs = node,
+                    .op = .BitOr,
+                    .rhs = rhs,
+                };
+                node = &or_node.base;
+            },
             .LBrace => {
                 const arr_node = try transCreateNodeArrayAccess(rp.c, node);
-                arr_node.op.ArrayAccess = try parseCPrimaryExpr(rp, it, source_loc, scope);
+                arr_node.op.ArrayAccess = try parseCExpr(rp, it, source_loc, scope);
                 arr_node.rtoken = try appendToken(rp.c, .RBrace, "]");
                 node = &arr_node.base;
                 if (it.next().?.id != .RBrace)
test/translate_c.zig
@@ -166,50 +166,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add_both("enums",
-        \\enum Foo {
-        \\    FooA,
-        \\    FooB,
-        \\    Foo1,
-        \\};
-    , &[_][]const u8{
-        \\pub const enum_Foo = extern enum {
-        \\    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;
-    });
-
-    cases.add_both("enums",
-        \\enum Foo {
-        \\    FooA = 2,
-        \\    FooB = 5,
-        \\    Foo1,
-        \\};
-    , &[_][]const u8{
-        \\pub const enum_Foo = extern enum {
-        \\    A = 2,
-        \\    B = 5,
-        \\    @"1" = 6,
-        \\};
-    ,
-        \\pub const FooA = enum_Foo.A;
-    ,
-        \\pub const FooB = enum_Foo.B;
-    ,
-        \\pub const Foo1 = enum_Foo.@"1";
-    ,
-        \\pub const Foo = enum_Foo;
-    });
-
     cases.add_both("typedef of function in struct field",
         \\typedef void lws_callback_function(void);
         \\struct Foo {
@@ -921,27 +877,27 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    p,
         \\};
     , &[_][]const u8{
-        \\pub const a = enum_unnamed_1.a;
-        \\pub const b = enum_unnamed_1.b;
-        \\pub const c = enum_unnamed_1.c;
+        \\pub const a = 0;
+        \\pub const b = 1;
+        \\pub const c = 2;
         \\const enum_unnamed_1 = extern enum {
         \\    a,
         \\    b,
         \\    c,
         \\};
         \\pub const d = enum_unnamed_1;
-        \\pub const e = enum_unnamed_2.e;
-        \\pub const f = enum_unnamed_2.f;
-        \\pub const g = enum_unnamed_2.g;
+        \\pub const e = 0;
+        \\pub const f = 4;
+        \\pub const g = 5;
         \\const enum_unnamed_2 = extern enum {
         \\    e = 0,
         \\    f = 4,
         \\    g = 5,
         \\};
-        \\pub export var h: enum_unnamed_2 = @as(enum_unnamed_2, e);
-        \\pub const i = enum_unnamed_3.i;
-        \\pub const j = enum_unnamed_3.j;
-        \\pub const k = enum_unnamed_3.k;
+        \\pub export var h: enum_unnamed_2 = @intToEnum(enum_unnamed_2, e);
+        \\pub const i = 0;
+        \\pub const j = 1;
+        \\pub const k = 2;
         \\const enum_unnamed_3 = extern enum {
         \\    i,
         \\    j,
@@ -951,9 +907,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    l: enum_unnamed_3,
         \\    m: d,
         \\};
-        \\pub const n = enum_i.n;
-        \\pub const o = enum_i.o;
-        \\pub const p = enum_i.p;
+        \\pub const n = 0;
+        \\pub const o = 1;
+        \\pub const p = 2;
         \\pub const enum_i = extern enum {
         \\    n,
         \\    o,
@@ -1393,8 +1349,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    Two,
         \\};
     , &[_][]const u8{
-        \\pub const One = enum_unnamed_1.One;
-        \\pub const Two = enum_unnamed_1.Two;
+        \\pub const One = 0;
+        \\pub const Two = 1;
         \\const enum_unnamed_1 = extern enum {
         \\    One,
         \\    Two,
@@ -1496,9 +1452,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
         \\}
     , &[_][]const u8{
-        \\pub const FooA = enum_Foo.A;
-        \\pub const FooB = enum_Foo.B;
-        \\pub const FooC = enum_Foo.C;
         \\pub const enum_Foo = extern enum {
         \\    A,
         \\    B,
@@ -1509,7 +1462,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    var a = _arg_a;
         \\    var b = _arg_b;
         \\    var c = _arg_c;
-        \\    var d: enum_Foo = @as(enum_Foo, FooA);
+        \\    var d: enum_Foo = @intToEnum(enum_Foo, FooA);
         \\    var e: c_int = @boolToInt(((a != 0) and (b != 0)));
         \\    var f: c_int = @boolToInt(((b != 0) and (c != null)));
         \\    var g: c_int = @boolToInt(((a != 0) and (c != null)));
@@ -1543,8 +1496,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    x: c_int,
         \\    y: c_int,
         \\};
-        \\pub const BarA = enum_Bar.A;
-        \\pub const BarB = enum_Bar.B;
+    ,
         \\pub const enum_Bar = extern enum {
         \\    A,
         \\    B,
@@ -1746,9 +1698,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return 4;
         \\}
     , &[_][]const u8{
-        \\pub const A = enum_SomeEnum.A;
-        \\pub const B = enum_SomeEnum.B;
-        \\pub const C = enum_SomeEnum.C;
         \\pub const enum_SomeEnum = extern enum {
         \\    A,
         \\    B,
@@ -1863,26 +1812,26 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    i -= 1;
         \\    u +%= 1;
         \\    u -%= 1;
-        \\    i = blk: {
+        \\    i = (blk: {
         \\        const _ref_1 = &i;
         \\        _ref_1.* += 1;
         \\        break :blk _ref_1.*;
-        \\    };
-        \\    i = blk: {
+        \\    });
+        \\    i = (blk: {
         \\        const _ref_2 = &i;
         \\        _ref_2.* -= 1;
         \\        break :blk _ref_2.*;
-        \\    };
-        \\    u = blk: {
+        \\    });
+        \\    u = (blk: {
         \\        const _ref_3 = &u;
         \\        _ref_3.* +%= 1;
         \\        break :blk _ref_3.*;
-        \\    };
-        \\    u = blk: {
+        \\    });
+        \\    u = (blk: {
         \\        const _ref_4 = &u;
         \\        _ref_4.* -%= 1;
         \\        break :blk _ref_4.*;
-        \\    };
+        \\    });
         \\}
     });
 
@@ -2062,30 +2011,30 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    i -= 1;
         \\    u +%= 1;
         \\    u -%= 1;
-        \\    i = blk: {
+        \\    i = (blk: {
         \\        const _ref_1 = &i;
         \\        const _tmp_2 = _ref_1.*;
         \\        _ref_1.* += 1;
         \\        break :blk _tmp_2;
-        \\    };
-        \\    i = blk: {
+        \\    });
+        \\    i = (blk: {
         \\        const _ref_3 = &i;
         \\        const _tmp_4 = _ref_3.*;
         \\        _ref_3.* -= 1;
         \\        break :blk _tmp_4;
-        \\    };
-        \\    u = blk: {
+        \\    });
+        \\    u = (blk: {
         \\        const _ref_5 = &u;
         \\        const _tmp_6 = _ref_5.*;
         \\        _ref_5.* +%= 1;
         \\        break :blk _tmp_6;
-        \\    };
-        \\    u = blk: {
+        \\    });
+        \\    u = (blk: {
         \\        const _ref_7 = &u;
         \\        const _tmp_8 = _ref_7.*;
         \\        _ref_7.* -%= 1;
         \\        break :blk _tmp_8;
-        \\    };
+        \\    });
         \\}
     });
 
@@ -2172,6 +2121,58 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const FOO_CHAR = '\x3f';
     });
 
+    cases.add_2("enums",
+        \\enum Foo {
+        \\    FooA,
+        \\    FooB,
+        \\    Foo1,
+        \\};
+    , &[_][]const u8{
+        \\pub const enum_Foo = extern enum {
+        \\    A,
+        \\    B,
+        \\    @"1",
+        \\};
+    ,
+        \\pub const FooA = 0;
+    ,
+        \\pub const FooB = 1;
+    ,
+        \\pub const Foo1 = 2;
+    ,
+        \\pub const Foo = enum_Foo;
+    });
+
+    cases.add_2("enums",
+        \\enum Foo {
+        \\    FooA = 2,
+        \\    FooB = 5,
+        \\    Foo1,
+        \\};
+    , &[_][]const u8{
+        \\pub const enum_Foo = extern enum {
+        \\    A = 2,
+        \\    B = 5,
+        \\    @"1" = 6,
+        \\};
+    ,
+        \\pub const FooA = 2;
+    ,
+        \\pub const FooB = 5;
+    ,
+        \\pub const Foo1 = 6;
+    ,
+        \\pub const Foo = enum_Foo;
+    });
+
+    cases.add_2("macro cast",
+    \\#define FOO(bar) baz((void *)(baz))
+    , &[_][]const u8{
+        \\pub inline fn FOO(bar: var) @TypeOf(baz(if (@typeId(@TypeOf(baz)) == .Pointer) @ptrCast([*c]void, baz) else if (@typeId(@TypeOf(baz)) == .Int) @intToPtr([*c]void, baz) else @as([*c]void, baz))) {
+        \\    return baz(if (@typeId(@TypeOf(baz)) == .Pointer) @ptrCast([*c]void, baz) else if (@typeId(@TypeOf(baz)) == .Int) @intToPtr([*c]void, baz) else @as([*c]void, baz));
+        \\}
+    });
+
     /////////////// Cases for only stage1 because stage2 behavior is better ////////////////
     cases.addC("Parameterless function prototypes",
         \\void foo() {}
@@ -3124,4 +3125,48 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     ,
         \\pub const FOO_CHAR = 63;
     });
+
+    cases.add("enums",
+        \\enum Foo {
+        \\    FooA,
+        \\    FooB,
+        \\    Foo1,
+        \\};
+    , &[_][]const u8{
+        \\pub const enum_Foo = extern enum {
+        \\    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;
+    });
+
+    cases.add("enums",
+        \\enum Foo {
+        \\    FooA = 2,
+        \\    FooB = 5,
+        \\    Foo1,
+        \\};
+    , &[_][]const u8{
+        \\pub const enum_Foo = extern enum {
+        \\    A = 2,
+        \\    B = 5,
+        \\    @"1" = 6,
+        \\};
+    ,
+        \\pub const FooA = enum_Foo.A;
+    ,
+        \\pub const FooB = enum_Foo.B;
+    ,
+        \\pub const Foo1 = enum_Foo.@"1";
+    ,
+        \\pub const Foo = enum_Foo;
+    });
 }