| ... | ... | @@ -1144,18 +1144,16 @@ fn transBinaryOperator( |
| 1144 | 1144 | } |
| 1145 | 1145 | }, |
| 1146 | 1146 | .Shl => { |
| 1147 | | const node = try transCreateNodeShiftOp(c, scope, stmt, .shl); |
| 1148 | | return maybeSuppressResult(c, scope, result_used, node); |
| 1147 | return transCreateNodeShiftOp(c, scope, stmt, .shl, result_used); |
| 1149 | 1148 | }, |
| 1150 | 1149 | .Shr => { |
| 1151 | | const node = try transCreateNodeShiftOp(c, scope, stmt, .shr); |
| 1152 | | return maybeSuppressResult(c, scope, result_used, node); |
| 1150 | return transCreateNodeShiftOp(c, scope, stmt, .shr, result_used); |
| 1153 | 1151 | }, |
| 1154 | 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 | 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 | 1158 | else => {}, |
| 1161 | 1159 | } |
| ... | ... | @@ -1233,15 +1231,7 @@ fn transBinaryOperator( |
| 1233 | 1231 | else |
| 1234 | 1232 | rhs_uncasted; |
| 1235 | 1233 | |
| 1236 | | const payload = try c.arena.create(ast.Payload.BinOp); |
| 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)); |
| 1234 | return transCreateNodeInfixOp(c, scope, op_id, lhs, rhs, used); |
| 1245 | 1235 | } |
| 1246 | 1236 | |
| 1247 | 1237 | fn transCompoundStmtInline( |
| ... | ... | @@ -1716,7 +1706,7 @@ fn transStringLiteralAsArray( |
| 1716 | 1706 | init_list[i] = try transCreateCharLitNode(c, narrow, code_unit); |
| 1717 | 1707 | } |
| 1718 | 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 | } |
| 1721 | 1711 | |
| 1722 | 1712 | return Node.array_init.create(c.arena, init_list); |
| ... | ... | @@ -2398,7 +2388,7 @@ fn transCharLiteral( |
| 2398 | 2388 | // C has a somewhat obscure feature called multi-character character constant |
| 2399 | 2389 | // e.g. 'abcd' |
| 2400 | 2390 | const int_lit_node = if (kind == .Ascii and val > 255) |
| 2401 | | try transCreateNodeInt(c, val) |
| 2391 | try transCreateNodeNumber(c, val) |
| 2402 | 2392 | else |
| 2403 | 2393 | try transCreateCharLitNode(c, narrow, val); |
| 2404 | 2394 | |
| ... | ... | @@ -2434,8 +2424,8 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used: |
| 2434 | 2424 | .val = try transStmt(c, &block_scope.base, it[0], .used, .r_value), |
| 2435 | 2425 | }); |
| 2436 | 2426 | try block_scope.statements.append(break_node); |
| 2437 | | |
| 2438 | | return block_scope.complete(c); |
| 2427 | const res = try block_scope.complete(c); |
| 2428 | return maybeSuppressResult(c, scope, used, res); |
| 2439 | 2429 | } |
| 2440 | 2430 | |
| 2441 | 2431 | fn 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 | 2450 | const decl = @ptrCast(*const clang.NamedDecl, member_decl); |
| 2461 | 2451 | break :blk try c.str(decl.getName_bytes_begin()); |
| 2462 | 2452 | }; |
| 2453 | const ident = try Node.identifier.create(c.arena, name); |
| 2463 | 2454 | |
| 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 | 2456 | return maybeSuppressResult(c, scope, result_used, node); |
| 2466 | 2457 | } |
| 2467 | 2458 | |
| ... | ... | @@ -2716,15 +2707,9 @@ fn transCreatePreCrement( |
| 2716 | 2707 | // common case |
| 2717 | 2708 | // c: ++expr |
| 2718 | 2709 | // zig: expr += 1 |
| 2719 | | const payload = try c.arena.create(ast.Payload.BinOp); |
| 2720 | | payload.* = .{ |
| 2721 | | .base = .{ .tag = op }, |
| 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); |
| 2710 | const lhs = try transExpr(c, scope, op_expr, .used, .r_value); |
| 2711 | const rhs = Node.one_literal.init(); |
| 2712 | return transCreateNodeInfixOp(c, scope, op, lhs, rhs, .used); |
| 2728 | 2713 | } |
| 2729 | 2714 | // worst case |
| 2730 | 2715 | // c: ++expr |
| ... | ... | @@ -2744,20 +2729,15 @@ fn transCreatePreCrement( |
| 2744 | 2729 | |
| 2745 | 2730 | const lhs_node = try Node.identifier.create(c.arena, ref); |
| 2746 | 2731 | const ref_node = try Node.deref.create(c.arena, lhs_node); |
| 2747 | | const payload = try c.arena.create(ast.Payload.BinOp); |
| 2748 | | payload.* = .{ |
| 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)); |
| 2732 | const node = try transCreateNodeInfixOp(c, scope, op, ref_node, Node.one_literal.init(), .used); |
| 2733 | try block_scope.statements.append(node); |
| 2756 | 2734 | |
| 2757 | | return Node.break_val.create(c.arena, .{ |
| 2735 | const break_node = try Node.break_val.create(c.arena, .{ |
| 2758 | 2736 | .label = block_scope.label, |
| 2759 | 2737 | .val = ref_node, |
| 2760 | 2738 | }); |
| 2739 | try block_scope.statements.append(break_node); |
| 2740 | return block_scope.complete(c); |
| 2761 | 2741 | } |
| 2762 | 2742 | |
| 2763 | 2743 | fn transCreatePostCrement( |
| ... | ... | @@ -2771,17 +2751,11 @@ fn transCreatePostCrement( |
| 2771 | 2751 | |
| 2772 | 2752 | if (used == .unused) { |
| 2773 | 2753 | // common case |
| 2774 | | // c: ++expr |
| 2754 | // c: expr++ |
| 2775 | 2755 | // zig: expr += 1 |
| 2776 | | const payload = try c.arena.create(ast.Payload.BinOp); |
| 2777 | | payload.* = .{ |
| 2778 | | .base = .{ .tag = op }, |
| 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); |
| 2756 | const lhs = try transExpr(c, scope, op_expr, .used, .r_value); |
| 2757 | const rhs = Node.one_literal.init(); |
| 2758 | return transCreateNodeInfixOp(c, scope, op, lhs, rhs, .used); |
| 2785 | 2759 | } |
| 2786 | 2760 | // worst case |
| 2787 | 2761 | // c: expr++ |
| ... | ... | @@ -2807,44 +2781,39 @@ fn transCreatePostCrement( |
| 2807 | 2781 | const tmp_decl = try Node.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node}); |
| 2808 | 2782 | try block_scope.statements.append(tmp_decl); |
| 2809 | 2783 | |
| 2810 | | const payload = try c.arena.create(ast.Payload.BinOp); |
| 2811 | | payload.* = .{ |
| 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)); |
| 2784 | const node = try transCreateNodeInfixOp(c, scope, op, ref_node, Node.one_literal.init(), .used); |
| 2785 | try block_scope.statements.append(node); |
| 2819 | 2786 | |
| 2820 | | return Node.break_val.create(c.arena, .{ |
| 2787 | const break_node = try Node.break_val.create(c.arena, .{ |
| 2821 | 2788 | .label = block_scope.label, |
| 2822 | 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 | } |
| 2825 | 2794 | |
| 2826 | | fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.CompoundAssignOperator, used: ResultUsed) TransError!*ast.Node { |
| 2795 | fn transCompoundAssignOperator(c: *Context, scope: *Scope, stmt: *const clang.CompoundAssignOperator, used: ResultUsed) TransError!Node { |
| 2827 | 2796 | switch (stmt.getOpcode()) { |
| 2828 | 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 | 2799 | else |
| 2831 | | return transCreateCompoundAssign(rp, scope, stmt, .AssignMul, .AsteriskEqual, "*=", .Mul, .Asterisk, "*", used), |
| 2800 | return transCreateCompoundAssign(c, scope, stmt, .assign_mul, used), |
| 2832 | 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 | 2803 | else |
| 2835 | | return transCreateCompoundAssign(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", .Add, .Plus, "+", used), |
| 2804 | return transCreateCompoundAssign(c, scope, stmt, .assign_add, used), |
| 2836 | 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 | 2807 | else |
| 2839 | | return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used), |
| 2840 | | .DivAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignDiv, .SlashEqual, "/=", .Div, .Slash, "/", used), |
| 2841 | | .RemAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignMod, .PercentEqual, "%=", .Mod, .Percent, "%", used), |
| 2842 | | .ShlAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftLeft, .AngleBracketAngleBracketLeftEqual, "<<=", .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<", used), |
| 2843 | | .ShrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftRight, .AngleBracketAngleBracketRightEqual, ">>=", .BitShiftRight, .AngleBracketAngleBracketRight, ">>", used), |
| 2844 | | .AndAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitAnd, .AmpersandEqual, "&=", .BitAnd, .Ampersand, "&", used), |
| 2845 | | .XorAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitXor, .CaretEqual, "^=", .BitXor, .Caret, "^", used), |
| 2846 | | .OrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitOr, .PipeEqual, "|=", .BitOr, .Pipe, "|", used), |
| 2847 | | else => return revertAndWarn( |
| 2808 | return transCreateCompoundAssign(c, scope, stmt, .assign_sub, used), |
| 2809 | .DivAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_div, used), |
| 2810 | .RemAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_mod, used), |
| 2811 | .ShlAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_shl, used), |
| 2812 | .ShrAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_shr, used), |
| 2813 | .AndAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_bit_and, used), |
| 2814 | .XorAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_bit_xor, used), |
| 2815 | .OrAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_bit_or, used), |
| 2816 | else => return fail( |
| 2848 | 2817 | rp, |
| 2849 | 2818 | error.UnsupportedTranslation, |
| 2850 | 2819 | stmt.getBeginLoc(), |
| ... | ... | @@ -2855,25 +2824,20 @@ fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const cla |
| 2855 | 2824 | } |
| 2856 | 2825 | |
| 2857 | 2826 | fn transCreateCompoundAssign( |
| 2858 | | rp: RestorePoint, |
| 2827 | c: *Context, |
| 2859 | 2828 | scope: *Scope, |
| 2860 | 2829 | stmt: *const clang.CompoundAssignOperator, |
| 2861 | | assign_op: ast.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, |
| 2830 | op: Node.Tag, |
| 2867 | 2831 | used: ResultUsed, |
| 2868 | | ) TransError!*ast.Node { |
| 2869 | | const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight; |
| 2870 | | const is_div = bin_op == .Div; |
| 2871 | | const is_mod = bin_op == .Mod; |
| 2832 | ) TransError!Node { |
| 2833 | const is_shift = op == .assign_shl or op == .assign_shr; |
| 2834 | const is_div = op == .assign_div; |
| 2835 | const is_mod = op == .assign_mod; |
| 2872 | 2836 | const lhs = stmt.getLHS(); |
| 2873 | 2837 | const rhs = stmt.getRHS(); |
| 2874 | 2838 | const loc = stmt.getBeginLoc(); |
| 2875 | | const lhs_qt = getExprQualType(rp.c, lhs); |
| 2876 | | const rhs_qt = getExprQualType(rp.c, rhs); |
| 2839 | const lhs_qt = getExprQualType(c, lhs); |
| 2840 | const rhs_qt = getExprQualType(c, rhs); |
| 2877 | 2841 | const is_signed = cIsSignedInteger(lhs_qt); |
| 2878 | 2842 | const requires_int_cast = blk: { |
| 2879 | 2843 | const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt); |
| ... | ... | @@ -2885,146 +2849,99 @@ fn transCreateCompoundAssign( |
| 2885 | 2849 | // c: lhs += rhs |
| 2886 | 2850 | // zig: lhs += rhs |
| 2887 | 2851 | if ((is_mod or is_div) and is_signed) { |
| 2888 | | const op_token = try appendToken(rp.c, .Equal, "="); |
| 2889 | | const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp); |
| 2890 | | const builtin = if (is_mod) "@rem" else "@divTrunc"; |
| 2891 | | const builtin_node = try rp.c.createBuiltinCall(builtin, 2); |
| 2892 | | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); |
| 2893 | | builtin_node.params()[0] = lhs_node; |
| 2894 | | _ = try appendToken(rp.c, .Comma, ","); |
| 2895 | | builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value); |
| 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; |
| 2852 | const lhs_node = try transExpr(c, scope, lhs, .used, .l_value); |
| 2853 | const rhs_node = try transExpr(c, scope, rhs, .used, .r_value); |
| 2854 | const builtin = if (is_mod) |
| 2855 | try Node.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }) |
| 2856 | else |
| 2857 | try Node.divTrunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }); |
| 2858 | |
| 2859 | return transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used); |
| 2905 | 2860 | } |
| 2906 | 2861 | |
| 2907 | | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); |
| 2908 | | const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes); |
| 2862 | const lhs_node = try transExpr(c, scope, lhs, .used, .l_value); |
| 2909 | 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 | 2865 | else |
| 2912 | | try transExpr(rp, scope, rhs, .used, .r_value); |
| 2866 | try transExpr(c, scope, rhs, .used, .r_value); |
| 2913 | 2867 | |
| 2914 | 2868 | if (is_shift or requires_int_cast) { |
| 2915 | | const cast_node = try rp.c.createBuiltinCall("@intCast", 2); |
| 2869 | // @intCast(rhs) |
| 2916 | 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 | 2872 | else |
| 2919 | | try transQualType(rp, getExprQualType(rp.c, lhs), loc); |
| 2920 | | cast_node.params()[0] = cast_to_type; |
| 2921 | | _ = try appendToken(rp.c, .Comma, ","); |
| 2922 | | cast_node.params()[1] = rhs_node; |
| 2923 | | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 2924 | | rhs_node = &cast_node.base; |
| 2873 | try transQualType(c, getExprQualType(c, lhs), loc); |
| 2874 | |
| 2875 | rhs_node = try Node.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node }); |
| 2925 | 2876 | } |
| 2926 | | if (scope.id != .Condition) |
| 2927 | | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 2928 | | return transCreateNodeInfixOp(rp, scope, lhs_node, assign_op, eq_token, rhs_node, .used, false); |
| 2877 | |
| 2878 | return transCreateNodeInfixOp(c, scope, assign_op, lhs_node, rhs_node, .used); |
| 2929 | 2879 | } |
| 2930 | 2880 | // worst case |
| 2931 | 2881 | // c: lhs += rhs |
| 2932 | 2882 | // zig: (blk: { |
| 2933 | 2883 | // zig: const _ref = &lhs; |
| 2934 | | // zig: _ref.* = _ref.* + rhs; |
| 2884 | // zig: _ref.* += rhs; |
| 2935 | 2885 | // zig: break :blk _ref.* |
| 2936 | 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 | 2888 | defer block_scope.deinit(); |
| 2939 | | const ref = try block_scope.makeMangledName(rp.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); |
| 2889 | const ref = try block_scope.makeMangledName(c, "ref"); |
| 2957 | 2890 | |
| 2958 | | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); |
| 2959 | | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); |
| 2960 | | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 2891 | const expr = try transExpr(c, scope, op_expr, .used, .r_value); |
| 2892 | const addr_of = try Node.address_of.create(c.arena, expr); |
| 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); |
| 2961 | 2898 | |
| 2962 | 2899 | if ((is_mod or is_div) and is_signed) { |
| 2963 | | const op_token = try appendToken(rp.c, .Equal, "="); |
| 2964 | | const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp); |
| 2965 | | const builtin = if (is_mod) "@rem" else "@divTrunc"; |
| 2966 | | const builtin_node = try rp.c.createBuiltinCall(builtin, 2); |
| 2967 | | builtin_node.params()[0] = try transCreateNodePtrDeref(rp.c, lhs_node); |
| 2968 | | _ = try appendToken(rp.c, .Comma, ","); |
| 2969 | | builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value); |
| 2970 | | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 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); |
| 2900 | const rhs_node = try transExpr(c, scope, rhs, .used, .r_value); |
| 2901 | const builtin = if (is_mod) |
| 2902 | try Node.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }) |
| 2903 | else |
| 2904 | try Node.divTrunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }); |
| 2905 | |
| 2906 | const assign = try transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used); |
| 2907 | try block_scope.statements.append(assign); |
| 2980 | 2908 | } else { |
| 2981 | | const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes); |
| 2982 | | var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); |
| 2909 | var rhs_node = try transExpr(c, scope, rhs, .used, .r_value); |
| 2983 | 2910 | |
| 2984 | 2911 | if (is_shift or requires_int_cast) { |
| 2985 | | const cast_node = try rp.c.createBuiltinCall("@intCast", 2); |
| 2912 | // @intCast(rhs) |
| 2986 | 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 | 2915 | else |
| 2989 | | try transQualType(rp, getExprQualType(rp.c, lhs), loc); |
| 2990 | | cast_node.params()[0] = cast_to_type; |
| 2991 | | _ = try appendToken(rp.c, .Comma, ","); |
| 2992 | | cast_node.params()[1] = rhs_node; |
| 2993 | | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 2994 | | rhs_node = &cast_node.base; |
| 2916 | try transQualType(c, getExprQualType(c, lhs), loc); |
| 2917 | |
| 2918 | rhs_node = try Node.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node }); |
| 2995 | 2919 | } |
| 2996 | 2920 | |
| 2997 | | const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false); |
| 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); |
| 2921 | const assign = try transCreateNodeInfixOp(c, scope, op, ref_node, rhs_node, .used); |
| 3002 | 2922 | try block_scope.statements.append(assign); |
| 3003 | 2923 | } |
| 3004 | 2924 | |
| 3005 | | const break_node = try transCreateNodeBreak(rp.c, block_scope.label, ref_node); |
| 3006 | | try block_scope.statements.append(&break_node.base); |
| 3007 | | const block_node = try block_scope.complete(rp.c); |
| 3008 | | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 3009 | | grouped_expr.* = .{ |
| 3010 | | .lparen = try appendToken(rp.c, .LParen, "("), |
| 3011 | | .expr = block_node, |
| 3012 | | .rparen = try appendToken(rp.c, .RParen, ")"), |
| 3013 | | }; |
| 3014 | | return &grouped_expr.base; |
| 2925 | const break_node = try Node.break_val.create(c.arena, .{ |
| 2926 | .label = block_scope.label, |
| 2927 | .val = ref_node, |
| 2928 | }); |
| 2929 | try block_scope.statements.append(break_node); |
| 2930 | return block_scope.complete(c); |
| 3015 | 2931 | } |
| 3016 | 2932 | |
| 3017 | 2933 | fn transCPtrCast( |
| 3018 | | rp: RestorePoint, |
| 2934 | c: *Context, |
| 3019 | 2935 | loc: clang.SourceLocation, |
| 3020 | 2936 | dst_type: clang.QualType, |
| 3021 | 2937 | src_type: clang.QualType, |
| 3022 | | expr: *ast.Node, |
| 3023 | | ) !*ast.Node { |
| 2938 | expr: Node, |
| 2939 | ) !Node { |
| 3024 | 2940 | const ty = dst_type.getTypePtr(); |
| 3025 | 2941 | const child_type = ty.getPointeeType(); |
| 3026 | 2942 | const src_ty = src_type.getTypePtr(); |
| 3027 | 2943 | const src_child_type = src_ty.getPointeeType(); |
| 2944 | const dst_type = try transType(c, ty, loc); |
| 3028 | 2945 | |
| 3029 | 2946 | if ((src_child_type.isConstQualified() and |
| 3030 | 2947 | !child_type.isConstQualified()) or |
| ... | ... | @@ -3032,47 +2949,25 @@ fn transCPtrCast( |
| 3032 | 2949 | !child_type.isVolatileQualified())) |
| 3033 | 2950 | { |
| 3034 | 2951 | // Casting away const or volatile requires us to use @intToPtr |
| 3035 | | const inttoptr_node = try rp.c.createBuiltinCall("@intToPtr", 2); |
| 3036 | | const dst_type_node = try transType(rp, ty, loc); |
| 3037 | | inttoptr_node.params()[0] = dst_type_node; |
| 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; |
| 2952 | const ptr_to_int = try Node.ptr_to_int.create(c.arena, expr); |
| 2953 | const int_to_ptr = try Node.int_to_ptr.create(c.arena, .{ .lhs = dst_type, .rhs = ptr_to_int }); |
| 2954 | return int_to_ptr; |
| 3047 | 2955 | } else { |
| 3048 | 2956 | // Implicit downcasting from higher to lower alignment values is forbidden, |
| 3049 | 2957 | // use @alignCast to side-step this problem |
| 3050 | | const ptrcast_node = try rp.c.createBuiltinCall("@ptrCast", 2); |
| 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()) { |
| 2958 | const rhs = if (qualTypeCanon(child_type).isVoidType()) |
| 3056 | 2959 | // void has 1-byte alignment, so @alignCast is not needed |
| 3057 | | ptrcast_node.params()[1] = expr; |
| 3058 | | } else if (typeIsOpaque(rp.c, qualTypeCanon(child_type), loc)) { |
| 2960 | expr |
| 2961 | else if (typeIsOpaque(c, qualTypeCanon(child_type), loc)) |
| 3059 | 2962 | // For opaque types a ptrCast is enough |
| 3060 | | ptrcast_node.params()[1] = expr; |
| 3061 | | } else { |
| 3062 | | const aligncast_node = try rp.c.createBuiltinCall("@alignCast", 2); |
| 3063 | | const alignof_node = try rp.c.createBuiltinCall("@alignOf", 1); |
| 3064 | | const child_type_node = try transQualType(rp, child_type, loc); |
| 3065 | | alignof_node.params()[0] = child_type_node; |
| 3066 | | alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3067 | | aligncast_node.params()[0] = &alignof_node.base; |
| 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; |
| 2963 | expr |
| 2964 | else blk: { |
| 2965 | const child_type_node = try transQualType(c, child_type, loc); |
| 2966 | const alignof = try Node.alignof.create(c.arena, child_type_node); |
| 2967 | const align_cast = try Node.align_cast.create(c.arena, .{ .lhs = alignof, .rhs = expr }); |
| 2968 | break :blk align_cast; |
| 2969 | }; |
| 2970 | return Node.ptr_cast.create(c.arena, .{ .lhs = dst_type, .rhs = rhs }); |
| 3076 | 2971 | } |
| 3077 | 2972 | } |
| 3078 | 2973 | |
| ... | ... | @@ -3092,13 +2987,15 @@ fn transBreak(c: *Context, scope: *Scope) TransError!Node { |
| 3092 | 2987 | fn transFloatingLiteral(c: *Context, scope: *Scope, stmt: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node { |
| 3093 | 2988 | // TODO use something more accurate |
| 3094 | 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 | 2991 | return maybeSuppressResult(c, scope, used, &node.base); |
| 3097 | 2992 | } |
| 3098 | 2993 | |
| 3099 | | fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.BinaryConditionalOperator, used: ResultUsed) TransError!*ast.Node { |
| 2994 | fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.BinaryConditionalOperator, used: ResultUsed) TransError!Node { |
| 3100 | 2995 | // GNU extension of the ternary operator where the middle expression is |
| 3101 | 2996 | // 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 | 2999 | const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt); |
| 3103 | 3000 | const cond_expr = casted_stmt.getCond(); |
| 3104 | 3001 | const true_expr = casted_stmt.getTrueExpr(); |
| ... | ... | @@ -3109,67 +3006,39 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const |
| 3109 | 3006 | // const _cond_temp = (cond_expr); |
| 3110 | 3007 | // break :blk if (_cond_temp) _cond_temp else (false_expr); |
| 3111 | 3008 | // }) |
| 3112 | | const lparen = try appendToken(rp.c, .LParen, "("); |
| 3113 | | |
| 3114 | | var block_scope = try Scope.Block.init(rp.c, scope, true); |
| 3009 | var block_scope = try Scope.Block.init(c, scope, true); |
| 3115 | 3010 | defer block_scope.deinit(); |
| 3116 | 3011 | |
| 3117 | | const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp"); |
| 3118 | | const mut_tok = try appendToken(rp.c, .Keyword_const, "const"); |
| 3119 | | const name_tok = try appendIdentifier(rp.c, mangled_name); |
| 3120 | | const eq_token = try appendToken(rp.c, .Equal, "="); |
| 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, ";"); |
| 3012 | const mangled_name = try block_scope.makeMangledName(c, "cond_temp"); |
| 3013 | const init_node = try transExpr(c, &block_scope.base, cond_expr, .used, .r_value); |
| 3014 | const ref_decl = try Node.var_simple.create(c.arena, .{ .name = mangled_name, .init = init_node}); |
| 3015 | try block_scope.statements.append(ref_decl); |
| 3154 | 3016 | |
| 3155 | | const break_node = try break_node_tmp.finish(&if_node.base); |
| 3156 | | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3157 | | try block_scope.statements.append(&break_node.base); |
| 3158 | | const block_node = try block_scope.complete(rp.c); |
| 3017 | const cond_node = try transBoolExpr(c, &cond_scope.base, cond_expr, .used); |
| 3018 | var then_body = try Node.identifier.create(c.arena, mangled_name); |
| 3019 | if (!res_is_bool and isBoolRes(init_node)) { |
| 3020 | then_body = try Node.bool_to_int.create(c.arena, then_body); |
| 3021 | } |
| 3159 | 3022 | |
| 3160 | | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 3161 | | grouped_expr.* = .{ |
| 3162 | | .lparen = lparen, |
| 3163 | | .expr = block_node, |
| 3164 | | .rparen = try appendToken(rp.c, .RParen, ")"), |
| 3165 | | }; |
| 3166 | | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); |
| 3023 | var else_body = try transExpr(c, &block_scope.base, false_expr, .used, .r_value); |
| 3024 | if (!res_is_bool and isBoolRes(else_body)) { |
| 3025 | else_body = try Node.bool_to_int.create(c.arena, else_body); |
| 3026 | } |
| 3027 | const if_node = try Node.@"if".create(c.arena, .{ |
| 3028 | .cond = cond, |
| 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 | } |
| 3168 | 3040 | |
| 3169 | | fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.ConditionalOperator, used: ResultUsed) TransError!*ast.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); |
| 3041 | fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.ConditionalOperator, used: ResultUsed) TransError!Node { |
| 3173 | 3042 | var cond_scope = Scope.Condition{ |
| 3174 | 3043 | .base = .{ |
| 3175 | 3044 | .parent = scope, |
| ... | ... | @@ -3178,60 +3047,41 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang. |
| 3178 | 3047 | }; |
| 3179 | 3048 | defer cond_scope.deinit(); |
| 3180 | 3049 | |
| 3050 | const qt = @ptrCast(*const clang.Stmt, stmt).getType(); |
| 3051 | const res_is_bool = qualTypeIsBoolean(qt); |
| 3181 | 3052 | const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt); |
| 3182 | 3053 | const cond_expr = casted_stmt.getCond(); |
| 3183 | 3054 | const true_expr = casted_stmt.getTrueExpr(); |
| 3184 | 3055 | const false_expr = casted_stmt.getFalseExpr(); |
| 3185 | 3056 | |
| 3186 | | if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false); |
| 3187 | | _ = try appendToken(rp.c, .RParen, ")"); |
| 3188 | | |
| 3189 | | if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value); |
| 3057 | const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used, .r_value); |
| 3190 | 3058 | |
| 3191 | | if_node.@"else" = try transCreateNodeElse(rp.c); |
| 3192 | | if_node.@"else".?.body = try transExpr(rp, scope, false_expr, .used, .r_value); |
| 3059 | var then_body = try transExpr(c, scope, true_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 | } |
| 3193 | 3063 | |
| 3194 | | if (grouped) { |
| 3195 | | const rparen = try appendToken(rp.c, .RParen, ")"); |
| 3196 | | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 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); |
| 3064 | var else_body = try transExpr(c, scope, false_expr, .used, .r_value); |
| 3065 | if (!res_is_bool and isBoolRes(else_body)) { |
| 3066 | else_body = try Node.bool_to_int.create(c.arena, else_body); |
| 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 | } |
| 3207 | 3076 | |
| 3208 | 3077 | fn maybeSuppressResult( |
| 3209 | | rp: RestorePoint, |
| 3078 | c: *Context, |
| 3210 | 3079 | scope: *Scope, |
| 3211 | 3080 | used: ResultUsed, |
| 3212 | | result: *ast.Node, |
| 3213 | | ) TransError!*ast.Node { |
| 3081 | result: Node, |
| 3082 | ) TransError!Node { |
| 3214 | 3083 | if (used == .used) return result; |
| 3215 | | if (scope.id != .Condition) { |
| 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; |
| 3084 | return Node.ignore.create(c.arena, result); |
| 3235 | 3085 | } |
| 3236 | 3086 | |
| 3237 | 3087 | 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 | 3092 | /// only matters for incomplete arrays, since the size of the array is determined |
| 3243 | 3093 | /// by the size of the initializer |
| 3244 | 3094 | fn transQualTypeInitialized( |
| 3245 | | rp: RestorePoint, |
| 3095 | c: *Context, |
| 3246 | 3096 | qt: clang.QualType, |
| 3247 | 3097 | decl_init: *const clang.Expr, |
| 3248 | 3098 | source_loc: clang.SourceLocation, |
| 3249 | | ) TypeError!*ast.Node { |
| 3099 | ) TypeError!Node { |
| 3250 | 3100 | const ty = qt.getTypePtr(); |
| 3251 | 3101 | if (ty.getTypeClass() == .IncompleteArray) { |
| 3252 | 3102 | const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty); |
| ... | ... | @@ -3257,17 +3107,17 @@ fn transQualTypeInitialized( |
| 3257 | 3107 | const string_lit = @ptrCast(*const clang.StringLiteral, decl_init); |
| 3258 | 3108 | const string_lit_size = string_lit.getLength() + 1; // +1 for null terminator |
| 3259 | 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 | 3112 | .InitListExprClass => { |
| 3263 | 3113 | const init_expr = @ptrCast(*const clang.InitListExpr, decl_init); |
| 3264 | 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 | 3117 | else => {}, |
| 3268 | 3118 | } |
| 3269 | 3119 | } |
| 3270 | | return transQualType(rp, qt, source_loc); |
| 3120 | return transQualType(c, qt, source_loc); |
| 3271 | 3121 | } |
| 3272 | 3122 | |
| 3273 | 3123 | fn 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 | 3126 | |
| 3277 | 3127 | /// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness. |
| 3278 | 3128 | /// Asserts the type is an integer. |
| 3279 | | fn transQualTypeIntWidthOf(c: *Context, ty: clang.QualType, is_signed: bool) TypeError!*ast.Node { |
| 3129 | fn transQualTypeIntWidthOf(c: *Context, ty: clang.QualType, is_signed: bool) TypeError!Node { |
| 3280 | 3130 | return transTypeIntWidthOf(c, qualTypeCanon(ty), is_signed); |
| 3281 | 3131 | } |
| 3282 | 3132 | |
| 3283 | 3133 | /// Produces a Zig AST node by translating a Clang Type, respecting the width, but modifying the signed-ness. |
| 3284 | 3134 | /// Asserts the type is an integer. |
| 3285 | | fn transTypeIntWidthOf(c: *Context, ty: *const clang.Type, is_signed: bool) TypeError!*ast.Node { |
| 3135 | fn transTypeIntWidthOf(c: *Context, ty: *const clang.Type, is_signed: bool) TypeError!Node { |
| 3286 | 3136 | assert(ty.getTypeClass() == .Builtin); |
| 3287 | 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 | 3139 | .Char_U, .Char_S, .UChar, .SChar, .Char8 => if (is_signed) "i8" else "u8", |
| 3290 | 3140 | .UShort, .Short => if (is_signed) "c_short" else "c_ushort", |
| 3291 | 3141 | .UInt, .Int => if (is_signed) "c_int" else "c_uint", |
| ... | ... | @@ -3532,28 +3382,22 @@ fn cIsLongLongInteger(qt: clang.QualType) bool { |
| 3532 | 3382 | }; |
| 3533 | 3383 | } |
| 3534 | 3384 | fn transCreateNodeAssign( |
| 3535 | | rp: RestorePoint, |
| 3385 | c: *Context, |
| 3536 | 3386 | scope: *Scope, |
| 3537 | 3387 | result_used: ResultUsed, |
| 3538 | 3388 | lhs: *const clang.Expr, |
| 3539 | 3389 | rhs: *const clang.Expr, |
| 3540 | | ) !*ast.Node { |
| 3390 | ) !Node { |
| 3541 | 3391 | // common case |
| 3542 | 3392 | // c: lhs = rhs |
| 3543 | 3393 | // zig: lhs = rhs |
| 3544 | 3394 | if (result_used == .unused) { |
| 3545 | | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); |
| 3546 | | const eq_token = try appendToken(rp.c, .Equal, "="); |
| 3547 | | var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value); |
| 3395 | const lhs_node = try transExpr(c, scope, lhs, .used, .l_value); |
| 3396 | var rhs_node = try transExprCoercing(c, scope, rhs, .used, .r_value); |
| 3548 | 3397 | if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) { |
| 3549 | | const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1); |
| 3550 | | builtin_node.params()[0] = rhs_node; |
| 3551 | | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3552 | | rhs_node = &builtin_node.base; |
| 3398 | rhs_node = try Node.bool_to_int.create(c.arena, rhs_node); |
| 3553 | 3399 | } |
| 3554 | | if (scope.id != .Condition) |
| 3555 | | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3556 | | return transCreateNodeInfixOp(rp, scope, lhs_node, .Assign, eq_token, rhs_node, .used, false); |
| 3400 | return transCreateNodeInfixOp(c, scope, .assign, lhs_node, rhs_node, .used); |
| 3557 | 3401 | } |
| 3558 | 3402 | |
| 3559 | 3403 | // worst case |
| ... | ... | @@ -3563,76 +3407,36 @@ fn transCreateNodeAssign( |
| 3563 | 3407 | // zig: lhs = _tmp; |
| 3564 | 3408 | // zig: break :blk _tmp |
| 3565 | 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 | 3411 | defer block_scope.deinit(); |
| 3568 | 3412 | |
| 3569 | | const tmp = try block_scope.makeMangledName(rp.c, "tmp"); |
| 3570 | | const mut_tok = try appendToken(rp.c, .Keyword_const, "const"); |
| 3571 | | const name_tok = try appendIdentifier(rp.c, tmp); |
| 3572 | | const eq_token = try appendToken(rp.c, .Equal, "="); |
| 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); |
| 3413 | const tmp = try block_scope.makeMangledName(c, "tmp"); |
| 3414 | const rhs = try transExpr(c, scope, op_expr, .used, .r_value); |
| 3415 | const tmp_decl = try Node.var_simple.create(c.arena, .{ .name = tmp, .init = rhs}); |
| 3416 | try block_scope.statements.append(tmp_decl); |
| 3591 | 3417 | |
| 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, ";"); |
| 3596 | 3418 | |
| 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 | 3422 | try block_scope.statements.append(assign); |
| 3599 | 3423 | |
| 3600 | | const break_node = blk: { |
| 3601 | | var tmp_ctrl_flow = try CtrlFlow.init(rp.c, .Break, tokenSlice(rp.c, block_scope.label.?)); |
| 3602 | | const rhs_expr = try transCreateNodeIdentifier(rp.c, tmp); |
| 3603 | | break :blk try tmp_ctrl_flow.finish(rhs_expr); |
| 3604 | | }; |
| 3605 | | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 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 | | |
| 3613 | | fn 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; |
| 3424 | const break_node = try Node.break_val.create(c.arena, .{ |
| 3425 | .label = block_scope.label, |
| 3426 | .val = tmp_ident, |
| 3427 | }); |
| 3428 | try block_scope.statements.append(break_node); |
| 3429 | return block_scope.complete(c); |
| 3622 | 3430 | } |
| 3623 | 3431 | |
| 3624 | | fn transCreateNodeBoolInfixOp( |
| 3432 | fn transCreateNodeInfixOp( |
| 3625 | 3433 | c: *Context, |
| 3626 | 3434 | scope: *Scope, |
| 3627 | | stmt: *const clang.BinaryOperator, |
| 3628 | 3435 | op: ast.Node.Tag, |
| 3436 | lhs: Node, |
| 3437 | rhs: Node, |
| 3629 | 3438 | used: ResultUsed, |
| 3630 | 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 | 3440 | const payload = try c.arena.create(ast.Payload.BinOp); |
| 3637 | 3441 | payload.* = .{ |
| 3638 | 3442 | .base = .{ .tag = op }, |
| ... | ... | @@ -3644,39 +3448,19 @@ fn transCreateNodeBoolInfixOp( |
| 3644 | 3448 | return maybeSuppressResult(c, scope, used, Node.initPayload(&payload.base)); |
| 3645 | 3449 | } |
| 3646 | 3450 | |
| 3647 | | fn transCreateNodePtrType( |
| 3451 | fn transCreateNodeBoolInfixOp( |
| 3648 | 3452 | c: *Context, |
| 3649 | | is_const: bool, |
| 3650 | | is_volatile: bool, |
| 3651 | | op_tok_id: std.zig.Token.Id, |
| 3652 | | ) !*ast.Node.PtrType { |
| 3653 | | const node = try c.arena.create(ast.Node.PtrType); |
| 3654 | | const op_token = switch (op_tok_id) { |
| 3655 | | .LBracket => blk: { |
| 3656 | | const lbracket = try appendToken(c, .LBracket, "["); |
| 3657 | | _ = try appendToken(c, .Asterisk, "*"); |
| 3658 | | _ = try appendToken(c, .RBracket, "]"); |
| 3659 | | break :blk lbracket; |
| 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; |
| 3453 | scope: *Scope, |
| 3454 | stmt: *const clang.BinaryOperator, |
| 3455 | op: ast.Node.Tag, |
| 3456 | used: ResultUsed, |
| 3457 | ) !Node { |
| 3458 | std.debug.assert(op == .bool_and or op == .bool_or); |
| 3459 | |
| 3460 | const lhs = try transBoolExpr(rp, scope, stmt.getLHS(), .used, .l_value); |
| 3461 | const rhs = try transBoolExpr(rp, scope, stmt.getRHS(), .used, .r_value); |
| 3462 | |
| 3463 | return transCreateNodeInfixOp(c, scope, op, lhs, rhs, used); |
| 3680 | 3464 | } |
| 3681 | 3465 | |
| 3682 | 3466 | fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node { |
| ... | ... | @@ -3722,73 +3506,10 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node { |
| 3722 | 3506 | return Node.int_literal.create(c.arena, str); |
| 3723 | 3507 | } |
| 3724 | 3508 | |
| 3725 | | fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { |
| 3726 | | const token = try appendToken(c, .Keyword_undefined, "undefined"); |
| 3727 | | const node = try c.arena.create(ast.Node.OneToken); |
| 3728 | | node.* = .{ |
| 3729 | | .base = .{ .tag = .UndefinedLiteral }, |
| 3730 | | .token = token, |
| 3731 | | }; |
| 3732 | | return &node.base; |
| 3733 | | } |
| 3734 | | |
| 3735 | | fn 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 | | |
| 3745 | | fn 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 | | |
| 3758 | | fn 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 | | |
| 3769 | | fn 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 | | |
| 3779 | | fn 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; |
| 3509 | fn transCreateNodeNumber(c: *Context, int: anytype) !Node { |
| 3510 | const fmt_s = if (comptime std.meta.trait.isNumber(@TypeOf(int))) "{d}" else "{s}"; |
| 3511 | const str = try std.fmt.allocPrint(c.arena, fmt_s, .{int}); |
| 3512 | return Node.int_literal.create(c.arena, str); |
| 3792 | 3513 | } |
| 3793 | 3514 | |
| 3794 | 3515 | fn 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 | 3594 | return &fn_proto.base; |
| 3874 | 3595 | } |
| 3875 | 3596 | |
| 3876 | | |
| 3877 | | |
| 3878 | 3597 | fn transCreateNodeShiftOp( |
| 3879 | 3598 | c: *Context, |
| 3880 | 3599 | scope: *Scope, |
| 3881 | 3600 | stmt: *const clang.BinaryOperator, |
| 3882 | 3601 | op: Node.Tag, |
| 3602 | used: ResultUsed, |
| 3883 | 3603 | ) !Node { |
| 3884 | 3604 | std.debug.assert(op == .shl or op == .shr); |
| 3885 | 3605 | |
| ... | ... | @@ -3894,15 +3614,7 @@ fn transCreateNodeShiftOp( |
| 3894 | 3614 | const rhs = try transExprCoercing(c, scope, rhs_expr, .used, .r_value); |
| 3895 | 3615 | const rhs_casted = try Node.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs_type }); |
| 3896 | 3616 | |
| 3897 | | const payload = try c.arena.create(ast.Payload.BinOp); |
| 3898 | | payload.* = .{ |
| 3899 | | .base = .{ .tag = op }, |
| 3900 | | .data = .{ |
| 3901 | | .lhs = lhs, |
| 3902 | | .rhs = rhs_casted, |
| 3903 | | }, |
| 3904 | | }; |
| 3905 | | return Node.initPayload(&payload.base); |
| 3617 | return transCreateNodeInfixOp(c, scope, op, lhs, rhs_casted, used); |
| 3906 | 3618 | } |
| 3907 | 3619 | |
| 3908 | 3620 | fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Node { |