Commit d54c288bd3

Vexu <git@vexu.eu>
2019-12-18 22:56:39
translate-c-2 function calls
1 parent c2666c4
Changed files (3)
src-self-hosted/clang.zig
@@ -839,6 +839,7 @@ pub extern fn ZigClangFunctionType_getReturnType(self: *const ZigClangFunctionTy
 pub extern fn ZigClangFunctionProtoType_isVariadic(self: *const struct_ZigClangFunctionProtoType) bool;
 pub extern fn ZigClangFunctionProtoType_getNumParams(self: *const struct_ZigClangFunctionProtoType) c_uint;
 pub extern fn ZigClangFunctionProtoType_getParamType(self: *const struct_ZigClangFunctionProtoType, i: c_uint) ZigClangQualType;
+pub extern fn ZigClangFunctionProtoType_getReturnType(self: *const ZigClangFunctionProtoType) ZigClangQualType;
 
 pub const ZigClangSourceLocation = struct_ZigClangSourceLocation;
 pub const ZigClangQualType = struct_ZigClangQualType;
@@ -993,6 +994,7 @@ pub extern fn ZigClangIncompleteArrayType_getElementType(*const ZigClangIncomple
 pub extern fn ZigClangConstantArrayType_getElementType(self: *const struct_ZigClangConstantArrayType) ZigClangQualType;
 pub extern fn ZigClangConstantArrayType_getSize(self: *const struct_ZigClangConstantArrayType) *const struct_ZigClangAPInt;
 pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const ZigClangValueDecl;
+pub extern fn ZigClangDeclRefExpr_getFoundDecl(*const ZigClangDeclRefExpr) *const ZigClangNamedDecl;
 
 pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType;
 
@@ -1105,3 +1107,7 @@ pub extern fn ZigClangMemberExpr_getMemberDecl(*const ZigClangMemberExpr) *const
 pub extern fn ZigClangArraySubscriptExpr_getBase(*const ZigClangArraySubscriptExpr) *const ZigClangExpr;
 pub extern fn ZigClangArraySubscriptExpr_getIdx(*const ZigClangArraySubscriptExpr) *const ZigClangExpr;
 
+pub extern fn ZigClangCallExpr_getCallee(*const ZigClangCallExpr) *const ZigClangExpr;
+pub extern fn ZigClangCallExpr_getNumArgs(*const ZigClangCallExpr) c_uint;
+pub extern fn ZigClangCallExpr_getArgs(*const ZigClangCallExpr) [*]const *const ZigClangExpr;
+
src-self-hosted/translate_c.zig
@@ -851,6 +851,7 @@ fn transStmt(
         .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used),
         .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const ZigClangMemberExpr, stmt), result_used),
         .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used),
