diff --git a/src-self-hosted/c_tokenizer.zig b/src-self-hosted/c_tokenizer.zig index 1d166cafe9..cc862a0e67 100644 --- a/src-self-hosted/c_tokenizer.zig +++ b/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, } }, diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 489c809e4f..478232b20a 100644 --- a/src-self-hosted/translate_c.zig +++ b/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) diff --git a/test/translate_c.zig b/test/translate_c.zig index d7b5d7208c..917bd98d09 100644 --- a/test/translate_c.zig +++ b/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; + }); }