authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-11 12:31:48+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-16 16:40:05+02:00
logc30c2f7c133861a8749a9ffbc2bf6a49d9c6283e
tree81ac639745b54cb969e40ca953762f4511fdd77f
parent450b718b9ec21b328966469c851983ee8969e577
signature Commit is signed but in an unrecognized format.

translate-c: convert assignment and conditional exprs


2 files changed, 234 insertions(+), 522 deletions(-)

src/translate_c.zig+219-507
...@@ -1144,18 +1144,16 @@ fn transBinaryOperator(...@@ -1144,18 +1144,16 @@ fn transBinaryOperator(
1144 }1144 }
1145 },1145 },
1146 .Shl => {1146 .Shl => {
1147 const node = try transCreateNodeShiftOp(c, scope, stmt, .shl);1147 return transCreateNodeShiftOp(c, scope, stmt, .shl, result_used);
1148 return maybeSuppressResult(c, scope, result_used, node);
1149 },1148 },
1150 .Shr => {1149 .Shr => {
1151 const node = try transCreateNodeShiftOp(c, scope, stmt, .shr);1150 return transCreateNodeShiftOp(c, scope, stmt, .shr, result_used);
1152 return maybeSuppressResult(c, scope, result_used, node);
1153 },1151 },
1154 .LAnd => {1152 .LAnd => {
1155 return transCreateNodeBoolInfixOp(c, scope, stmt, .bool_and, result_used, true);1153 return transCreateNodeBoolInfixOp(c, scope, stmt, .bool_and, result_used);
1156 },1154 },
1157 .LOr => {1155 .LOr => {
1158 return transCreateNodeBoolInfixOp(c, scope, stmt, .bool_or, result_used, true);1156 return transCreateNodeBoolInfixOp(c, scope, stmt, .bool_or, result_used);
1159 },1157 },
1160 else => {},1158 else => {},
1161 }1159 }
...@@ -1233,15 +1231,7 @@ fn transBinaryOperator(...@@ -1233,15 +1231,7 @@ fn transBinaryOperator(
1233 else1231 else
1234 rhs_uncasted;1232 rhs_uncasted;
12351233
1236 const payload = try c.arena.create(ast.Payload.BinOp);1234 return transCreateNodeInfixOp(c, scope, op_id, lhs, rhs, used);
1237 payload.* = .{
1238 .base = .{ .tag = op_id },
1239 .data = .{
1240 .lhs = lhs,
1241 .rhs = rhs,
1242 },
1243 };
1244 return maybeSuppressResult(c, scope, used, Node.initPayload(&payload.base));
1245}1235}
12461236
1247fn transCompoundStmtInline(1237fn transCompoundStmtInline(
...@@ -1716,7 +1706,7 @@ fn transStringLiteralAsArray(...@@ -1716,7 +1706,7 @@ fn transStringLiteralAsArray(
1716 init_list[i] = try transCreateCharLitNode(c, narrow, code_unit);1706 init_list[i] = try transCreateCharLitNode(c, narrow, code_unit);
1717 }1707 }
1718 while (i < array_size) : (i += 1) {1708 while (i < array_size) : (i += 1) {
1719 init_list[i] = try transCreateNodeInt(c, 0);1709 init_list[i] = try transCreateNodeNumber(c, 0);
1720 }1710 }
17211711
1722 return Node.array_init.create(c.arena, init_list);1712 return Node.array_init.create(c.arena, init_list);
...@@ -2398,7 +2388,7 @@ fn transCharLiteral(...@@ -2398,7 +2388,7 @@ fn transCharLiteral(
2398 // C has a somewhat obscure feature called multi-character character constant2388 // C has a somewhat obscure feature called multi-character character constant
2399 // e.g. 'abcd'2389 // e.g. 'abcd'
2400 const int_lit_node = if (kind == .Ascii and val > 255)2390 const int_lit_node = if (kind == .Ascii and val > 255)
2401 try transCreateNodeInt(c, val)2391 try transCreateNodeNumber(c, val)
2402 else2392 else
2403 try transCreateCharLitNode(c, narrow, val);2393 try transCreateCharLitNode(c, narrow, val);
24042394
...@@ -2434,8 +2424,8 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used:...@@ -2434,8 +2424,8 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used:
2434 .val = try transStmt(c, &block_scope.base, it[0], .used, .r_value),2424 .val = try transStmt(c, &block_scope.base, it[0], .used, .r_value),
2435 });2425 });
2436 try block_scope.statements.append(break_node);2426 try block_scope.statements.append(break_node);
24372427 const res = try block_scope.complete(c);
2438 return block_scope.complete(c);2428 return maybeSuppressResult(c, scope, used, res);
2439}2429}
24402430
2441fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!Node {2431fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!Node {
...@@ -2460,8 +2450,9 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re...@@ -2460,8 +2450,9 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re
2460 const decl = @ptrCast(*const clang.NamedDecl, member_decl);2450 const decl = @ptrCast(*const clang.NamedDecl, member_decl);
2461 break :blk try c.str(decl.getName_bytes_begin());2451 break :blk try c.str(decl.getName_bytes_begin());
2462 };2452 };
2453 const ident = try Node.identifier.create(c.arena, name);
24632454
2464 const node = try Node.field_access.create(c.arena, .{ .container = container_node, .name = name});2455 const node = try Node.field_access.create(c.arena, .{ .lhs = container_node, .rhs = ident});
2465 return maybeSuppressResult(c, scope, result_used, node);2456 return maybeSuppressResult(c, scope, result_used, node);
2466}2457}
24672458
...@@ -2716,15 +2707,9 @@ fn transCreatePreCrement(...@@ -2716,15 +2707,9 @@ fn transCreatePreCrement(
2716 // common case2707 // common case
2717 // c: ++expr2708 // c: ++expr
2718 // zig: expr += 12709 // zig: expr += 1
2719 const payload = try c.arena.create(ast.Payload.BinOp);2710 const lhs = try transExpr(c, scope, op_expr, .used, .r_value);
2720 payload.* = .{2711 const rhs = Node.one_literal.init();
2721 .base = .{ .tag = op },2712 return transCreateNodeInfixOp(c, scope, op, lhs, rhs, .used);
2722 .data = .{
2723 .lhs = try transExpr(c, scope, op_expr, .used, .r_value),
2724 .rhs = Node.one_literal.init(),
2725 }
2726 };
2727 return Node.initPayload(&payload.base);
2728 }2713 }
2729 // worst case2714 // worst case
2730 // c: ++expr2715 // c: ++expr
...@@ -2744,20 +2729,15 @@ fn transCreatePreCrement(...@@ -2744,20 +2729,15 @@ fn transCreatePreCrement(
27442729
2745 const lhs_node = try Node.identifier.create(c.arena, ref);2730 const lhs_node = try Node.identifier.create(c.arena, ref);
2746 const ref_node = try Node.deref.create(c.arena, lhs_node);2731 const ref_node = try Node.deref.create(c.arena, lhs_node);
2747 const payload = try c.arena.create(ast.Payload.BinOp);2732 const node = try transCreateNodeInfixOp(c, scope, op, ref_node, Node.one_literal.init(), .used);
2748 payload.* = .{2733 try block_scope.statements.append(node);
2749 .base = .{ .tag = op },
2750 .data = .{
2751 .lhs = ref_node,
2752 .rhs = Node.one_literal.init(),
2753 }
2754 };
2755 try block_scope.statements.append(Node.initPayload(&payload.base));
27562734
2757 return Node.break_val.create(c.arena, .{2735 const break_node = try Node.break_val.create(c.arena, .{
2758 .label = block_scope.label,2736 .label = block_scope.label,
2759 .val = ref_node,2737 .val = ref_node,
2760 });2738 });
2739 try block_scope.statements.append(break_node);
2740 return block_scope.complete(c);
2761}2741}
27622742
2763fn transCreatePostCrement(2743fn transCreatePostCrement(
...@@ -2771,17 +2751,11 @@ fn transCreatePostCrement(...@@ -2771,17 +2751,11 @@ fn transCreatePostCrement(
27712751
2772 if (used == .unused) {2752 if (used == .unused) {
2773 // common case2753 // common case
2774 // c: ++expr2754 // c: expr++
2775 // zig: expr += 12755 // zig: expr += 1
2776 const payload = try c.arena.create(ast.Payload.BinOp);2756 const lhs = try transExpr(c, scope, op_expr, .used, .r_value);
2777 payload.* = .{2757 const rhs = Node.one_literal.init();
2778 .base = .{ .tag = op },2758 return transCreateNodeInfixOp(c, scope, op, lhs, rhs, .used);
2779 .data = .{
2780 .lhs = try transExpr(c, scope, op_expr, .used, .r_value),
2781 .rhs = Node.one_literal.init(),
2782 }
2783 };
2784 return Node.initPayload(&payload.base);
2785 }2759 }
2786 // worst case2760 // worst case
2787 // c: expr++2761 // c: expr++
...@@ -2807,44 +2781,39 @@ fn transCreatePostCrement(...@@ -2807,44 +2781,39 @@ fn transCreatePostCrement(
2807 const tmp_decl = try Node.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node});2781 const tmp_decl = try Node.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node});
2808 try block_scope.statements.append(tmp_decl);2782 try block_scope.statements.append(tmp_decl);
28092783
2810 const payload = try c.arena.create(ast.Payload.BinOp);2784 const node = try transCreateNodeInfixOp(c, scope, op, ref_node, Node.one_literal.init(), .used);
2811 payload.* = .{2785 try block_scope.statements.append(node);
2812 .base = .{ .tag = op },
2813 .data = .{
2814 .lhs = ref_node,
2815 .rhs = Node.one_literal.init(),
2816 }
2817 };
2818 try block_scope.statements.append(Node.initPayload(&payload.base));
28192786
2820 return Node.break_val.create(c.arena, .{2787 const break_node = try Node.break_val.create(c.arena, .{
2821 .label = block_scope.label,2788 .label = block_scope.label,
2822 .val = try Node.identifier.create(c.arena, tmp),2789 .val = try Node.identifier.create(c.arena, tmp),
2823 });2790 });
2791 try block_scope.statements.append(break_node);
2792 return block_scope.complete(c);
2824}2793}
28252794
2826fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.CompoundAssignOperator, used: ResultUsed) TransError!*ast.Node {2795fn transCompoundAssignOperator(c: *Context, scope: *Scope, stmt: *const clang.CompoundAssignOperator, used: ResultUsed) TransError!Node {
2827 switch (stmt.getOpcode()) {2796 switch (stmt.getOpcode()) {
2828 .MulAssign => if (qualTypeHasWrappingOverflow(stmt.getType()))2797 .MulAssign => if (qualTypeHasWrappingOverflow(stmt.getType()))
2829 return transCreateCompoundAssign(rp, scope, stmt, .AssignMulWrap, .AsteriskPercentEqual, "*%=", .MulWrap, .AsteriskPercent, "*%", used)2798 return transCreateCompoundAssign(c, scope, stmt, .assign_mul_wrap, used)
2830 else2799 else
2831 return transCreateCompoundAssign(rp, scope, stmt, .AssignMul, .AsteriskEqual, "*=", .Mul, .Asterisk, "*", used),2800 return transCreateCompoundAssign(c, scope, stmt, .assign_mul, used),
2832 .AddAssign => if (qualTypeHasWrappingOverflow(stmt.getType()))2801 .AddAssign => if (qualTypeHasWrappingOverflow(stmt.getType()))
2833 return transCreateCompoundAssign(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", .AddWrap, .PlusPercent, "+%", used)2802 return transCreateCompoundAssign(c, scope, stmt, .assign_add_wrap, used)
2834 else2803 else
2835 return transCreateCompoundAssign(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", .Add, .Plus, "+", used),2804 return transCreateCompoundAssign(c, scope, stmt, .assign_add, used),
2836 .SubAssign => if (qualTypeHasWrappingOverflow(stmt.getType()))2805 .SubAssign => if (qualTypeHasWrappingOverflow(stmt.getType()))
2837 return transCreateCompoundAssign(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", .SubWrap, .MinusPercent, "-%", used)2806 return transCreateCompoundAssign(c, scope, stmt, .assign_sub_wrap, used)
2838 else2807 else
2839 return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used),2808 return transCreateCompoundAssign(c, scope, stmt, .assign_sub, used),
2840 .DivAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignDiv, .SlashEqual, "/=", .Div, .Slash, "/", used),2809 .DivAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_div, used),
2841 .RemAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignMod, .PercentEqual, "%=", .Mod, .Percent, "%", used),2810 .RemAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_mod, used),
2842 .ShlAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftLeft, .AngleBracketAngleBracketLeftEqual, "<<=", .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<", used),2811 .ShlAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_shl, used),
2843 .ShrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftRight, .AngleBracketAngleBracketRightEqual, ">>=", .BitShiftRight, .AngleBracketAngleBracketRight, ">>", used),2812 .ShrAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_shr, used),
2844 .AndAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitAnd, .AmpersandEqual, "&=", .BitAnd, .Ampersand, "&", used),2813 .AndAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_bit_and, used),
2845 .XorAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitXor, .CaretEqual, "^=", .BitXor, .Caret, "^", used),2814 .XorAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_bit_xor, used),
2846 .OrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitOr, .PipeEqual, "|=", .BitOr, .Pipe, "|", used),2815 .OrAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_bit_or, used),
2847 else => return revertAndWarn(2816 else => return fail(
2848 rp,2817 rp,
2849 error.UnsupportedTranslation,2818 error.UnsupportedTranslation,
2850 stmt.getBeginLoc(),2819 stmt.getBeginLoc(),
...@@ -2855,25 +2824,20 @@ fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const cla...@@ -2855,25 +2824,20 @@ fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const cla
2855}2824}
28562825
2857fn transCreateCompoundAssign(2826fn transCreateCompoundAssign(
2858 rp: RestorePoint,2827 c: *Context,
2859 scope: *Scope,2828 scope: *Scope,
2860 stmt: *const clang.CompoundAssignOperator,2829 stmt: *const clang.CompoundAssignOperator,
2861 assign_op: ast.Node.Tag,2830 op: Node.Tag,
2862 assign_tok_id: std.zig.Token.Id,
2863 assign_bytes: []const u8,
2864 bin_op: ast.Node.Tag,
2865 bin_tok_id: std.zig.Token.Id,
2866 bin_bytes: []const u8,
2867 used: ResultUsed,2831 used: ResultUsed,
2868) TransError!*ast.Node {2832) TransError!Node {
2869 const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight;2833 const is_shift = op == .assign_shl or op == .assign_shr;
2870 const is_div = bin_op == .Div;2834 const is_div = op == .assign_div;
2871 const is_mod = bin_op == .Mod;2835 const is_mod = op == .assign_mod;
2872 const lhs = stmt.getLHS();2836 const lhs = stmt.getLHS();
2873 const rhs = stmt.getRHS();2837 const rhs = stmt.getRHS();
2874 const loc = stmt.getBeginLoc();2838 const loc = stmt.getBeginLoc();
2875 const lhs_qt = getExprQualType(rp.c, lhs);2839 const lhs_qt = getExprQualType(c, lhs);
2876 const rhs_qt = getExprQualType(rp.c, rhs);2840 const rhs_qt = getExprQualType(c, rhs);
2877 const is_signed = cIsSignedInteger(lhs_qt);2841 const is_signed = cIsSignedInteger(lhs_qt);
2878 const requires_int_cast = blk: {2842 const requires_int_cast = blk: {
2879 const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt);2843 const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt);
...@@ -2885,146 +2849,99 @@ fn transCreateCompoundAssign(...@@ -2885,146 +2849,99 @@ fn transCreateCompoundAssign(
2885 // c: lhs += rhs2849 // c: lhs += rhs
2886 // zig: lhs += rhs2850 // zig: lhs += rhs
2887 if ((is_mod or is_div) and is_signed) {2851 if ((is_mod or is_div) and is_signed) {
2888 const op_token = try appendToken(rp.c, .Equal, "=");2852 const lhs_node = try transExpr(c, scope, lhs, .used, .l_value);
2889 const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);2853 const rhs_node = try transExpr(c, scope, rhs, .used, .r_value);
2890 const builtin = if (is_mod) "@rem" else "@divTrunc";2854 const builtin = if (is_mod)
2891 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);2855 try Node.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node })
2892 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);2856 else
2893 builtin_node.params()[0] = lhs_node;2857 try Node.divTrunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node });
2894 _ = try appendToken(rp.c, .Comma, ",");2858
2895 builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value);2859 return transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used);
2896 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2897 op_node.* = .{
2898 .base = .{ .tag = .Assign },
2899 .op_token = op_token,
2900 .lhs = lhs_node,
2901 .rhs = &builtin_node.base,
2902 };
2903 _ = try appendToken(rp.c, .Semicolon, ";");
2904 return &op_node.base;
2905 }2860 }
29062861
2907 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);2862 const lhs_node = try transExpr(c, scope, lhs, .used, .l_value);
2908 const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
2909 var rhs_node = if (is_shift or requires_int_cast)2863 var rhs_node = if (is_shift or requires_int_cast)
2910 try transExprCoercing(rp, scope, rhs, .used, .r_value)2864 try transExprCoercing(c, scope, rhs, .used, .r_value)
2911 else2865 else
2912 try transExpr(rp, scope, rhs, .used, .r_value);2866 try transExpr(c, scope, rhs, .used, .r_value);
29132867
2914 if (is_shift or requires_int_cast) {2868 if (is_shift or requires_int_cast) {
2915 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);2869 // @intCast(rhs)
2916 const cast_to_type = if (is_shift)2870 const cast_to_type = if (is_shift)
2917 try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc)2871 try qualTypeToLog2IntRef(c, getExprQualType(c, rhs), loc)
2918 else2872 else
2919 try transQualType(rp, getExprQualType(rp.c, lhs), loc);2873 try transQualType(c, getExprQualType(c, lhs), loc);
2920 cast_node.params()[0] = cast_to_type;2874
2921 _ = try appendToken(rp.c, .Comma, ",");2875 rhs_node = try Node.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });
2922 cast_node.params()[1] = rhs_node;
2923 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2924 rhs_node = &cast_node.base;
2925 }2876 }
2926 if (scope.id != .Condition)2877
2927 _ = try appendToken(rp.c, .Semicolon, ";");2878 return transCreateNodeInfixOp(c, scope, assign_op, lhs_node, rhs_node, .used);
2928 return transCreateNodeInfixOp(rp, scope, lhs_node, assign_op, eq_token, rhs_node, .used, false);
2929 }2879 }
2930 // worst case2880 // worst case
2931 // c: lhs += rhs2881 // c: lhs += rhs
2932 // zig: (blk: {2882 // zig: (blk: {
2933 // zig: const _ref = &lhs;2883 // zig: const _ref = &lhs;
2934 // zig: _ref.* = _ref.* + rhs;2884 // zig: _ref.* += rhs;
2935 // zig: break :blk _ref.*2885 // zig: break :blk _ref.*
2936 // zig: })2886 // zig: })
2937 var block_scope = try Scope.Block.init(rp.c, scope, true);2887 var block_scope = try Scope.Block.init(c, scope, true);
2938 defer block_scope.deinit();2888 defer block_scope.deinit();
2939 const ref = try block_scope.makeMangledName(rp.c, "ref");2889 const ref = try block_scope.makeMangledName(c, "ref");
2940
2941 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
2942 const name_tok = try appendIdentifier(rp.c, ref);
2943 const eq_token = try appendToken(rp.c, .Equal, "=");
2944 const addr_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
2945 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
2946 const init_node = &addr_node.base;
2947 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
2948 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
2949 .name_token = name_tok,
2950 .mut_token = mut_tok,
2951 .semicolon_token = semicolon_token,
2952 }, .{
2953 .eq_token = eq_token,
2954 .init_node = init_node,
2955 });
2956 try block_scope.statements.append(&node.base);
29572890
2958 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);2891 const expr = try transExpr(c, scope, op_expr, .used, .r_value);
2959 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);2892 const addr_of = try Node.address_of.create(c.arena, expr);
2960 _ = try appendToken(rp.c, .Semicolon, ";");2893 const ref_decl = try Node.var_simple.create(c.arena, .{ .name = ref, .init = addr_of});
2894 try block_scope.statements.append(ref_decl);
2895
2896 const lhs_node = try Node.identifier.create(c.arena, ref);
2897 const ref_node = try Node.deref.create(c.arena, lhs_node);
29612898
2962 if ((is_mod or is_div) and is_signed) {2899 if ((is_mod or is_div) and is_signed) {
2963 const op_token = try appendToken(rp.c, .Equal, "=");2900 const rhs_node = try transExpr(c, scope, rhs, .used, .r_value);
2964 const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);2901 const builtin = if (is_mod)
2965 const builtin = if (is_mod) "@rem" else "@divTrunc";2902 try Node.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node })
2966 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);2903 else
2967 builtin_node.params()[0] = try transCreateNodePtrDeref(rp.c, lhs_node);2904 try Node.divTrunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node });
2968 _ = try appendToken(rp.c, .Comma, ",");2905
2969 builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value);2906 const assign = try transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used);
2970 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");2907 try block_scope.statements.append(assign);
2971 _ = try appendToken(rp.c, .Semicolon, ";");
2972 op_node.* = .{
2973 .base = .{ .tag = .Assign },
2974 .op_token = op_token,
2975 .lhs = ref_node,
2976 .rhs = &builtin_node.base,
2977 };
2978 _ = try appendToken(rp.c, .Semicolon, ";");
2979 try block_scope.statements.append(&op_node.base);
2980 } else {2908 } else {
2981 const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);2909 var rhs_node = try transExpr(c, scope, rhs, .used, .r_value);
2982 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
29832910
2984 if (is_shift or requires_int_cast) {2911 if (is_shift or requires_int_cast) {
2985 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);2912 // @intCast(rhs)
2986 const cast_to_type = if (is_shift)2913 const cast_to_type = if (is_shift)
2987 try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc)2914 try qualTypeToLog2IntRef(c, getExprQualType(c, rhs), loc)
2988 else2915 else
2989 try transQualType(rp, getExprQualType(rp.c, lhs), loc);2916 try transQualType(c, getExprQualType(c, lhs), loc);
2990 cast_node.params()[0] = cast_to_type;2917
2991 _ = try appendToken(rp.c, .Comma, ",");2918 rhs_node = try Node.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });
2992 cast_node.params()[1] = rhs_node;
2993 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2994 rhs_node = &cast_node.base;
2995 }2919 }
29962920
2997 const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);2921 const assign = try transCreateNodeInfixOp(c, scope, op, ref_node, rhs_node, .used);
2998 _ = try appendToken(rp.c, .Semicolon, ";");
2999
3000 const ass_eq_token = try appendToken(rp.c, .Equal, "=");
3001 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, ass_eq_token, rhs_bin, .used, false);
3002 try block_scope.statements.append(assign);2922 try block_scope.statements.append(assign);
3003 }2923 }
30042924
3005 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, ref_node);2925 const break_node = try Node.break_val.create(c.arena, .{
3006 try block_scope.statements.append(&break_node.base);2926 .label = block_scope.label,
3007 const block_node = try block_scope.complete(rp.c);2927 .val = ref_node,
3008 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);2928 });
3009 grouped_expr.* = .{2929 try block_scope.statements.append(break_node);
3010 .lparen = try appendToken(rp.c, .LParen, "("),2930 return block_scope.complete(c);
3011 .expr = block_node,
3012 .rparen = try appendToken(rp.c, .RParen, ")"),
3013 };
3014 return &grouped_expr.base;
3015}2931}
30162932
3017fn transCPtrCast(2933fn transCPtrCast(
3018 rp: RestorePoint,2934 c: *Context,
3019 loc: clang.SourceLocation,2935 loc: clang.SourceLocation,
3020 dst_type: clang.QualType,2936 dst_type: clang.QualType,
3021 src_type: clang.QualType,2937 src_type: clang.QualType,
3022 expr: *ast.Node,2938 expr: Node,
3023) !*ast.Node {2939) !Node {
3024 const ty = dst_type.getTypePtr();2940 const ty = dst_type.getTypePtr();
3025 const child_type = ty.getPointeeType();2941 const child_type = ty.getPointeeType();
3026 const src_ty = src_type.getTypePtr();2942 const src_ty = src_type.getTypePtr();
3027 const src_child_type = src_ty.getPointeeType();2943 const src_child_type = src_ty.getPointeeType();
2944 const dst_type = try transType(c, ty, loc);
30282945
3029 if ((src_child_type.isConstQualified() and2946 if ((src_child_type.isConstQualified() and
3030 !child_type.isConstQualified()) or2947 !child_type.isConstQualified()) or
...@@ -3032,47 +2949,25 @@ fn transCPtrCast(...@@ -3032,47 +2949,25 @@ fn transCPtrCast(
3032 !child_type.isVolatileQualified()))2949 !child_type.isVolatileQualified()))
3033 {2950 {
3034 // Casting away const or volatile requires us to use @intToPtr2951 // Casting away const or volatile requires us to use @intToPtr
3035 const inttoptr_node = try rp.c.createBuiltinCall("@intToPtr", 2);2952 const ptr_to_int = try Node.ptr_to_int.create(c.arena, expr);
3036 const dst_type_node = try transType(rp, ty, loc);2953 const int_to_ptr = try Node.int_to_ptr.create(c.arena, .{ .lhs = dst_type, .rhs = ptr_to_int });
3037 inttoptr_node.params()[0] = dst_type_node;2954 return int_to_ptr;
3038 _ = try appendToken(rp.c, .Comma, ",");
3039
3040 const ptrtoint_node = try rp.c.createBuiltinCall("@ptrToInt", 1);
3041 ptrtoint_node.params()[0] = expr;
3042 ptrtoint_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3043
3044 inttoptr_node.params()[1] = &ptrtoint_node.base;
3045 inttoptr_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3046 return &inttoptr_node.base;
3047 } else {2955 } else {
3048 // Implicit downcasting from higher to lower alignment values is forbidden,2956 // Implicit downcasting from higher to lower alignment values is forbidden,
3049 // use @alignCast to side-step this problem2957 // use @alignCast to side-step this problem
3050 const ptrcast_node = try rp.c.createBuiltinCall("@ptrCast", 2);2958 const rhs = if (qualTypeCanon(child_type).isVoidType())
3051 const dst_type_node = try transType(rp, ty, loc);
3052 ptrcast_node.params()[0] = dst_type_node;
3053 _ = try appendToken(rp.c, .Comma, ",");
3054
3055 if (qualTypeCanon(child_type).isVoidType()) {
3056 // void has 1-byte alignment, so @alignCast is not needed2959 // void has 1-byte alignment, so @alignCast is not needed
3057 ptrcast_node.params()[1] = expr;2960 expr
3058 } else if (typeIsOpaque(rp.c, qualTypeCanon(child_type), loc)) {2961 else if (typeIsOpaque(c, qualTypeCanon(child_type), loc))
3059 // For opaque types a ptrCast is enough2962 // For opaque types a ptrCast is enough
3060 ptrcast_node.params()[1] = expr;2963 expr
3061 } else {2964 else blk: {
3062 const aligncast_node = try rp.c.createBuiltinCall("@alignCast", 2);2965 const child_type_node = try transQualType(c, child_type, loc);
3063 const alignof_node = try rp.c.createBuiltinCall("@alignOf", 1);2966 const alignof = try Node.alignof.create(c.arena, child_type_node);
3064 const child_type_node = try transQualType(rp, child_type, loc);2967 const align_cast = try Node.align_cast.create(c.arena, .{ .lhs = alignof, .rhs = expr });
3065 alignof_node.params()[0] = child_type_node;2968 break :blk align_cast;
3066 alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")");2969 };
3067 aligncast_node.params()[0] = &alignof_node.base;2970 return Node.ptr_cast.create(c.arena, .{ .lhs = dst_type, .rhs = rhs });
3068 _ = try appendToken(rp.c, .Comma, ",");
3069 aligncast_node.params()[1] = expr;
3070 aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3071 ptrcast_node.params()[1] = &aligncast_node.base;
3072 }
3073 ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3074
3075 return &ptrcast_node.base;
3076 }2971 }
3077}2972}
30782973
...@@ -3092,13 +2987,15 @@ fn transBreak(c: *Context, scope: *Scope) TransError!Node {...@@ -3092,13 +2987,15 @@ fn transBreak(c: *Context, scope: *Scope) TransError!Node {
3092fn transFloatingLiteral(c: *Context, scope: *Scope, stmt: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node {2987fn transFloatingLiteral(c: *Context, scope: *Scope, stmt: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node {
3093 // TODO use something more accurate2988 // TODO use something more accurate
3094 const dbl = stmt.getValueAsApproximateDouble();2989 const dbl = stmt.getValueAsApproximateDouble();
3095 const node = try Node.float_literal.create(c.arena, try std.fmt.allocPrint(c.arena, "{d}", .{dbl}));2990 const node = try transCreateNodeNumber(c, dbl);
3096 return maybeSuppressResult(c, scope, used, &node.base);2991 return maybeSuppressResult(c, scope, used, &node.base);
3097}2992}
30982993
3099fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.BinaryConditionalOperator, used: ResultUsed) TransError!*ast.Node {2994fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.BinaryConditionalOperator, used: ResultUsed) TransError!Node {
3100 // GNU extension of the ternary operator where the middle expression is2995 // GNU extension of the ternary operator where the middle expression is
3101 // omitted, the conditition itself is returned if it evaluates to true2996 // omitted, the conditition itself is returned if it evaluates to true
2997 const qt = @ptrCast(*const clang.Stmt, stmt).getType();
2998 const res_is_bool = qualTypeIsBoolean(qt);
3102 const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt);2999 const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt);
3103 const cond_expr = casted_stmt.getCond();3000 const cond_expr = casted_stmt.getCond();
3104 const true_expr = casted_stmt.getTrueExpr();3001 const true_expr = casted_stmt.getTrueExpr();
...@@ -3109,67 +3006,39 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const...@@ -3109,67 +3006,39 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
3109 // const _cond_temp = (cond_expr);3006 // const _cond_temp = (cond_expr);
3110 // break :blk if (_cond_temp) _cond_temp else (false_expr);3007 // break :blk if (_cond_temp) _cond_temp else (false_expr);
3111 // })3008 // })
3112 const lparen = try appendToken(rp.c, .LParen, "(");3009 var block_scope = try Scope.Block.init(c, scope, true);
3113
3114 var block_scope = try Scope.Block.init(rp.c, scope, true);
3115 defer block_scope.deinit();3010 defer block_scope.deinit();
31163011
3117 const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");3012 const mangled_name = try block_scope.makeMangledName(c, "cond_temp");
3118 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");3013 const init_node = try transExpr(c, &block_scope.base, cond_expr, .used, .r_value);
3119 const name_tok = try appendIdentifier(rp.c, mangled_name);3014 const ref_decl = try Node.var_simple.create(c.arena, .{ .name = mangled_name, .init = init_node});
3120 const eq_token = try appendToken(rp.c, .Equal, "=");3015 try block_scope.statements.append(ref_decl);
3121 const init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value);
3122 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3123 const tmp_var = try ast.Node.VarDecl.create(rp.c.arena, .{
3124 .name_token = name_tok,
3125 .mut_token = mut_tok,
3126 .semicolon_token = semicolon_token,
3127 }, .{
3128 .eq_token = eq_token,
3129 .init_node = init_node,
3130 });
3131 try block_scope.statements.append(&tmp_var.base);
3132
3133 var break_node_tmp = try CtrlFlow.initToken(rp.c, .Break, block_scope.label);
3134
3135 const if_node = try transCreateNodeIf(rp.c);
3136 var cond_scope = Scope.Condition{
3137 .base = .{
3138 .parent = &block_scope.base,
3139 .id = .Condition,
3140 },
3141 };
3142 defer cond_scope.deinit();
3143 const tmp_var_node = try transCreateNodeIdentifier(rp.c, mangled_name);
3144
3145 const ty = getExprQualType(rp.c, cond_expr).getTypePtr();
3146 const cond_node = try finishBoolExpr(rp, &cond_scope.base, cond_expr.getBeginLoc(), ty, tmp_var_node, used);
3147 if_node.condition = cond_node;
3148 _ = try appendToken(rp.c, .RParen, ")");
3149
3150 if_node.body = try transCreateNodeIdentifier(rp.c, mangled_name);
3151 if_node.@"else" = try transCreateNodeElse(rp.c);
3152 if_node.@"else".?.body = try transExpr(rp, &block_scope.base, false_expr, .used, .r_value);
3153 _ = try appendToken(rp.c, .Semicolon, ";");
31543016
3155 const break_node = try break_node_tmp.finish(&if_node.base);3017 const cond_node = try transBoolExpr(c, &cond_scope.base, cond_expr, .used);
3156 _ = try appendToken(rp.c, .Semicolon, ";");3018 var then_body = try Node.identifier.create(c.arena, mangled_name);
3157 try block_scope.statements.append(&break_node.base);3019 if (!res_is_bool and isBoolRes(init_node)) {
3158 const block_node = try block_scope.complete(rp.c);3020 then_body = try Node.bool_to_int.create(c.arena, then_body);
3021 }
31593022
3160 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);3023 var else_body = try transExpr(c, &block_scope.base, false_expr, .used, .r_value);
3161 grouped_expr.* = .{3024 if (!res_is_bool and isBoolRes(else_body)) {
3162 .lparen = lparen,3025 else_body = try Node.bool_to_int.create(c.arena, else_body);
3163 .expr = block_node,3026 }
3164 .rparen = try appendToken(rp.c, .RParen, ")"),3027 const if_node = try Node.@"if".create(c.arena, .{
3165 };3028 .cond = cond,
3166 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);3029 .then = then_body,
3030 .@"else" = else_body,
3031 });
3032 const break_node = try Node.break_val.create(c.arena, .{
3033 .label = block_scope.label,
3034 .val = if_node,
3035 });
3036 try block_scope.statements.append(break_node);
3037 const res = try block_scope.complete(c);
3038 return maybeSuppressResult(c, scope, used, res);
3167}3039}
31683040
3169fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.ConditionalOperator, used: ResultUsed) TransError!*ast.Node {3041fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.ConditionalOperator, used: ResultUsed) TransError!Node {
3170 const grouped = scope.id == .Condition;
3171 const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
3172 const if_node = try transCreateNodeIf(rp.c);
3173 var cond_scope = Scope.Condition{3042 var cond_scope = Scope.Condition{
3174 .base = .{3043 .base = .{
3175 .parent = scope,3044 .parent = scope,
...@@ -3178,60 +3047,41 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang....@@ -3178,60 +3047,41 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.
3178 };3047 };
3179 defer cond_scope.deinit();3048 defer cond_scope.deinit();
31803049
3050 const qt = @ptrCast(*const clang.Stmt, stmt).getType();
3051 const res_is_bool = qualTypeIsBoolean(qt);
3181 const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt);3052 const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt);
3182 const cond_expr = casted_stmt.getCond();3053 const cond_expr = casted_stmt.getCond();
3183 const true_expr = casted_stmt.getTrueExpr();3054 const true_expr = casted_stmt.getTrueExpr();
3184 const false_expr = casted_stmt.getFalseExpr();3055 const false_expr = casted_stmt.getFalseExpr();
31853056
3186 if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);3057 const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used, .r_value);
3187 _ = try appendToken(rp.c, .RParen, ")");
3188
3189 if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value);
31903058
3191 if_node.@"else" = try transCreateNodeElse(rp.c);3059 var then_body = try transExpr(c, scope, true_expr, .used, .r_value);
3192 if_node.@"else".?.body = try transExpr(rp, scope, false_expr, .used, .r_value);3060 if (!res_is_bool and isBoolRes(then_body)) {
3061 then_body = try Node.bool_to_int.create(c.arena, then_body);
3062 }
31933063
3194 if (grouped) {3064 var else_body = try transExpr(c, scope, false_expr, .used, .r_value);
3195 const rparen = try appendToken(rp.c, .RParen, ")");3065 if (!res_is_bool and isBoolRes(else_body)) {
3196 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);3066 else_body = try Node.bool_to_int.create(c.arena, else_body);
3197 grouped_expr.* = .{
3198 .lparen = lparen,
3199 .expr = &if_node.base,
3200 .rparen = rparen,
3201 };
3202 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
3203 } else {
3204 return maybeSuppressResult(rp, scope, used, &if_node.base);
3205 }3067 }
3068
3069 const if_node = try Node.@"if".create(c.arena, .{
3070 .cond = cond,
3071 .then = then_body,
3072 .@"else" = else_body,
3073 });
3074 return maybeSuppressResult(c, scope, used, if_node);
3206}3075}
32073076
3208fn maybeSuppressResult(3077fn maybeSuppressResult(
3209 rp: RestorePoint,3078 c: *Context,
3210 scope: *Scope,3079 scope: *Scope,
3211 used: ResultUsed,3080 used: ResultUsed,
3212 result: *ast.Node,3081 result: Node,
3213) TransError!*ast.Node {3082) TransError!Node {
3214 if (used == .used) return result;3083 if (used == .used) return result;
3215 if (scope.id != .Condition) {3084 return Node.ignore.create(c.arena, result);
3216 // NOTE: This is backwards, but the semicolon must immediately follow the node.
3217 _ = try appendToken(rp.c, .Semicolon, ";");
3218 } else { // TODO is there a way to avoid this hack?
3219 // this parenthesis must come immediately following the node
3220 _ = try appendToken(rp.c, .RParen, ")");
3221 // these need to come before _
3222 _ = try appendToken(rp.c, .Colon, ":");
3223 _ = try appendToken(rp.c, .LParen, "(");
3224 }
3225 const lhs = try transCreateNodeIdentifier(rp.c, "_");
3226 const op_token = try appendToken(rp.c, .Equal, "=");
3227 const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
3228 op_node.* = .{
3229 .base = .{ .tag = .Assign },
3230 .op_token = op_token,
3231 .lhs = lhs,
3232 .rhs = result,
3233 };
3234 return &op_node.base;
3235}3085}
32363086
3237fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {3087fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {
...@@ -3242,11 +3092,11 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {...@@ -3242,11 +3092,11 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {
3242/// only matters for incomplete arrays, since the size of the array is determined3092/// only matters for incomplete arrays, since the size of the array is determined
3243/// by the size of the initializer3093/// by the size of the initializer
3244fn transQualTypeInitialized(3094fn transQualTypeInitialized(
3245 rp: RestorePoint,3095 c: *Context,
3246 qt: clang.QualType,3096 qt: clang.QualType,
3247 decl_init: *const clang.Expr,3097 decl_init: *const clang.Expr,
3248 source_loc: clang.SourceLocation,3098 source_loc: clang.SourceLocation,
3249) TypeError!*ast.Node {3099) TypeError!Node {
3250 const ty = qt.getTypePtr();3100 const ty = qt.getTypePtr();
3251 if (ty.getTypeClass() == .IncompleteArray) {3101 if (ty.getTypeClass() == .IncompleteArray) {
3252 const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty);3102 const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty);
...@@ -3257,17 +3107,17 @@ fn transQualTypeInitialized(...@@ -3257,17 +3107,17 @@ fn transQualTypeInitialized(
3257 const string_lit = @ptrCast(*const clang.StringLiteral, decl_init);3107 const string_lit = @ptrCast(*const clang.StringLiteral, decl_init);
3258 const string_lit_size = string_lit.getLength() + 1; // +1 for null terminator3108 const string_lit_size = string_lit.getLength() + 1; // +1 for null terminator
3259 const array_size = @intCast(usize, string_lit_size);3109 const array_size = @intCast(usize, string_lit_size);
3260 return transCreateNodeArrayType(rp, source_loc, elem_ty, array_size);3110 return Node.array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_ty });
3261 },3111 },
3262 .InitListExprClass => {3112 .InitListExprClass => {
3263 const init_expr = @ptrCast(*const clang.InitListExpr, decl_init);3113 const init_expr = @ptrCast(*const clang.InitListExpr, decl_init);
3264 const size = init_expr.getNumInits();3114 const size = init_expr.getNumInits();
3265 return transCreateNodeArrayType(rp, source_loc, elem_ty, size);3115 return Node.array_type.create(c.arena, .{ .len = size, .elem_type = elem_ty });
3266 },3116 },
3267 else => {},3117 else => {},
3268 }3118 }
3269 }3119 }
3270 return transQualType(rp, qt, source_loc);3120 return transQualType(c, qt, source_loc);
3271}3121}
32723122
3273fn transQualType(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!Node {3123fn transQualType(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!Node {
...@@ -3276,16 +3126,16 @@ fn transQualType(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocati...@@ -3276,16 +3126,16 @@ fn transQualType(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocati
32763126
3277/// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness.3127/// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness.
3278/// Asserts the type is an integer.3128/// Asserts the type is an integer.
3279fn transQualTypeIntWidthOf(c: *Context, ty: clang.QualType, is_signed: bool) TypeError!*ast.Node {3129fn transQualTypeIntWidthOf(c: *Context, ty: clang.QualType, is_signed: bool) TypeError!Node {
3280 return transTypeIntWidthOf(c, qualTypeCanon(ty), is_signed);3130 return transTypeIntWidthOf(c, qualTypeCanon(ty), is_signed);
3281}3131}
32823132
3283/// Produces a Zig AST node by translating a Clang Type, respecting the width, but modifying the signed-ness.3133/// Produces a Zig AST node by translating a Clang Type, respecting the width, but modifying the signed-ness.
3284/// Asserts the type is an integer.3134/// Asserts the type is an integer.
3285fn transTypeIntWidthOf(c: *Context, ty: *const clang.Type, is_signed: bool) TypeError!*ast.Node {3135fn transTypeIntWidthOf(c: *Context, ty: *const clang.Type, is_signed: bool) TypeError!Node {
3286 assert(ty.getTypeClass() == .Builtin);3136 assert(ty.getTypeClass() == .Builtin);
3287 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);3137 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
3288 return transCreateNodeIdentifier(c, switch (builtin_ty.getKind()) {3138 return Node.type.create(c.arena, switch (builtin_ty.getKind()) {
3289 .Char_U, .Char_S, .UChar, .SChar, .Char8 => if (is_signed) "i8" else "u8",3139 .Char_U, .Char_S, .UChar, .SChar, .Char8 => if (is_signed) "i8" else "u8",
3290 .UShort, .Short => if (is_signed) "c_short" else "c_ushort",3140 .UShort, .Short => if (is_signed) "c_short" else "c_ushort",
3291 .UInt, .Int => if (is_signed) "c_int" else "c_uint",3141 .UInt, .Int => if (is_signed) "c_int" else "c_uint",
...@@ -3532,28 +3382,22 @@ fn cIsLongLongInteger(qt: clang.QualType) bool {...@@ -3532,28 +3382,22 @@ fn cIsLongLongInteger(qt: clang.QualType) bool {
3532 };3382 };
3533}3383}
3534fn transCreateNodeAssign(3384fn transCreateNodeAssign(
3535 rp: RestorePoint,3385 c: *Context,
3536 scope: *Scope,3386 scope: *Scope,
3537 result_used: ResultUsed,3387 result_used: ResultUsed,
3538 lhs: *const clang.Expr,3388 lhs: *const clang.Expr,
3539 rhs: *const clang.Expr,3389 rhs: *const clang.Expr,
3540) !*ast.Node {3390) !Node {
3541 // common case3391 // common case
3542 // c: lhs = rhs3392 // c: lhs = rhs
3543 // zig: lhs = rhs3393 // zig: lhs = rhs
3544 if (result_used == .unused) {3394 if (result_used == .unused) {
3545 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);3395 const lhs_node = try transExpr(c, scope, lhs, .used, .l_value);
3546 const eq_token = try appendToken(rp.c, .Equal, "=");3396 var rhs_node = try transExprCoercing(c, scope, rhs, .used, .r_value);
3547 var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value);
3548 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {3397 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
3549 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);3398 rhs_node = try Node.bool_to_int.create(c.arena, rhs_node);
3550 builtin_node.params()[0] = rhs_node;
3551 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3552 rhs_node = &builtin_node.base;
3553 }3399 }
3554 if (scope.id != .Condition)3400 return transCreateNodeInfixOp(c, scope, .assign, lhs_node, rhs_node, .used);
3555 _ = try appendToken(rp.c, .Semicolon, ";");
3556 return transCreateNodeInfixOp(rp, scope, lhs_node, .Assign, eq_token, rhs_node, .used, false);
3557 }3401 }
35583402
3559 // worst case3403 // worst case
...@@ -3563,76 +3407,36 @@ fn transCreateNodeAssign(...@@ -3563,76 +3407,36 @@ fn transCreateNodeAssign(
3563 // zig: lhs = _tmp;3407 // zig: lhs = _tmp;
3564 // zig: break :blk _tmp3408 // zig: break :blk _tmp
3565 // zig: })3409 // zig: })
3566 var block_scope = try Scope.Block.init(rp.c, scope, true);3410 var block_scope = try Scope.Block.init(c, scope, true);
3567 defer block_scope.deinit();3411 defer block_scope.deinit();
35683412
3569 const tmp = try block_scope.makeMangledName(rp.c, "tmp");3413 const tmp = try block_scope.makeMangledName(c, "tmp");
3570 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");3414 const rhs = try transExpr(c, scope, op_expr, .used, .r_value);
3571 const name_tok = try appendIdentifier(rp.c, tmp);3415 const tmp_decl = try Node.var_simple.create(c.arena, .{ .name = tmp, .init = rhs});
3572 const eq_token = try appendToken(rp.c, .Equal, "=");3416 try block_scope.statements.append(tmp_decl);
3573 var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value);
3574 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
3575 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
3576 builtin_node.params()[0] = rhs_node;
3577 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3578 rhs_node = &builtin_node.base;
3579 }
3580 const init_node = rhs_node;
3581 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3582 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
3583 .name_token = name_tok,
3584 .mut_token = mut_tok,
3585 .semicolon_token = semicolon_token,
3586 }, .{
3587 .eq_token = eq_token,
3588 .init_node = init_node,
3589 });
3590 try block_scope.statements.append(&node.base);
35913417
3592 const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value);
3593 const lhs_eq_token = try appendToken(rp.c, .Equal, "=");
3594 const ident = try transCreateNodeIdentifier(rp.c, tmp);
3595 _ = try appendToken(rp.c, .Semicolon, ";");
35963418
3597 const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, lhs_eq_token, ident, .used, false);3419 const lhs = try transExpr(c, &block_scope.base, lhs, .used, .l_value);
3420 const tmp_ident = try Node.identifier.create(c.arena, tmp);
3421 const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, lhs, tmp_iden, .used);
3598 try block_scope.statements.append(assign);3422 try block_scope.statements.append(assign);
35993423
3600 const break_node = blk: {3424 const break_node = try Node.break_val.create(c.arena, .{
3601 var tmp_ctrl_flow = try CtrlFlow.init(rp.c, .Break, tokenSlice(rp.c, block_scope.label.?));3425 .label = block_scope.label,
3602 const rhs_expr = try transCreateNodeIdentifier(rp.c, tmp);3426 .val = tmp_ident,
3603 break :blk try tmp_ctrl_flow.finish(rhs_expr);3427 });
3604 };3428 try block_scope.statements.append(break_node);
3605 _ = try appendToken(rp.c, .Semicolon, ";");3429 return block_scope.complete(c);
3606 try block_scope.statements.append(&break_node.base);
3607 const block_node = try block_scope.complete(rp.c);
3608 // semicolon must immediately follow rbrace because it is the last token in a block
3609 _ = try appendToken(rp.c, .Semicolon, ";");
3610 return block_node;
3611}
3612
3613fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node {
3614 const field_access_node = try c.arena.create(ast.Node.SimpleInfixOp);
3615 field_access_node.* = .{
3616 .base = .{ .tag = .Period },
3617 .op_token = try appendToken(c, .Period, "."),
3618 .lhs = container,
3619 .rhs = try transCreateNodeIdentifier(c, field_name),
3620 };
3621 return &field_access_node.base;
3622}3430}
36233431
3624fn transCreateNodeBoolInfixOp(3432fn transCreateNodeInfixOp(
3625 c: *Context,3433 c: *Context,
3626 scope: *Scope,3434 scope: *Scope,
3627 stmt: *const clang.BinaryOperator,
3628 op: ast.Node.Tag,3435 op: ast.Node.Tag,
3436 lhs: Node,
3437 rhs: Node,
3629 used: ResultUsed,3438 used: ResultUsed,
3630) !Node {3439) !Node {
3631 std.debug.assert(op == .bool_and or op == .bool_or);
3632
3633 const lhs = try transBoolExpr(rp, scope, stmt.getLHS(), .used, .l_value, true);
3634 const rhs = try transBoolExpr(rp, scope, stmt.getRHS(), .used, .r_value, true);
3635
3636 const payload = try c.arena.create(ast.Payload.BinOp);3440 const payload = try c.arena.create(ast.Payload.BinOp);
3637 payload.* = .{3441 payload.* = .{
3638 .base = .{ .tag = op },3442 .base = .{ .tag = op },
...@@ -3644,39 +3448,19 @@ fn transCreateNodeBoolInfixOp(...@@ -3644,39 +3448,19 @@ fn transCreateNodeBoolInfixOp(
3644 return maybeSuppressResult(c, scope, used, Node.initPayload(&payload.base));3448 return maybeSuppressResult(c, scope, used, Node.initPayload(&payload.base));
3645}3449}
36463450
3647fn transCreateNodePtrType(3451fn transCreateNodeBoolInfixOp(
3648 c: *Context,3452 c: *Context,
3649 is_const: bool,3453 scope: *Scope,
3650 is_volatile: bool,3454 stmt: *const clang.BinaryOperator,
3651 op_tok_id: std.zig.Token.Id,3455 op: ast.Node.Tag,
3652) !*ast.Node.PtrType {3456 used: ResultUsed,
3653 const node = try c.arena.create(ast.Node.PtrType);3457) !Node {
3654 const op_token = switch (op_tok_id) {3458 std.debug.assert(op == .bool_and or op == .bool_or);
3655 .LBracket => blk: {3459
3656 const lbracket = try appendToken(c, .LBracket, "[");3460 const lhs = try transBoolExpr(rp, scope, stmt.getLHS(), .used, .l_value);
3657 _ = try appendToken(c, .Asterisk, "*");3461 const rhs = try transBoolExpr(rp, scope, stmt.getRHS(), .used, .r_value);
3658 _ = try appendToken(c, .RBracket, "]");3462
3659 break :blk lbracket;3463 return transCreateNodeInfixOp(c, scope, op, lhs, rhs, used);
3660 },
3661 .Identifier => blk: {
3662 const lbracket = try appendToken(c, .LBracket, "["); // Rendering checks if this token + 2 == .Identifier, so needs to return this token
3663 _ = try appendToken(c, .Asterisk, "*");
3664 _ = try appendIdentifier(c, "c");
3665 _ = try appendToken(c, .RBracket, "]");
3666 break :blk lbracket;
3667 },
3668 .Asterisk => try appendToken(c, .Asterisk, "*"),
3669 else => unreachable,
3670 };
3671 node.* = .{
3672 .op_token = op_token,
3673 .ptr_info = .{
3674 .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,
3675 .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,
3676 },
3677 .rhs = undefined, // translate and set afterward
3678 };
3679 return node;
3680}3464}
36813465
3682fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {3466fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {
...@@ -3722,73 +3506,10 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {...@@ -3722,73 +3506,10 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {
3722 return Node.int_literal.create(c.arena, str);3506 return Node.int_literal.create(c.arena, str);
3723}3507}
37243508
3725fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {3509fn transCreateNodeNumber(c: *Context, int: anytype) !Node {
3726 const token = try appendToken(c, .Keyword_undefined, "undefined");3510 const fmt_s = if (comptime std.meta.trait.isNumber(@TypeOf(int))) "{d}" else "{s}";
3727 const node = try c.arena.create(ast.Node.OneToken);3511 const str = try std.fmt.allocPrint(c.arena, fmt_s, .{int});
3728 node.* = .{3512 return Node.int_literal.create(c.arena, str);
3729 .base = .{ .tag = .UndefinedLiteral },
3730 .token = token,
3731 };
3732 return &node.base;
3733}
3734
3735fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {
3736 const token = try appendToken(c, .Keyword_null, "null");
3737 const node = try c.arena.create(ast.Node.OneToken);
3738 node.* = .{
3739 .base = .{ .tag = .NullLiteral },
3740 .token = token,
3741 };
3742 return &node.base;
3743}
3744
3745fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
3746 const token = if (value)
3747 try appendToken(c, .Keyword_true, "true")
3748 else
3749 try appendToken(c, .Keyword_false, "false");
3750 const node = try c.arena.create(ast.Node.OneToken);
3751 node.* = .{
3752 .base = .{ .tag = .BoolLiteral },
3753 .token = token,
3754 };
3755 return &node.base;
3756}
3757
3758fn transCreateNodeInt(c: *Context, int: anytype) !*ast.Node {
3759 const fmt_s = if (comptime std.meta.trait.isIntegerNumber(@TypeOf(int))) "{d}" else "{s}";
3760 const token = try appendTokenFmt(c, .IntegerLiteral, fmt_s, .{int});
3761 const node = try c.arena.create(ast.Node.OneToken);
3762 node.* = .{
3763 .base = .{ .tag = .IntegerLiteral },
3764 .token = token,
3765 };
3766 return &node.base;
3767}
3768
3769fn transCreateNodeFloat(c: *Context, str: []const u8) !*ast.Node {
3770 const token = try appendTokenFmt(c, .FloatLiteral, "{s}", .{str});
3771 const node = try c.arena.create(ast.Node.OneToken);
3772 node.* = .{
3773 .base = .{ .tag = .FloatLiteral },
3774 .token = token,
3775 };
3776 return &node.base;
3777}
3778
3779fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
3780 const container_tok = try appendToken(c, .Keyword_opaque, "opaque");
3781 const lbrace_token = try appendToken(c, .LBrace, "{");
3782 const container_node = try ast.Node.ContainerDecl.alloc(c.arena, 0);
3783 container_node.* = .{
3784 .kind_token = container_tok,
3785 .layout_token = null,
3786 .lbrace_token = lbrace_token,
3787 .rbrace_token = try appendToken(c, .RBrace, "}"),
3788 .fields_and_decls_len = 0,
3789 .init_arg_expr = .None,
3790 };
3791 return &container_node.base;
3792}3513}
37933514
3794fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias: *ast.Node.FnProto) !*ast.Node {3515fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias: *ast.Node.FnProto) !*ast.Node {
...@@ -3873,13 +3594,12 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a...@@ -3873,13 +3594,12 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
3873 return &fn_proto.base;3594 return &fn_proto.base;
3874}3595}
38753596
3876
3877
3878fn transCreateNodeShiftOp(3597fn transCreateNodeShiftOp(
3879 c: *Context,3598 c: *Context,
3880 scope: *Scope,3599 scope: *Scope,
3881 stmt: *const clang.BinaryOperator,3600 stmt: *const clang.BinaryOperator,
3882 op: Node.Tag,3601 op: Node.Tag,
3602 used: ResultUsed,
3883) !Node {3603) !Node {
3884 std.debug.assert(op == .shl or op == .shr);3604 std.debug.assert(op == .shl or op == .shr);
38853605
...@@ -3894,15 +3614,7 @@ fn transCreateNodeShiftOp(...@@ -3894,15 +3614,7 @@ fn transCreateNodeShiftOp(
3894 const rhs = try transExprCoercing(c, scope, rhs_expr, .used, .r_value);3614 const rhs = try transExprCoercing(c, scope, rhs_expr, .used, .r_value);
3895 const rhs_casted = try Node.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs_type });3615 const rhs_casted = try Node.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs_type });
38963616
3897 const payload = try c.arena.create(ast.Payload.BinOp);3617 return transCreateNodeInfixOp(c, scope, op, lhs, rhs_casted, used);
3898 payload.* = .{
3899 .base = .{ .tag = op },
3900 .data = .{
3901 .lhs = lhs,
3902 .rhs = rhs_casted,
3903 },
3904 };
3905 return Node.initPayload(&payload.base);
3906}3618}
39073619
3908fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Node {3620fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Node {
src/translate_c/ast.zig+15-15
...@@ -24,8 +24,8 @@ pub const Node = extern union {...@@ -24,8 +24,8 @@ pub const Node = extern union {
24 usingnamespace_builtins,24 usingnamespace_builtins,
25 // After this, the tag requires a payload.25 // After this, the tag requires a payload.
2626
27 int_literal,27 // int or float, doesn't really matter
28 float_literal,28 number_literal,
29 string_literal,29 string_literal,
30 char_literal,30 char_literal,
31 identifier,31 identifier,
...@@ -115,6 +115,7 @@ pub const Node = extern union {...@@ -115,6 +115,7 @@ pub const Node = extern union {
115 bit_xor,115 bit_xor,
116 array_cat,116 array_cat,
117 ellipsis3,117 ellipsis3,
118 assign,
118119
119 log2_int_type,120 log2_int_type,
120 /// @import("std").math.Log2Int(operand)121 /// @import("std").math.Log2Int(operand)
...@@ -147,6 +148,8 @@ pub const Node = extern union {...@@ -147,6 +148,8 @@ pub const Node = extern union {
147 int_to_ptr,148 int_to_ptr,
148 /// @ptrToInt(operand)149 /// @ptrToInt(operand)
149 ptr_to_int,150 ptr_to_int,
151 /// @alignCast(lhs, rhs)
152 align_cast,
150153
151 negate,154 negate,
152 negate_wrap,155 negate_wrap,
...@@ -190,6 +193,9 @@ pub const Node = extern union {...@@ -190,6 +193,9 @@ pub const Node = extern union {
190 /// [1]type{val} ** count193 /// [1]type{val} ** count
191 array_filler,194 array_filler,
192195
196 /// _ = operand;
197 ignore,
198
193 pub const last_no_payload_tag = Tag.usingnamespace_builtins;199 pub const last_no_payload_tag = Tag.usingnamespace_builtins;
194 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;200 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
195201
...@@ -227,6 +233,7 @@ pub const Node = extern union {...@@ -227,6 +233,7 @@ pub const Node = extern union {
227 .while_true,233 .while_true,
228 .if_not_break,234 .if_not_break,
229 .switch_else,235 .switch_else,
236 .ignore,
230 => Payload.UnOp,237 => Payload.UnOp,
231238
232 .add,239 .add,
...@@ -292,12 +299,14 @@ pub const Node = extern union {...@@ -292,12 +299,14 @@ pub const Node = extern union {
292 .array_cat,299 .array_cat,
293 .ellipsis3,300 .ellipsis3,
294 .switch_prong,301 .switch_prong,
302 .field_access,
303 .assign,
304 .align_cast,
295 => Payload.BinOp,305 => Payload.BinOp,
296306
297 .int,307 .number_literal,
298 .float,308 .string_literal,
299 .string,309 .char_literal,
300 .char,
301 .identifier,310 .identifier,
302 .warning,311 .warning,
303 .failed_decl,312 .failed_decl,
...@@ -327,7 +336,6 @@ pub const Node = extern union {...@@ -327,7 +336,6 @@ pub const Node = extern union {
327 .typedef, .pub_typedef, .var_simple, .pub_var_simple => Payload.SimpleVarDecl,336 .typedef, .pub_typedef, .var_simple, .pub_var_simple => Payload.SimpleVarDecl,
328 .enum_redecl => Payload.EnumRedecl,337 .enum_redecl => Payload.EnumRedecl,
329 .array_filler => Payload.ArrayFiller,338 .array_filler => Payload.ArrayFiller,
330 .field_access => Payload.FieldAccess,
331 };339 };
332 }340 }
333341
...@@ -590,14 +598,6 @@ pub const Payload = struct {...@@ -590,14 +598,6 @@ pub const Payload = struct {
590 count: usize,598 count: usize,
591 },599 },
592 };600 };
593
594 pub const FieldAccess = struct {
595 base: Node,
596 data: struct {
597 container: Node,
598 name: []const u8,
599 },
600 };
601};601};
602602
603/// Converts the nodes into a Zig ast.603/// Converts the nodes into a Zig ast.