| ... | @@ -20,7 +20,7 @@ pub const ClangErrMsg = Stage2ErrorMsg; | ... | @@ -20,7 +20,7 @@ pub const ClangErrMsg = Stage2ErrorMsg; |
| 20 | | 20 | |
| 21 | pub const Error = error{OutOfMemory}; | 21 | pub const Error = error{OutOfMemory}; |
| 22 | const TypeError = Error || error{UnsupportedType}; | 22 | const TypeError = Error || error{UnsupportedType}; |
| 23 | const TransError = Error || error{UnsupportedTranslation}; | 23 | const TransError = TypeError || error{UnsupportedTranslation}; |
| 24 | | 24 | |
| 25 | const DeclTable = std.HashMap(usize, void, addrHash, addrEql); | 25 | const DeclTable = std.HashMap(usize, void, addrHash, addrEql); |
| 26 | | 26 | |
| ... | @@ -199,7 +199,7 @@ pub fn translate( | ... | @@ -199,7 +199,7 @@ pub fn translate( |
| 199 | return context.err; | 199 | return context.err; |
| 200 | } | 200 | } |
| 201 | | 201 | |
| 202 | _ = try appendToken(&context, .Eof, ""); | 202 | tree.root_node.eof_token = try appendToken(&context, .Eof, ""); |
| 203 | tree.source = source_buffer.toOwnedSlice(); | 203 | tree.source = source_buffer.toOwnedSlice(); |
| 204 | if (false) { | 204 | if (false) { |
| 205 | std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", tree.source); | 205 | std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", tree.source); |
| ... | @@ -299,7 +299,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { | ... | @@ -299,7 +299,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 299 | const body_stmt = ZigClangFunctionDecl_getBody(fn_decl); | 299 | const body_stmt = ZigClangFunctionDecl_getBody(fn_decl); |
| 300 | const result = transStmt(rp, scope, body_stmt, .unused, .r_value) catch |err| switch (err) { | 300 | const result = transStmt(rp, scope, body_stmt, .unused, .r_value) catch |err| switch (err) { |
| 301 | error.OutOfMemory => |e| return e, | 301 | error.OutOfMemory => |e| return e, |
| 302 | error.UnsupportedTranslation => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function"), | 302 | error.UnsupportedTranslation, |
| | 303 | error.UnsupportedType, |
| | 304 | => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function"), |
| 303 | }; | 305 | }; |
| 304 | assert(result.node.id == ast.Node.Id.Block); | 306 | assert(result.node.id == ast.Node.Id.Block); |
| 305 | proto_node.body_node = result.node; | 307 | proto_node.body_node = result.node; |
| ... | @@ -484,7 +486,11 @@ fn transImplicitCastExpr( | ... | @@ -484,7 +486,11 @@ fn transImplicitCastExpr( |
| 484 | const node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value); | 486 | const node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value); |
| 485 | const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr)); | 487 | const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr)); |
| 486 | const src_type = getExprQualType(c, sub_expr); | 488 | const src_type = getExprQualType(c, sub_expr); |
| 487 | return try transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, node.node); | 489 | return TransResult{ |
| | 490 | .node = try transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, node.node), |
| | 491 | .node_scope = scope, |
| | 492 | .child_scope = scope, |
| | 493 | }; |
| 488 | }, | 494 | }, |
| 489 | .FunctionToPointerDecay, .ArrayToPointerDecay => { | 495 | .FunctionToPointerDecay, .ArrayToPointerDecay => { |
| 490 | return maybeSuppressResult( | 496 | return maybeSuppressResult( |
| ... | @@ -510,9 +516,27 @@ fn transCCast( | ... | @@ -510,9 +516,27 @@ fn transCCast( |
| 510 | loc: ZigClangSourceLocation, | 516 | loc: ZigClangSourceLocation, |
| 511 | dst_type: ZigClangQualType, | 517 | dst_type: ZigClangQualType, |
| 512 | src_type: ZigClangQualType, | 518 | src_type: ZigClangQualType, |
| 513 | target_node: *ast.Node, | 519 | expr: *ast.Node, |
| 514 | ) !TransResult { | 520 | ) !*ast.Node { |
| 515 | return revertAndWarn(rp, error.UnsupportedTranslation, loc, "TODO implement translation of C cast"); | 521 | if (ZigClangType_isVoidType(qualTypeCanon(dst_type))) return expr; |
| | 522 | if (ZigClangQualType_eq(dst_type, src_type)) return expr; |
| | 523 | if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type)) |
| | 524 | return transCPtrCast(rp, loc, dst_type, src_type, expr); |
| | 525 | if (cIsUnsignedInteger(dst_type) and qualTypeIsPtr(src_type)) { |
| | 526 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "ptrToInt"); |
| | 527 | try builtin_node.params.push(expr); |
| | 528 | return &(try transCreateNodeFnCall(rp.c, try transQualType(rp, dst_type, loc), &builtin_node.base)).base; |
| | 529 | } |
| | 530 | if (cIsUnsignedInteger(src_type) and qualTypeIsPtr(dst_type)) { |
| | 531 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "intToPtr"); |
| | 532 | try builtin_node.params.push(try transQualType(rp, dst_type, loc)); |
| | 533 | try builtin_node.params.push(expr); |
| | 534 | return &builtin_node.base; |
| | 535 | } |
| | 536 | // TODO: maybe widen to increase size |
| | 537 | // TODO: maybe bitcast to change sign |
| | 538 | // TODO: maybe truncate to reduce size |
| | 539 | return &(try transCreateNodeFnCall(rp.c, try transQualType(rp, dst_type, loc), expr)).base; |
| 516 | } | 540 | } |
| 517 | | 541 | |
| 518 | fn transExpr( | 542 | fn transExpr( |
| ... | @@ -542,6 +566,38 @@ fn transLookupZigIdentifier(inner: *Scope, c_name: []const u8) []const u8 { | ... | @@ -542,6 +566,38 @@ fn transLookupZigIdentifier(inner: *Scope, c_name: []const u8) []const u8 { |
| 542 | } | 566 | } |
| 543 | } | 567 | } |
| 544 | | 568 | |
| | 569 | fn transCPtrCast( |
| | 570 | rp: RestorePoint, |
| | 571 | loc: ZigClangSourceLocation, |
| | 572 | dst_type: ZigClangQualType, |
| | 573 | src_type: ZigClangQualType, |
| | 574 | expr: *ast.Node, |
| | 575 | ) !*ast.Node { |
| | 576 | const ty = ZigClangQualType_getTypePtr(dst_type); |
| | 577 | const child_type = ZigClangType_getPointeeType(ty); |
| | 578 | const dst_type_node = try transType(rp, ty, loc); |
| | 579 | const child_type_node = try transQualType(rp, child_type, loc); |
| | 580 | |
| | 581 | // Implicit downcasting from higher to lower alignment values is forbidden, |
| | 582 | // use @alignCast to side-step this problem |
| | 583 | const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "ptrCast"); |
| | 584 | try ptrcast_node.params.push(dst_type_node); |
| | 585 | |
| | 586 | if (ZigClangType_isVoidType(qualTypeCanon(child_type))) { |
| | 587 | // void has 1-byte alignment, so @alignCast is not needed |
| | 588 | try ptrcast_node.params.push(expr); |
| | 589 | } else { |
| | 590 | const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "alignOf"); |
| | 591 | try alignof_node.params.push(child_type_node); |
| | 592 | const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "alignCast"); |
| | 593 | try aligncast_node.params.push(&alignof_node.base); |
| | 594 | try aligncast_node.params.push(expr); |
| | 595 | try ptrcast_node.params.push(&aligncast_node.base); |
| | 596 | } |
| | 597 | |
| | 598 | return &ptrcast_node.base; |
| | 599 | } |
| | 600 | |
| 545 | fn maybeSuppressResult( | 601 | fn maybeSuppressResult( |
| 546 | rp: RestorePoint, | 602 | rp: RestorePoint, |
| 547 | scope: *Scope, | 603 | scope: *Scope, |
| ... | @@ -574,6 +630,24 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou | ... | @@ -574,6 +630,24 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou |
| 574 | return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); | 630 | return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); |
| 575 | } | 631 | } |
| 576 | | 632 | |
| | 633 | fn qualTypeIsPtr(qt: ZigClangQualType) bool { |
| | 634 | return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer; |
| | 635 | } |
| | 636 | |
| | 637 | fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool { |
| | 638 | const ty = ZigClangQualType_getTypePtr(qt); |
| | 639 | if (ZigClangType_getTypeClass(ty) == .Paren) { |
| | 640 | const paren_type = @ptrCast(*const ZigClangParenType, ty); |
| | 641 | const inner_type = ZigClangParenType_getInnerType(ty); |
| | 642 | return ZigClangQualType_getTypeClass(inner_type) == .FunctionProto; |
| | 643 | } |
| | 644 | if (ZigClangType_getTypeClass(ty) == .Attributed) { |
| | 645 | const attr_type = @ptrCast(*const ZigClangAttributedType, ty); |
| | 646 | return qualTypeChildIsFnProto(bitcast(ZigClangAttributedType_getEquivalentType(attr_type))); |
| | 647 | } |
| | 648 | return false; |
| | 649 | } |
| | 650 | |
| 577 | fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType { | 651 | fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType { |
| 578 | const canon = ZigClangQualType_getCanonicalType(qt); | 652 | const canon = ZigClangQualType_getCanonicalType(qt); |
| 579 | return ZigClangQualType_getTypePtr(canon); | 653 | return ZigClangQualType_getTypePtr(canon); |
| ... | @@ -596,6 +670,113 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType { | ... | @@ -596,6 +670,113 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType { |
| 596 | return ZigClangExpr_getType(expr); | 670 | return ZigClangExpr_getType(expr); |
| 597 | } | 671 | } |
| 598 | | 672 | |
| | 673 | fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool { |
| | 674 | switch (ZigClangType_getTypeClass(ty)) { |
| | 675 | .Builtin => { |
| | 676 | const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); |
| | 677 | return ZigClangBuiltinType_getKind(builtin_ty) == .Void; |
| | 678 | }, |
| | 679 | .Record => { |
| | 680 | const record_ty = @ptrCast(*const ZigClangRecordType, ty); |
| | 681 | const record_decl = ZigClangRecordType_getDecl(record_ty); |
| | 682 | return (ZigClangRecordDecl_getDefinition(record_decl) == null); |
| | 683 | }, |
| | 684 | .Elaborated => { |
| | 685 | const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty); |
| | 686 | const qt = ZigClangElaboratedType_getNamedType(elaborated_ty); |
| | 687 | return typeIsOpaque(c, ZigClangQualType_getTypePtr(qt), loc); |
| | 688 | }, |
| | 689 | .Typedef => { |
| | 690 | const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); |
| | 691 | const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); |
| | 692 | const underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); |
| | 693 | return typeIsOpaque(c, ZigClangQualType_getTypePtr(underlying_type), loc); |
| | 694 | }, |
| | 695 | else => return false, |
| | 696 | } |
| | 697 | } |
| | 698 | |
| | 699 | fn cIsUnsignedInteger(qt: ZigClangQualType) bool { |
| | 700 | const c_type = qualTypeCanon(qt); |
| | 701 | if (ZigClangType_getTypeClass(c_type) != .Builtin) return false; |
| | 702 | const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type); |
| | 703 | return switch (ZigClangBuiltinType_getKind(builtin_ty)) { |
| | 704 | .Char_U, |
| | 705 | .UChar, |
| | 706 | .Char_S, |
| | 707 | .UShort, |
| | 708 | .UInt, |
| | 709 | .ULong, |
| | 710 | .ULongLong, |
| | 711 | .UInt128, |
| | 712 | .WChar_U, |
| | 713 | => true, |
| | 714 | else => false, |
| | 715 | }; |
| | 716 | } |
| | 717 | |
| | 718 | fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.BuiltinCall { |
| | 719 | const node = try c.a().create(ast.Node.BuiltinCall); |
| | 720 | node.* = ast.Node.BuiltinCall{ |
| | 721 | .base = ast.Node{ .id = .BuiltinCall }, |
| | 722 | .builtin_token = try appendToken(c, .Builtin, name), |
| | 723 | .params = ast.Node.BuiltinCall.ParamList.init(c.a()), |
| | 724 | .rparen_token = undefined, // TODO TokenIndex, |
| | 725 | }; |
| | 726 | return node; |
| | 727 | } |
| | 728 | |
| | 729 | fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node, first_arg: *ast.Node) !*ast.Node.SuffixOp { |
| | 730 | const node = try c.a().create(ast.Node.SuffixOp); |
| | 731 | node.* = ast.Node.SuffixOp{ |
| | 732 | .base = ast.Node{ .id = .SuffixOp }, |
| | 733 | .lhs = fn_expr, |
| | 734 | .op = ast.Node.SuffixOp.Op{ |
| | 735 | .Call = ast.Node.SuffixOp.Op.Call{ |
| | 736 | .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()), |
| | 737 | .async_attr = null, |
| | 738 | }, |
| | 739 | }, |
| | 740 | .rtoken = undefined, // TODO TokenIndex |
| | 741 | }; |
| | 742 | return node; |
| | 743 | } |
| | 744 | |
| | 745 | fn transCreateNodePrefixOp(c: *Context, op: ast.Node.PrefixOp.Op, rhs: *ast.Node) !*ast.Node { |
| | 746 | const node = try c.a().create(ast.Node.PrefixOp); |
| | 747 | node.* = ast.Node.PrefixOp{ |
| | 748 | .base = ast.Node{ .id = .PrefixOp }, |
| | 749 | .op_token = undefined, // TODO TokenIndex, |
| | 750 | .op = op, |
| | 751 | .rhs = rhs, |
| | 752 | }; |
| | 753 | return &node.base; |
| | 754 | } |
| | 755 | |
| | 756 | fn transCreateNodePtrType( |
| | 757 | c: *Context, |
| | 758 | is_const: bool, |
| | 759 | is_volatile: bool, |
| | 760 | rhs: *ast.Node, |
| | 761 | op_tok_id: std.zig.Token.Id, |
| | 762 | ) !*ast.Node { |
| | 763 | const node = try c.a().create(ast.Node.PrefixOp); |
| | 764 | node.* = ast.Node.PrefixOp{ |
| | 765 | .base = ast.Node{ .id = .PrefixOp }, |
| | 766 | .op_token = try appendToken(c, op_tok_id, ""), // TODO TokenIndex, |
| | 767 | .op = ast.Node.PrefixOp.Op{ |
| | 768 | .PtrType = ast.Node.PrefixOp.PtrInfo{ |
| | 769 | .allowzero_token = null, |
| | 770 | .align_info = null, |
| | 771 | .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null, |
| | 772 | .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null, |
| | 773 | }, |
| | 774 | }, |
| | 775 | .rhs = rhs, |
| | 776 | }; |
| | 777 | return &node.base; |
| | 778 | } |
| | 779 | |
| 599 | const RestorePoint = struct { | 780 | const RestorePoint = struct { |
| 600 | c: *Context, | 781 | c: *Context, |
| 601 | token_index: ast.TokenIndex, | 782 | token_index: ast.TokenIndex, |
| ... | @@ -642,6 +823,29 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour | ... | @@ -642,6 +823,29 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 642 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type"), | 823 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type"), |
| 643 | } | 824 | } |
| 644 | }, | 825 | }, |
| | 826 | .Pointer => { |
| | 827 | const child_qt = ZigClangType_getPointeeType(ty); |
| | 828 | const child_node = try transQualType(rp, child_qt, source_loc); |
| | 829 | if (qualTypeChildIsFnProto(child_qt)) |
| | 830 | return transCreateNodePrefixOp(rp.c, .OptionalType, child_node); |
| | 831 | if (typeIsOpaque(rp.c, ZigClangQualType_getTypePtr(child_qt), source_loc)) { |
| | 832 | const pointer_node = try transCreateNodePtrType( |
| | 833 | rp.c, |
| | 834 | ZigClangQualType_isConstQualified(child_qt), |
| | 835 | ZigClangQualType_isVolatileQualified(child_qt), |
| | 836 | child_node, |
| | 837 | .Asterisk, |
| | 838 | ); |
| | 839 | return transCreateNodePrefixOp(rp.c, .OptionalType, pointer_node); |
| | 840 | } |
| | 841 | return transCreateNodePtrType( |
| | 842 | rp.c, |
| | 843 | ZigClangQualType_isConstQualified(child_qt), |
| | 844 | ZigClangQualType_isVolatileQualified(child_qt), |
| | 845 | child_node, |
| | 846 | .BracketStarCBracket, |
| | 847 | ); |
| | 848 | }, |
| 645 | .FunctionProto => { | 849 | .FunctionProto => { |
| 646 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); | 850 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); |
| 647 | const fn_proto = try transFnProto(rp, fn_proto_ty, source_loc, null); | 851 | const fn_proto = try transFnProto(rp, fn_proto_ty, source_loc, null); |