From ed2a19dcecf5470ae2529e0fc7f86bf89d532162 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sun, 15 Dec 2019 21:32:30 +0200 Subject: [PATCH] translate-c-2 macro cast --- src-self-hosted/c_tokenizer.zig | 5 + src-self-hosted/translate_c.zig | 173 +++++++++++++++++++++++++++++--- test/translate_c.zig | 6 ++ 3 files changed, 169 insertions(+), 15 deletions(-) diff --git a/src-self-hosted/c_tokenizer.zig b/src-self-hosted/c_tokenizer.zig index 704cd268f7..426ff61fe6 100644 --- a/src-self-hosted/c_tokenizer.zig +++ b/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, } }, diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index f1232d65da..3934aca275 100644 --- a/src-self-hosted/translate_c.zig +++ b/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; diff --git a/test/translate_c.zig b/test/translate_c.zig index 201ab9993a..163323d56c 100644 --- a/test/translate_c.zig +++ b/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",