| ... | ... | @@ -575,6 +575,45 @@ fn transStmt( |
| 575 | 575 | } |
| 576 | 576 | } |
| 577 | 577 | |
| 578 | fn transCreateNodeShiftOp( |
| 579 | rp: RestorePoint, |
| 580 | scope: *Scope, |
| 581 | stmt: *const ZigClangBinaryOperator, |
| 582 | comptime op: ast.Node.InfixOp.Op, |
| 583 | comptime op_tok_id: std.zig.Token.Id, |
| 584 | comptime bytes: []const u8, |
| 585 | ) !*ast.Node { |
| 586 | if (!(op == .BitShiftLeft or op == .BitShiftRight)) { |
| 587 | @compileError("op must be either .BitShiftLeft or .BitShiftRight"); |
| 588 | } |
| 589 | |
| 590 | const lhs_expr = ZigClangBinaryOperator_getLHS(stmt); |
| 591 | const rhs_expr = ZigClangBinaryOperator_getRHS(stmt); |
| 592 | const rhs_location = ZigClangExpr_getBeginLoc(rhs_expr); |
| 593 | // lhs >> u5(rh) |
| 594 | |
| 595 | const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value); |
| 596 | const op_token = try appendToken(rp.c, op_tok_id, bytes); |
| 597 | |
| 598 | const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); |
| 599 | const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location); |
| 600 | try as_node.params.push(rhs_type); |
| 601 | _ = try appendToken(rp.c, .Comma, ","); |
| 602 | const rhs = try transExpr(rp, scope, rhs_expr, .used, .l_value); |
| 603 | try as_node.params.push(rhs.node); |
| 604 | as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 605 | |
| 606 | const node = try rp.c.a().create(ast.Node.InfixOp); |
| 607 | node.* = ast.Node.InfixOp{ |
| 608 | .op_token = op_token, |
| 609 | .lhs = lhs.node, |
| 610 | .op = op, |
| 611 | .rhs = &as_node.base, |
| 612 | }; |
| 613 | |
| 614 | return &node.base; |
| 615 | } |
| 616 | |
| 578 | 617 | fn transBinaryOperator( |
| 579 | 618 | rp: RestorePoint, |
| 580 | 619 | scope: *Scope, |
| ... | ... | @@ -679,15 +718,22 @@ fn transBinaryOperator( |
| 679 | 718 | }); |
| 680 | 719 | } |
| 681 | 720 | }, |
| 682 | | .Shl, |
| 683 | | .Shr, |
| 684 | | => return revertAndWarn( |
| 685 | | rp, |
| 686 | | error.UnsupportedTranslation, |
| 687 | | ZigClangBinaryOperator_getBeginLoc(stmt), |
| 688 | | "TODO: handle more C binary operators: {}", |
| 689 | | .{op}, |
| 690 | | ), |
| 721 | .Shl => { |
| 722 | const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<"); |
| 723 | return maybeSuppressResult(rp, scope, result_used, TransResult{ |
| 724 | .node = node, |
| 725 | .child_scope = scope, |
| 726 | .node_scope = scope, |
| 727 | }); |
| 728 | }, |
| 729 | .Shr => { |
| 730 | const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftRight, .AngleBracketAngleBracketRight, ">>"); |
| 731 | return maybeSuppressResult(rp, scope, result_used, TransResult{ |
| 732 | .node = node, |
| 733 | .child_scope = scope, |
| 734 | .node_scope = scope, |
| 735 | }); |
| 736 | }, |
| 691 | 737 | .LT => { |
| 692 | 738 | const node = try transCreateNodeInfixOp(rp, scope, stmt, .LessThan, .AngleBracketLeft, "<", true); |
| 693 | 739 | return maybeSuppressResult(rp, scope, result_used, TransResult{ |
| ... | ... | @@ -1664,6 +1710,95 @@ fn qualTypeIsPtr(qt: ZigClangQualType) bool { |
| 1664 | 1710 | return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer; |
| 1665 | 1711 | } |
| 1666 | 1712 | |
| 1713 | fn qualTypeIntBitWidth(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !u32 { |
| 1714 | const ty = ZigClangQualType_getTypePtr(qt); |
| 1715 | |
| 1716 | switch (ZigClangType_getTypeClass(ty)) { |
| 1717 | .Builtin => { |
| 1718 | const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); |
| 1719 | |
| 1720 | switch (ZigClangBuiltinType_getKind(builtin_ty)) { |
| 1721 | .Char_U, |
| 1722 | .UChar, |
| 1723 | .Char_S, |
| 1724 | .SChar, |
| 1725 | => return 8, |
| 1726 | .UInt128, |
| 1727 | .Int128, |
| 1728 | => return 128, |
| 1729 | else => return 0, |
| 1730 | } |
| 1731 | |
| 1732 | unreachable; |
| 1733 | }, |
| 1734 | .Typedef => { |
| 1735 | const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); |
| 1736 | const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); |
| 1737 | const type_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); |
| 1738 | |
| 1739 | if (std.mem.eql(u8, type_name, "uint8_t") or std.mem.eql(u8, type_name, "int8_t")) { |
| 1740 | return 8; |
| 1741 | } else if (std.mem.eql(u8, type_name, "uint16_t") or std.mem.eql(u8, type_name, "int16_t")) { |
| 1742 | return 16; |
| 1743 | } else if (std.mem.eql(u8, type_name, "uint32_t") or std.mem.eql(u8, type_name, "int32_t")) { |
| 1744 | return 32; |
| 1745 | } else if (std.mem.eql(u8, type_name, "uint64_t") or std.mem.eql(u8, type_name, "int64_t")) { |
| 1746 | return 64; |
| 1747 | } else { |
| 1748 | return 0; |
| 1749 | } |
| 1750 | }, |
| 1751 | else => return 0, |
| 1752 | } |
| 1753 | |
| 1754 | unreachable; |
| 1755 | } |
| 1756 | |
| 1757 | fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !*ast.Node { |
| 1758 | const int_bit_width = try qualTypeIntBitWidth(rp, qt, source_loc); |
| 1759 | |
| 1760 | if (int_bit_width != 0) { |
| 1761 | // we can perform the log2 now. |
| 1762 | const cast_bit_width = std.math.log2_int(u64, int_bit_width); |
| 1763 | const node = try rp.c.a().create(ast.Node.IntegerLiteral); |
| 1764 | node.* = ast.Node.IntegerLiteral{ |
| 1765 | .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}), |
| 1766 | }; |
| 1767 | return &node.base; |
| 1768 | } |
| 1769 | |
| 1770 | const zig_type_node = try transQualType(rp, qt, source_loc); |
| 1771 | |
| 1772 | // @import("std").math.Log2Int(c_long); |
| 1773 | // |
| 1774 | // FnCall |
| 1775 | // FieldAccess |
| 1776 | // FieldAccess |
| 1777 | // FnCall (.builtin = true) |
| 1778 | // Symbol "import" |
| 1779 | // StringLiteral "std" |
| 1780 | // Symbol "math" |
| 1781 | // Symbol "Log2Int" |
| 1782 | // Symbol <zig_type_node> (var from above) |
| 1783 | |
| 1784 | const import_fn_call = try transCreateNodeBuiltinFnCall(rp.c, "@import"); |
| 1785 | const std_token = try appendToken(rp.c, .StringLiteral, "\"std\""); |
| 1786 | const std_node = try rp.c.a().create(ast.Node.StringLiteral); |
| 1787 | std_node.* = ast.Node.StringLiteral{ |
| 1788 | .token = std_token, |
| 1789 | }; |
| 1790 | try import_fn_call.params.push(&std_node.base); |
| 1791 | import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1792 | |
| 1793 | const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math"); |
| 1794 | const outer_field_access = try transCreateNodeFieldAccess(rp.c, &inner_field_access.base, "Log2Int"); |
| 1795 | const log2int_fn_call = try transCreateNodeFnCall(rp.c, &outer_field_access.base); |
| 1796 | try @ptrCast(*ast.Node.SuffixOp.Op.Call, &log2int_fn_call.op).params.push(zig_type_node); |
| 1797 | log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")"); |
| 1798 | |
| 1799 | return &log2int_fn_call.base; |
| 1800 | } |
| 1801 | |
| 1667 | 1802 | fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool { |
| 1668 | 1803 | const ty = ZigClangQualType_getTypePtr(qt); |
| 1669 | 1804 | |
| ... | ... | @@ -1827,7 +1962,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { |
| 1827 | 1962 | _ = try appendToken(c, .LParen, "("); |
| 1828 | 1963 | const node = try c.a().create(ast.Node.SuffixOp); |
| 1829 | 1964 | node.* = ast.Node.SuffixOp{ |
| 1830 | | .lhs = fn_expr, |
| 1965 | .lhs = .{ .node = fn_expr }, |
| 1831 | 1966 | .op = ast.Node.SuffixOp.Op{ |
| 1832 | 1967 | .Call = ast.Node.SuffixOp.Op.Call{ |
| 1833 | 1968 | .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()), |
| ... | ... | @@ -1839,6 +1974,17 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { |
| 1839 | 1974 | return node; |
| 1840 | 1975 | } |
| 1841 | 1976 | |
| 1977 | fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node.InfixOp { |
| 1978 | const field_access_node = try c.a().create(ast.Node.InfixOp); |
| 1979 | field_access_node.* = .{ |
| 1980 | .op_token = try appendToken(c, .Period, "."), |
| 1981 | .lhs = container, |
| 1982 | .op = .Period, |
| 1983 | .rhs = try transCreateNodeIdentifier(c, field_name), |
| 1984 | }; |
| 1985 | return field_access_node; |
| 1986 | } |
| 1987 | |
| 1842 | 1988 | fn transCreateNodePrefixOp( |
| 1843 | 1989 | c: *Context, |
| 1844 | 1990 | op: ast.Node.PrefixOp.Op, |