diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 25cbea1cc7..d24001cf94 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -610,7 +610,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { try transCreateNodeUndefinedLiteral(c); } else if (storage_class != .Extern) { eq_tok = try appendToken(c, .Equal, "="); - init_node = try transCreateNodeTypeIdentifier(c, "undefined"); + init_node = try transCreateNodeIdentifierUnchecked(c, "undefined"); } const linksection_expr = blk: { @@ -4814,7 +4814,7 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node { return &identifier.base; } -fn transCreateNodeTypeIdentifier(c: *Context, name: []const u8) !*ast.Node { +fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node { const token_index = try appendTokenFmt(c, .Identifier, "{}", .{name}); const identifier = try c.a().create(ast.Node.Identifier); identifier.* = .{ @@ -5368,15 +5368,15 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, return parseCNumLit(c, tok, source, source_loc); }, // eventually this will be replaced by std.c.parse which will handle these correctly - .Keyword_void => return transCreateNodeTypeIdentifier(c, "c_void"), - .Keyword_bool => return transCreateNodeTypeIdentifier(c, "bool"), - .Keyword_double => return transCreateNodeTypeIdentifier(c, "f64"), - .Keyword_long => return transCreateNodeTypeIdentifier(c, "c_long"), - .Keyword_int => return transCreateNodeTypeIdentifier(c, "c_int"), - .Keyword_float => return transCreateNodeTypeIdentifier(c, "f32"), - .Keyword_short => return transCreateNodeTypeIdentifier(c, "c_short"), - .Keyword_char => return transCreateNodeTypeIdentifier(c, "c_char"), - .Keyword_unsigned => return transCreateNodeTypeIdentifier(c, "c_uint"), + .Keyword_void => return transCreateNodeIdentifierUnchecked(c, "c_void"), + .Keyword_bool => return transCreateNodeIdentifierUnchecked(c, "bool"), + .Keyword_double => return transCreateNodeIdentifierUnchecked(c, "f64"), + .Keyword_long => return transCreateNodeIdentifierUnchecked(c, "c_long"), + .Keyword_int => return transCreateNodeIdentifierUnchecked(c, "c_int"), + .Keyword_float => return transCreateNodeIdentifierUnchecked(c, "f32"), + .Keyword_short => return transCreateNodeIdentifierUnchecked(c, "c_short"), + .Keyword_char => return transCreateNodeIdentifierUnchecked(c, "c_char"), + .Keyword_unsigned => return transCreateNodeIdentifierUnchecked(c, "c_uint"), .Identifier => { const mangled_name = scope.getAlias(source[tok.start..tok.end]); return transCreateNodeIdentifier(c, mangled_name); @@ -5512,6 +5512,8 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, var node = try parseCPrimaryExpr(c, it, source, source_loc, scope); while (true) { const tok = it.next().?; + var op_token: ast.TokenIndex = undefined; + var op_id: ast.Node.InfixOp.Op = undefined; switch (tok.id) { .Period => { const name_tok = it.next().?; @@ -5528,6 +5530,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, } node = try transCreateNodeFieldAccess(c, node, source[name_tok.start..name_tok.end]); + continue; }, .Arrow => { const name_tok = it.next().?; @@ -5542,9 +5545,16 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, ); return error.ParseError; } - - const deref = try transCreateNodePtrDeref(c, node); + // deref is often used together with casts so we group the lhs expression + const group = try c.a().create(ast.Node.GroupedExpression); + group.* = .{ + .lparen = try appendToken(c, .LParen, "("), + .expr = node, + .rparen = try appendToken(c, .RParen, ")"), + }; + const deref = try transCreateNodePtrDeref(c, &group.base); node = try transCreateNodeFieldAccess(c, deref, source[name_tok.start..name_tok.end]); + continue; }, .Asterisk => { if (it.peek().?.id == .RParen) { @@ -5568,161 +5578,57 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, return &ptr.base; } else { // expr * expr - const op_token = try appendToken(c, .Asterisk, "*"); - const rhs = try parseCPrimaryExpr(c, it, source, source_loc, scope); - const mul_node = try c.a().create(ast.Node.InfixOp); - mul_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .BitShiftLeft, - .rhs = rhs, - }; - node = &mul_node.base; + op_token = try appendToken(c, .Asterisk, "*"); + op_id = .BitShiftLeft; } }, .AngleBracketAngleBracketLeft => { - const op_token = try appendToken(c, .AngleBracketAngleBracketLeft, "<<"); - const rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const bitshift_node = try c.a().create(ast.Node.InfixOp); - bitshift_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .BitShiftLeft, - .rhs = rhs, - }; - node = &bitshift_node.base; + op_token = try appendToken(c, .AngleBracketAngleBracketLeft, "<<"); + op_id = .BitShiftLeft; }, .AngleBracketAngleBracketRight => { - const op_token = try appendToken(c, .AngleBracketAngleBracketRight, ">>"); - const rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const bitshift_node = try c.a().create(ast.Node.InfixOp); - bitshift_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .BitShiftRight, - .rhs = rhs, - }; - node = &bitshift_node.base; + op_token = try appendToken(c, .AngleBracketAngleBracketRight, ">>"); + op_id = .BitShiftRight; }, .Pipe => { - const op_token = try appendToken(c, .Pipe, "|"); - const rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const or_node = try c.a().create(ast.Node.InfixOp); - or_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .BitOr, - .rhs = rhs, - }; - node = &or_node.base; + op_token = try appendToken(c, .Pipe, "|"); + op_id = .BitOr; }, .Ampersand => { - const op_token = try appendToken(c, .Ampersand, "&"); - const rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const bitand_node = try c.a().create(ast.Node.InfixOp); - bitand_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .BitAnd, - .rhs = rhs, - }; - node = &bitand_node.base; + op_token = try appendToken(c, .Ampersand, "&"); + op_id .BitAnd; }, .Plus => { - const op_token = try appendToken(c, .Plus, "+"); - const rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const add_node = try c.a().create(ast.Node.InfixOp); - add_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .Add, - .rhs = rhs, - }; - node = &add_node.base; + op_token = try appendToken(c, .Plus, "+"); + op_id = .Add; }, .Minus => { - const op_token = try appendToken(c, .Minus, "-"); - const rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const sub_node = try c.a().create(ast.Node.InfixOp); - sub_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .Sub, - .rhs = rhs, - }; - node = &sub_node.base; + op_token = try appendToken(c, .Minus, "-"); + op_id .Sub; }, .AmpersandAmpersand => { - const op_token = try appendToken(c, .Keyword_and, "and"); - const rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const and_node = try c.a().create(ast.Node.InfixOp); - and_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .BoolAnd, - .rhs = rhs, - }; - node = &and_node.base; + op_token = try appendToken(c, .Keyword_and, "and"); + op_id = .BoolAnd; }, .PipePipe => { - const op_token = try appendToken(c, .Keyword_or, "or"); - const rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const or_node = try c.a().create(ast.Node.InfixOp); - or_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .BoolOr, - .rhs = rhs, - }; - node = &or_node.base; + op_token = try appendToken(c, .Keyword_or, "or"); + op_id = .BoolOr; }, .AngleBracketRight => { - const op_token = try appendToken(c, .AngleBracketRight, ">"); - const rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const and_node = try c.a().create(ast.Node.InfixOp); - and_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .GreaterThan, - .rhs = rhs, - }; - node = &and_node.base; + op_token = try appendToken(c, .AngleBracketRight, ">"); + op_id = .GreaterThan; }, .AngleBracketRightEqual => { - const op_token = try appendToken(c, .AngleBracketRightEqual, ">="); - const rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const and_node = try c.a().create(ast.Node.InfixOp); - and_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .GreaterOrEqual, - .rhs = rhs, - }; - node = &and_node.base; + op_token = try appendToken(c, .AngleBracketRightEqual, ">="); + op_id = .GreaterOrEqual; }, .AngleBracketLeft => { - const op_token = try appendToken(c, .AngleBracketLeft, "<"); - const rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const and_node = try c.a().create(ast.Node.InfixOp); - and_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .LessThan, - .rhs = rhs, - }; - node = &and_node.base; + op_token = try appendToken(c, .AngleBracketLeft, "<"); + op_id = .LessThan; }, .AngleBracketLeftEqual => { - const op_token = try appendToken(c, .AngleBracketLeftEqual, "<="); - const rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const and_node = try c.a().create(ast.Node.InfixOp); - and_node.* = .{ - .op_token = op_token, - .lhs = node, - .op = .LessOrEqual, - .rhs = rhs, - }; - node = &and_node.base; + op_token = try appendToken(c, .AngleBracketLeftEqual, "<="); + op_id = .LessOrEqual; }, .LBracket => { const arr_node = try transCreateNodeArrayAccess(c, node); @@ -5740,6 +5646,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, ); return error.ParseError; } + continue; }, .LParen => { const call_node = try transCreateNodeFnCall(c, node); @@ -5765,12 +5672,39 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, } call_node.rtoken = try appendToken(c, .RParen, ")"); node = &call_node.base; + continue; + }, + .BangEqual => { + op_token = try appendToken(c, .BangEqual, "!="); + op_id = .BangEqual; + }, + .EqualEqual => { + op_token = try appendToken(c, .EqualEqual, "=="); + op_id = .EqualEqual; + }, + .Slash => { + // unsigned/float division uses the operator + op_id = .Div; + op_token = try appendToken(c, .Slash, "/"); + }, + .Percent => { + // unsigned/float division uses the operator + op_id = .Mod; + op_token = try appendToken(c, .Percent, "%"); }, else => { _ = it.prev(); return node; }, } + const op_node = try c.a().create(ast.Node.InfixOp); + op_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = op_id, + .rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope), + }; + node = &op_node.base; } } @@ -5788,14 +5722,33 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); return &node.base; }, + .Plus => return try parseCPrefixOpExpr(c, it, source, source_loc, scope), .Tilde => { const node = try transCreateNodePrefixOp(c, .BitNot, .Tilde, "~"); node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); return &node.base; }, .Asterisk => { - const prefix_op_expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - return try transCreateNodePtrDeref(c, prefix_op_expr); + // deref is often used together with casts so we group the lhs expression + const group = try c.a().create(ast.Node.GroupedExpression); + group.* = .{ + .lparen = try appendToken(c, .LParen, "("), + .expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope), + .rparen = try appendToken(c, .RParen, ")"), + }; + return try transCreateNodePtrDeref(c, &group.base); + }, + .Ampersand => { + // address of is often used together with casts so we group the rhs expression + const node = try transCreateNodePrefixOp(c, .AddressOf, .Ampersand, "&"); + const group = try c.a().create(ast.Node.GroupedExpression); + group.* = .{ + .lparen = try appendToken(c, .LParen, "("), + .expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope), + .rparen = try appendToken(c, .RParen, ")"), + }; + node.rhs = &group.base; + return &node.base; }, else => { _ = it.prev(); diff --git a/test/translate_c.zig b/test/translate_c.zig index 29a65c8624..3d0843d272 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -5,7 +5,7 @@ const CrossTarget = std.zig.CrossTarget; pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("macro comma operator", \\#define foo (foo, bar) - \\#define bar(x) (x, 3, 4, 5 * 6, baz(1, 2), 2, baz(1,2)) + \\#define bar(x) (&x, +3, 4 == 4, 5 * 6, baz(1, 2), 2 % 2, baz(1,2)) , &[_][]const u8{ \\pub const foo = blk: { \\ _ = foo; @@ -14,12 +14,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub inline fn bar(x: var) @TypeOf(baz(1, 2)) { \\ return blk: { - \\ _ = x; + \\ _ = &(x); \\ _ = 3; - \\ _ = 4; + \\ _ = 4 == 4; \\ _ = 5 * 6; \\ _ = baz(1, 2); - \\ _ = 2; + \\ _ = 2 % 2; \\ break :blk baz(1, 2); \\ }; \\} @@ -1993,7 +1993,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub const DOT = a.b; , - \\pub const ARROW = a.*.b; + \\pub const ARROW = (a).*.b; }); cases.add("array access",