+        .CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const ZigClangCallExpr, stmt), result_used),
         else => {
             return revertAndWarn(
                 rp,
@@ -2004,6 +2005,73 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS
     return maybeSuppressResult(rp, scope, result_used, &node.base);
 }
 
+fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCallExpr, result_used: ResultUsed) TransError!*ast.Node {
+    const callee = ZigClangCallExpr_getCallee(stmt);
+    var raw_fn_expr = try transExpr(rp, scope, callee, .used, .r_value);
+
+    var is_ptr = false;
+    const fn_ty = qualTypeGetFnProto(ZigClangExpr_getType(callee), &is_ptr);
+
+    const fn_expr = if (is_ptr and fn_ty != null) blk: {
+        if (ZigClangExpr_getStmtClass(callee) == .ImplicitCastExprClass) {
+            const implicit_cast = @ptrCast(*const ZigClangImplicitCastExpr, callee);
+
+            if (ZigClangImplicitCastExpr_getCastKind(implicit_cast) == .FunctionToPointerDecay) {
+                const subexpr = ZigClangImplicitCastExpr_getSubExpr(implicit_cast);
+                if (ZigClangExpr_getStmtClass(subexpr) == .DeclRefExprClass) {
+                    const decl_ref = @ptrCast(*const ZigClangDeclRefExpr, subexpr);
+                    const named_decl = ZigClangDeclRefExpr_getFoundDecl(decl_ref);
+                    if (ZigClangDecl_getKind(@ptrCast(*const ZigClangDecl, named_decl)) == .Function) {
+                        break :blk raw_fn_expr;
+                    }
+                }
+            }
+        }
+        break :blk try transCreateNodeUnwrapNull(rp.c, raw_fn_expr);
+    } else
+        raw_fn_expr;
+    const node = try transCreateNodeFnCall(rp.c, fn_expr);
+
+    const num_args = ZigClangCallExpr_getNumArgs(stmt);
+    const args = ZigClangCallExpr_getArgs(stmt);
+    var i: usize = 0;
+    while (i < num_args) : (i+=1) {
+        if (i != 0) {
+            _ = try appendToken(rp.c, .Comma, ",");
+        }
+        const arg = try transExpr(rp, scope, args[i], .used, .r_value);
+        try node.op.Call.params.push(arg);
+    }
+    node.rtoken = try appendToken(rp.c, .RParen, ")");
+
+    if (fn_ty) |ty| {
+        const canon = ZigClangQualType_getCanonicalType(ZigClangFunctionProtoType_getReturnType(ty));
+        const ret_ty = ZigClangQualType_getTypePtr(canon);
+        if (ZigClangType_isVoidType(ret_ty)) {
+            _ = try appendToken(rp.c, .Semicolon, ";");
+            return &node.base;
+        }
+    }
+    
+    return maybeSuppressResult(rp, scope, result_used, &node.base);
+}
+
+fn qualTypeGetFnProto(qt: ZigClangQualType, is_ptr: *bool) ?*const ZigClangFunctionProtoType {
+    const canon = ZigClangQualType_getCanonicalType(qt);
+    var ty = ZigClangQualType_getTypePtr(canon);
+    is_ptr.* = false;
+
+    if (ZigClangType_getTypeClass(ty) == .Pointer) {
+        is_ptr.* = true;
+        const child_qt = ZigClangType_getPointeeType(ty);
+        ty = ZigClangQualType_getTypePtr(child_qt);
+    }
+    if (ZigClangType_getTypeClass(ty) == .FunctionProto) {
+        return @ptrCast(*const ZigClangFunctionProtoType, ty);
+    }
+    return null;
+}
+
 fn transCPtrCast(
     rp: RestorePoint,
     loc: ZigClangSourceLocation,
@@ -3947,6 +4015,22 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
                 if (it.next().?.id != .RBrace)
                     return error.ParseError;
             },
+            .LParen => {
+                const call_node = try transCreateNodeFnCall(rp.c, node);
+                while (true) {
+                    const arg = try parseCExpr(rp, it, source_loc, scope);
+                    try call_node.op.Call.params.push(arg);
+                    const next = it.next().?;
+                    if (next.id == .Comma)
+                        _ = try appendToken(rp.c, .Comma, ",")
+                    else if (next.id == .RParen)
+                        break
+                    else
+                        return error.ParseError;
+                }
+                call_node.rtoken = try appendToken(rp.c, .RParen, ")");
+                node = &call_node.base;
+            },
             else => {
                 _ = it.prev();
                 return node;
test/translate_c.zig
@@ -702,6 +702,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
+    cases.addC_both("function call",
+        \\static void bar(void) { }
+        \\void foo(int *(baz)(void)) {
+        \\    bar();
+        \\    baz();
+        \\}
+    , &[_][]const u8{
+        \\pub fn bar() void {}
+        \\pub export fn foo(baz: ?extern fn () [*c]c_int) void {
+        \\    bar();
+        \\    _ = baz.?();
+        \\}
+    });
+
     /////////////// Cases that pass for only stage2 ////////////////
 
     cases.add_2("Parameterless function prototypes",
@@ -1538,6 +1552,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const ACCESS = array[2];
     });
 
+    cases.add_2("macro call",
+        \\#define CALL(arg) bar(arg)
+    , &[_][]const u8{
+        \\pub inline fn CALL(arg: var) @TypeOf(bar(arg)) {
+        \\    return bar(arg);
+        \\}
+    });
+
     /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
 
     cases.addAllowWarnings("simple data types",
@@ -1728,24 +1750,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.addC("function call",
-        \\static void bar(void) { }
-        \\static int baz(void) { return 0; }
-        \\void foo(void) {
-        \\    bar();
-        \\    baz();
-        \\}
-    , &[_][]const u8{
-        \\pub fn bar() void {}
-        \\pub fn baz() c_int {
-        \\    return 0;
-        \\}
-        \\pub export fn foo() void {
-        \\    bar();
-        \\    _ = baz();
-        \\}
-    });
-
     cases.addC("sizeof",
         \\#include <stddef.h>
         \\size_t size_of(void) {