From e632c2ade3d9ea2cfaa201b20f523d315d9c47fd Mon Sep 17 00:00:00 2001 From: hryx Date: Mon, 27 May 2019 23:55:48 -0700 Subject: [PATCH] (broken) port a bunch of stuff from stage1 translate-c --- src-self-hosted/clang.zig | 1 + src-self-hosted/translate_c.zig | 218 +++++++++++++++++++++++++++++++- 2 files changed, 212 insertions(+), 7 deletions(-) diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index d1fe5153bb..108204d401 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -486,6 +486,7 @@ pub extern fn ZigClangQualType_isConstQualified(arg0: struct_ZigClangQualType) b pub extern fn ZigClangQualType_isVolatileQualified(arg0: struct_ZigClangQualType) bool; pub extern fn ZigClangQualType_isRestrictQualified(arg0: struct_ZigClangQualType) bool; pub extern fn ZigClangType_getTypeClass(self: ?*const struct_ZigClangType) ZigClangTypeClass; +pub extern fn ZigClangType_getPointeeType(self: ?*const struct_ZigClangType) struct_ZigClangQualType; pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool; pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*]const u8; pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index ffb325d192..017b861458 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -20,7 +20,7 @@ pub const ClangErrMsg = Stage2ErrorMsg; pub const Error = error{OutOfMemory}; const TypeError = Error || error{UnsupportedType}; -const TransError = Error || error{UnsupportedTranslation}; +const TransError = TypeError || error{UnsupportedTranslation}; const DeclTable = std.HashMap(usize, void, addrHash, addrEql); @@ -199,7 +199,7 @@ pub fn translate( return context.err; } - _ = try appendToken(&context, .Eof, ""); + tree.root_node.eof_token = try appendToken(&context, .Eof, ""); tree.source = source_buffer.toOwnedSlice(); if (false) { 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 { const body_stmt = ZigClangFunctionDecl_getBody(fn_decl); const result = transStmt(rp, scope, body_stmt, .unused, .r_value) catch |err| switch (err) { error.OutOfMemory => |e| return e, - error.UnsupportedTranslation => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function"), + error.UnsupportedTranslation, + error.UnsupportedType, + => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function"), }; assert(result.node.id == ast.Node.Id.Block); proto_node.body_node = result.node; @@ -484,7 +486,11 @@ fn transImplicitCastExpr( const node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value); const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr)); const src_type = getExprQualType(c, sub_expr); - return try transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, node.node); + return TransResult{ + .node = try transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, node.node), + .node_scope = scope, + .child_scope = scope, + }; }, .FunctionToPointerDecay, .ArrayToPointerDecay => { return maybeSuppressResult( @@ -510,9 +516,27 @@ fn transCCast( loc: ZigClangSourceLocation, dst_type: ZigClangQualType, src_type: ZigClangQualType, - target_node: *ast.Node, -) !TransResult { - return revertAndWarn(rp, error.UnsupportedTranslation, loc, "TODO implement translation of C cast"); + expr: *ast.Node, +) !*ast.Node { + if (ZigClangType_isVoidType(qualTypeCanon(dst_type))) return expr; + if (ZigClangQualType_eq(dst_type, src_type)) return expr; + if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type)) + return transCPtrCast(rp, loc, dst_type, src_type, expr); + if (cIsUnsignedInteger(dst_type) and qualTypeIsPtr(src_type)) { + const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "ptrToInt"); + try builtin_node.params.push(expr); + return &(try transCreateNodeFnCall(rp.c, try transQualType(rp, dst_type, loc), &builtin_node.base)).base; + } + if (cIsUnsignedInteger(src_type) and qualTypeIsPtr(dst_type)) { + const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "intToPtr"); + try builtin_node.params.push(try transQualType(rp, dst_type, loc)); + try builtin_node.params.push(expr); + return &builtin_node.base; + } + // TODO: maybe widen to increase size + // TODO: maybe bitcast to change sign + // TODO: maybe truncate to reduce size + return &(try transCreateNodeFnCall(rp.c, try transQualType(rp, dst_type, loc), expr)).base; } fn transExpr( @@ -542,6 +566,38 @@ fn transLookupZigIdentifier(inner: *Scope, c_name: []const u8) []const u8 { } } +fn transCPtrCast( + rp: RestorePoint, + loc: ZigClangSourceLocation, + dst_type: ZigClangQualType, + src_type: ZigClangQualType, + expr: *ast.Node, +) !*ast.Node { + const ty = ZigClangQualType_getTypePtr(dst_type); + const child_type = ZigClangType_getPointeeType(ty); + const dst_type_node = try transType(rp, ty, loc); + const child_type_node = try transQualType(rp, child_type, loc); + + // Implicit downcasting from higher to lower alignment values is forbidden, + // use @alignCast to side-step this problem + const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "ptrCast"); + try ptrcast_node.params.push(dst_type_node); + + if (ZigClangType_isVoidType(qualTypeCanon(child_type))) { + // void has 1-byte alignment, so @alignCast is not needed + try ptrcast_node.params.push(expr); + } else { + const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "alignOf"); + try alignof_node.params.push(child_type_node); + const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "alignCast"); + try aligncast_node.params.push(&alignof_node.base); + try aligncast_node.params.push(expr); + try ptrcast_node.params.push(&aligncast_node.base); + } + + return &ptrcast_node.base; +} + fn maybeSuppressResult( rp: RestorePoint, scope: *Scope, @@ -574,6 +630,24 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); } +fn qualTypeIsPtr(qt: ZigClangQualType) bool { + return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer; +} + +fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool { + const ty = ZigClangQualType_getTypePtr(qt); + if (ZigClangType_getTypeClass(ty) == .Paren) { + const paren_type = @ptrCast(*const ZigClangParenType, ty); + const inner_type = ZigClangParenType_getInnerType(ty); + return ZigClangQualType_getTypeClass(inner_type) == .FunctionProto; + } + if (ZigClangType_getTypeClass(ty) == .Attributed) { + const attr_type = @ptrCast(*const ZigClangAttributedType, ty); + return qualTypeChildIsFnProto(bitcast(ZigClangAttributedType_getEquivalentType(attr_type))); + } + return false; +} + fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType { const canon = ZigClangQualType_getCanonicalType(qt); return ZigClangQualType_getTypePtr(canon); @@ -596,6 +670,113 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType { return ZigClangExpr_getType(expr); } +fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool { + switch (ZigClangType_getTypeClass(ty)) { + .Builtin => { + const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); + return ZigClangBuiltinType_getKind(builtin_ty) == .Void; + }, + .Record => { + const record_ty = @ptrCast(*const ZigClangRecordType, ty); + const record_decl = ZigClangRecordType_getDecl(record_ty); + return (ZigClangRecordDecl_getDefinition(record_decl) == null); + }, + .Elaborated => { + const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty); + const qt = ZigClangElaboratedType_getNamedType(elaborated_ty); + return typeIsOpaque(c, ZigClangQualType_getTypePtr(qt), loc); + }, + .Typedef => { + const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); + const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); + const underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); + return typeIsOpaque(c, ZigClangQualType_getTypePtr(underlying_type), loc); + }, + else => return false, + } +} + +fn cIsUnsignedInteger(qt: ZigClangQualType) bool { + const c_type = qualTypeCanon(qt); + if (ZigClangType_getTypeClass(c_type) != .Builtin) return false; + const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type); + return switch (ZigClangBuiltinType_getKind(builtin_ty)) { + .Char_U, + .UChar, + .Char_S, + .UShort, + .UInt, + .ULong, + .ULongLong, + .UInt128, + .WChar_U, + => true, + else => false, + }; +} + +fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.BuiltinCall { + const node = try c.a().create(ast.Node.BuiltinCall); + node.* = ast.Node.BuiltinCall{ + .base = ast.Node{ .id = .BuiltinCall }, + .builtin_token = try appendToken(c, .Builtin, name), + .params = ast.Node.BuiltinCall.ParamList.init(c.a()), + .rparen_token = undefined, // TODO TokenIndex, + }; + return node; +} + +fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node, first_arg: *ast.Node) !*ast.Node.SuffixOp { + const node = try c.a().create(ast.Node.SuffixOp); + node.* = ast.Node.SuffixOp{ + .base = ast.Node{ .id = .SuffixOp }, + .lhs = fn_expr, + .op = ast.Node.SuffixOp.Op{ + .Call = ast.Node.SuffixOp.Op.Call{ + .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()), + .async_attr = null, + }, + }, + .rtoken = undefined, // TODO TokenIndex + }; + return node; +} + +fn transCreateNodePrefixOp(c: *Context, op: ast.Node.PrefixOp.Op, rhs: *ast.Node) !*ast.Node { + const node = try c.a().create(ast.Node.PrefixOp); + node.* = ast.Node.PrefixOp{ + .base = ast.Node{ .id = .PrefixOp }, + .op_token = undefined, // TODO TokenIndex, + .op = op, + .rhs = rhs, + }; + return &node.base; +} + +fn transCreateNodePtrType( + c: *Context, + is_const: bool, + is_volatile: bool, + rhs: *ast.Node, + op_tok_id: std.zig.Token.Id, +) !*ast.Node { + const node = try c.a().create(ast.Node.PrefixOp); + node.* = ast.Node.PrefixOp{ + .base = ast.Node{ .id = .PrefixOp }, + .op_token = try appendToken(c, op_tok_id, ""), // TODO TokenIndex, + .op = ast.Node.PrefixOp.Op{ + .PtrType = ast.Node.PrefixOp.PtrInfo{ + .allowzero_token = null, + .align_info = null, + .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null, + .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null, + }, + }, + .rhs = rhs, + }; + return &node.base; +} + const RestorePoint = struct { c: *Context, token_index: ast.TokenIndex, @@ -642,6 +823,29 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type"), } }, + .Pointer => { + const child_qt = ZigClangType_getPointeeType(ty); + const child_node = try transQualType(rp, child_qt, source_loc); + if (qualTypeChildIsFnProto(child_qt)) + return transCreateNodePrefixOp(rp.c, .OptionalType, child_node); + if (typeIsOpaque(rp.c, ZigClangQualType_getTypePtr(child_qt), source_loc)) { + const pointer_node = try transCreateNodePtrType( + rp.c, + ZigClangQualType_isConstQualified(child_qt), + ZigClangQualType_isVolatileQualified(child_qt), + child_node, + .Asterisk, + ); + return transCreateNodePrefixOp(rp.c, .OptionalType, pointer_node); + } + return transCreateNodePtrType( + rp.c, + ZigClangQualType_isConstQualified(child_qt), + ZigClangQualType_isVolatileQualified(child_qt), + child_node, + .BracketStarCBracket, + ); + }, .FunctionProto => { const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); const fn_proto = try transFnProto(rp, fn_proto_ty, source_loc, null);