Commit ed2a19dcec

Vexu <git@vexu.eu>
2019-12-15 20:32:30
translate-c-2 macro cast
1 parent 57170f9
Changed files (3)
src-self-hosted/c_tokenizer.zig
@@ -25,6 +25,7 @@ pub const CToken = struct {
         Tilde,
         Shl,
         Lt,
+        Comma,
     };
 
     pub const NumLitSuffix = enum {
@@ -191,6 +192,10 @@ fn next(chars: [*]const u8, i: *usize) !CToken {
                         result.id = .Tilde;
                         return result;
                     },
+                    ',' => {
+                        result.id = .Comma;
+                        return result;
+                    },
                     else => return error.TokenizingFailed,
                 }
             },
src-self-hosted/translate_c.zig
@@ -2039,7 +2039,7 @@ fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node {
     _ = try appendToken(c, .Period, ".");
     const qm = try appendToken(c, .QuestionMark, "?");
     const node = try c.a().create(ast.Node.SuffixOp);
-    node.* = ast.Node.SuffixOp{
+    node.* = .{
         .op = .UnwrapOptional,
         .lhs = .{ .node = wrapped },
         .rtoken = qm,
@@ -2047,6 +2047,39 @@ fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node {
     return &node.base;
 }
 
+fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node {
+    const node = try c.a().create(ast.Node.EnumLiteral);
+    node.* = .{
+        .dot = try appendToken(c, .Period, "."),
+        .name = try appendIdentifier(c, name),
+    };
+    return &node.base;
+}
+
+fn transCreateNodeIf(c: *Context) !*ast.Node.If {
+    const if_tok = try appendToken(c, .Keyword_if, "if");
+    _ = try appendToken(c, .LParen, "(");
+    const node = try c.a().create(ast.Node.If);
+    node.* = .{
+        .if_token = if_tok,
+        .condition = undefined,
+        .payload = null,
+        .body = undefined,
+        .@"else" = null,
+    };
+    return node;
+}
+
+fn transCreateNodeElse(c: *Context) !*ast.Node.Else {
+    const node = try c.a().create(ast.Node.Else);
+    node.* = .{
+        .else_token = try appendToken(c, .Keyword_else, "else"),
+        .payload = null,
+        .body = undefined,
+    };
+    return node;
+}
+
 const RestorePoint = struct {
     c: *Context,
     token_index: ast.TokenIndex,
@@ -2722,26 +2755,102 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc:
             };
             return &node.base;
         },
-        .Minus => {
-            const node = try transCreateNodePrefixOp(
-                rp.c,
-                .Negation,
-                .Minus,
-                "-",
-            );
-            node.rhs = try parseCNumLit(rp, it.next().?, source_loc);
-            return &node.base;
-        },
         .NumLitInt, .NumLitFloat => {
             return parseCNumLit(rp, tok, source_loc);
         },
         .Identifier => return transCreateNodeIdentifier(rp.c, tok.bytes),
         .LParen => {
-            _ = try appendToken(rp.c, .LParen, "(");
             const inner_node = try parseCExpr(rp, it, source_loc);
-            _ = try appendToken(rp.c, .RParen, ")");
 
-            return inner_node; // TODO
+            // hack to get zig fmt to render a comma in builtin calls
+            _ = try appendToken(rp.c, .Comma, ",");
+
+            if (it.peek().?.id == .RParen) {
+                _ = it.next();
+                return inner_node;
+            }
+
+            const node_to_cast = try parseCExpr(rp, it, source_loc);
+
+            if (it.next().?.id != .RParen) {
+                return revertAndWarn(
+                    rp,
+                    error.ParseError,
+                    source_loc,
+                    "unable to translate C expr",
+                    .{},
+                );
+            }
+
+            //if (@typeId(@TypeOf(x)) == .Pointer)
+            //    @ptrCast(dest, x)
+            //else if (@typeId(@TypeOf(x)) == .Integer)
+            //    @intToPtr(dest, x)
+            //else
+            //    @as(dest, x)
+
+            const if_1 = try transCreateNodeIf(rp.c);
+            const type_id_1 = try transCreateNodeBuiltinFnCall(rp.c, "@typeId");
+            const type_of_1 = try transCreateNodeBuiltinFnCall(rp.c, "@TypeOf");
+            try type_id_1.params.push(&type_of_1.base);
+            try type_of_1.params.push(node_to_cast);
+            type_of_1.rparen_token = try appendToken(rp.c, .LParen, ")");
+            type_id_1.rparen_token = try appendToken(rp.c, .LParen, ")");
+
+            const cmp_1 = try rp.c.a().create(ast.Node.InfixOp);
+            cmp_1.* = .{
+                .op_token = try appendToken(rp.c, .EqualEqual, "=="),
+                .lhs = &type_id_1.base,
+                .op = .EqualEqual,
+                .rhs = try transCreateNodeEnumLiteral(rp.c, "Pointer"),
+            };
+            if_1.condition = &cmp_1.base;
+            _ = try appendToken(rp.c, .LParen, ")");
+
+            const ptr_cast = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast");
+            try ptr_cast.params.push(inner_node);
+            try ptr_cast.params.push(node_to_cast);
+            ptr_cast.rparen_token = try appendToken(rp.c, .LParen, ")");
+            if_1.body = &ptr_cast.base;
+
+            const else_1 = try transCreateNodeElse(rp.c);
+            if_1.@"else" = else_1;
+
+            const if_2 = try transCreateNodeIf(rp.c);
+            const type_id_2 = try transCreateNodeBuiltinFnCall(rp.c, "@typeId");
+            const type_of_2 = try transCreateNodeBuiltinFnCall(rp.c, "@TypeOf");
+            try type_id_2.params.push(&type_of_2.base);
+            try type_of_2.params.push(node_to_cast);
+            type_of_2.rparen_token = try appendToken(rp.c, .LParen, ")");
+            type_id_2.rparen_token = try appendToken(rp.c, .LParen, ")");
+
+            const cmp_2 = try rp.c.a().create(ast.Node.InfixOp);
+            cmp_2.* = .{
+                .op_token = try appendToken(rp.c, .EqualEqual, "=="),
+                .lhs = &type_id_2.base,
+                .op = .EqualEqual,
+                .rhs = try transCreateNodeEnumLiteral(rp.c, "Int"),
+            };
+            if_2.condition = &cmp_2.base;
+            else_1.body = &if_2.base;
+            _ = try appendToken(rp.c, .LParen, ")");
+
+            const int_to_ptr = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr");
+            try int_to_ptr.params.push(inner_node);
+            try int_to_ptr.params.push(node_to_cast);
+            int_to_ptr.rparen_token = try appendToken(rp.c, .LParen, ")");
+            if_2.body = &int_to_ptr.base;
+
+            const else_2 = try transCreateNodeElse(rp.c);
+            if_2.@"else" = else_2;
+
+            const as = try transCreateNodeBuiltinFnCall(rp.c, "@as");
+            try as.params.push(inner_node);
+            try as.params.push(node_to_cast);
+            as.rparen_token = try appendToken(rp.c, .LParen, ")");
+            else_2.body = &as.base;
+
+            return &if_1.base;
         },
         else => return revertAndWarn(
             rp,
@@ -2780,6 +2889,30 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
                 };
                 node = &access_node.base;
             },
+            .Asterisk => {
+                if (it.peek().?.id == .RParen) {
+                    // type *)
+
+                    // hack to get zig fmt to render a comma in builtin calls
+                    _ = try appendToken(rp.c, .Comma, ",");
+
+                    const ptr = try transCreateNodePtrType(rp.c, false, false, .Identifier);
+                    ptr.rhs = node;
+                    return &ptr.base;
+                } else {
+                    // expr * expr
+                    const op_token = try appendToken(rp.c, .Asterisk, "*");
+                    const rhs = try parseCPrimaryExpr(rp, it, source_loc);
+                    const bitshift_node = try rp.c.a().create(ast.Node.InfixOp);
+                    bitshift_node.* = .{
+                        .op_token = op_token,
+                        .lhs = node,
+                        .op = .BitShiftLeft,
+                        .rhs = rhs,
+                    };
+                    node = &bitshift_node.base;
+                }
+            },
             .Shl => {
                 const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<");
                 const rhs = try parseCPrimaryExpr(rp, it, source_loc);
@@ -2819,6 +2952,16 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
             node.rhs = try parseCPrefixOpExpr(rp, it, source_loc);
             return &node.base;
         },
+        .Asterisk => {
+            const prefix_op_expr = try parseCPrefixOpExpr(rp, it, source_loc);
+            const node = try rp.c.a().create(ast.Node.SuffixOp);
+            node.* = .{
+                .lhs = .{ .node = prefix_op_expr },
+                .op = .Deref,
+                .rtoken = try appendToken(rp.c, .PeriodAsterisk, ".*"),
+            };
+            return &node.base;
+        },
         else => {
             _ = it.prev();
             return try parseCSuffixOpExpr(rp, it, source_loc);
@@ -2833,7 +2976,7 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 {
 
 fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node {
     const init = ref.cast(ast.Node.VarDecl).?.init_node.?;
-    const name = if (init.cast(ast.Node.Identifier)) |id| 
+    const name = if (init.cast(ast.Node.Identifier)) |id|
         tokenSlice(c, id.token)
     else
         return null;
test/translate_c.zig
@@ -397,6 +397,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const OpenGLProcs = union_OpenGLProcs;
     });
 
+    cases.add_2("macro pointer cast",
+        \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
+    , &[_][]const u8{
+        \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
+    });
+
     /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
 
     cases.add_both("typedef of function in struct field",