From c4dfabf4dcfc29f48356e3c5f762f1ca2c21f088 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 14 Feb 2021 15:35:51 +0200 Subject: [PATCH] translate-c: render macro functions, use cast type as return type Closes #8004 --- src/translate_c.zig | 8 +- src/translate_c/ast.zig | 280 ++++++++++++++++++++++++++-------------- 2 files changed, 191 insertions(+), 97 deletions(-) diff --git a/src/translate_c.zig b/src/translate_c.zig index abb4fff7f4..6fa3110118 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -4099,14 +4099,18 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { const br = blk_last.castTag(.break_val).?; break :blk br.data.val; } else expr; - const typeof = try Tag.typeof.create(c.arena, typeof_arg); + const return_type = if (typeof_arg.castTag(.std_meta_cast)) |some| + some.data.lhs + else + try Tag.typeof.create(c.arena, typeof_arg); + const return_expr = try Tag.@"return".create(c.arena, expr); try block_scope.statements.append(return_expr); const fn_decl = try Tag.pub_inline_fn.create(c.arena, .{ .name = m.name, .params = try c.arena.dupe(ast.Payload.Param, fn_params.items), - .return_type = typeof, + .return_type = return_type, .body = try block_scope.complete(c), }); _ = try c.global_scope.macro_table.put(m.name, fn_decl); diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 6d08688de4..2c3b9f29fe 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -615,9 +615,15 @@ pub fn render(gpa: *Allocator, nodes: []const Node) !std.zig.ast.Tree { defer ctx.extra_data.deinit(gpa); defer ctx.tokens.deinit(gpa); - // Estimate that each top level node has 25 child nodes. - const estimated_node_count = nodes.len * 25; + // Estimate that each top level node has 10 child nodes. + const estimated_node_count = nodes.len * 10; try ctx.nodes.ensureCapacity(gpa, estimated_node_count); + // Estimate that each each node has 2 tokens. + const estimated_tokens_count = estimated_node_count * 2; + try ctx.tokens.ensureCapacity(gpa, estimated_tokens_count); + // Estimate that each each token is 3 bytes long. + const estimated_buf_len = estimated_tokens_count * 3; + try ctx.buf.ensureCapacity(estimated_buf_len); ctx.nodes.appendAssumeCapacity(.{ .tag = .root, @@ -776,74 +782,47 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { .null_literal => return c.addNode(.{ .tag = .null_literal, .main_token = try c.addToken(.keyword_null, "null"), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }), .undefined_literal => return c.addNode(.{ .tag = .undefined_literal, .main_token = try c.addToken(.keyword_undefined, "undefined"), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }), .true_literal => return c.addNode(.{ .tag = .true_literal, .main_token = try c.addToken(.keyword_true, "true"), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }), .false_literal => return c.addNode(.{ .tag = .false_literal, .main_token = try c.addToken(.keyword_false, "false"), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }), .zero_literal => return c.addNode(.{ .tag = .integer_literal, .main_token = try c.addToken(.integer_literal, "0"), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }), .one_literal => return c.addNode(.{ .tag = .integer_literal, .main_token = try c.addToken(.integer_literal, "1"), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }), .void_type => return c.addNode(.{ .tag = .identifier, .main_token = try c.addToken(.identifier, "void"), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }), .@"anytype" => return c.addNode(.{ .tag = .@"anytype", .main_token = try c.addToken(.keyword_anytype, "anytype"), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }), .noreturn_type => return c.addNode(.{ .tag = .identifier, .main_token = try c.addToken(.identifier, "noreturn"), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }), .@"continue" => return c.addNode(.{ .tag = .@"continue", @@ -853,6 +832,14 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { .rhs = undefined, }, }), + .return_void => return c.addNode(.{ + .tag = .@"return", + .main_token = try c.addToken(.keyword_return, "return"), + .data = .{ + .lhs = 0, + .rhs = undefined, + }, + }), .@"break" => { const payload = node.castTag(.@"break").?.data; const tok = try c.addToken(.keyword_break, "break"); @@ -885,15 +872,23 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { }, }); }, + .@"return" => { + const payload = node.castTag(.@"return").?.data; + return c.addNode(.{ + .tag = .@"return", + .main_token = try c.addToken(.keyword_return, "return"), + .data = .{ + .lhs = try renderNode(c, payload), + .rhs = undefined, + }, + }); + }, .type => { const payload = node.castTag(.type).?.data; return c.addNode(.{ .tag = .identifier, .main_token = try c.addToken(.identifier, payload), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }); }, .log2_int_type => { @@ -901,10 +896,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { return c.addNode(.{ .tag = .identifier, .main_token = try c.addTokenFmt(.identifier, "u{d}", .{payload}), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }); }, .identifier => { @@ -912,10 +904,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { return c.addNode(.{ .tag = .identifier, .main_token = try c.addIdentifier(payload), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }); }, .float_literal => { @@ -923,10 +912,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { return c.addNode(.{ .tag = .float_literal, .main_token = try c.addToken(.float_literal, payload), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }); }, .integer_literal => { @@ -934,10 +920,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { return c.addNode(.{ .tag = .integer_literal, .main_token = try c.addToken(.integer_literal, payload), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }); }, .string_literal => { @@ -945,10 +928,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { return c.addNode(.{ .tag = .identifier, .main_token = try c.addToken(.string_literal, payload), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }); }, .char_literal => { @@ -956,10 +936,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { return c.addNode(.{ .tag = .identifier, .main_token = try c.addToken(.string_literal, payload), - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }); }, .fail_decl => { @@ -976,10 +953,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { const err_msg = try c.addNode(.{ .tag = .string_literal, .main_token = err_msg_tok, - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }); _ = try c.addToken(.r_paren, ")"); const compile_error = try c.addNode(.{ @@ -1130,6 +1104,31 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { }, }); }, + .c_pointer, .single_pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", node.ptr_otherwise).data; + + const asterisk = if (node.tag() == .single_pointer) + try c.addToken(.asterisk, "*") + else blk: { + _ = try c.addToken(.l_bracket, "["); + const res = try c.addToken(.asterisk, "*"); + _ = try c.addIdentifier("c"); + _ = try c.addToken(.r_bracket, "]"); + break :blk res; + }; + if (payload.is_const) _ = try c.addToken(.keyword_const, "const"); + if (payload.is_volatile) _ = try c.addToken(.keyword_volatile, "volatile"); + const elem_type = try renderNode(c, payload.elem_type); + + return c.addNode(.{ + .tag = .ptr_type_aligned, + .main_token = asterisk, + .data = .{ + .lhs = 0, + .rhs = elem_type, + }, + }); + }, .add => return renderBinOp(c, node, .add, .plus, "+"), .add_assign => return renderBinOp(c, node, .assign_add, .plus_equal, "+="), .add_wrap => return renderBinOp(c, node, .add_wrap, .plus_percent, "+%"), @@ -1229,6 +1228,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { }); }, .func => return renderFunc(c, node), + .pub_inline_fn => return renderMacroFunc(c, node), .discard => { const payload = node.castTag(.discard).?.data; const lhs = try c.addNode(.{ @@ -1300,6 +1300,9 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { .type, .array_access, .align_cast, + .optional_type, + .c_pointer, + .single_pointer, => { // no grouping needed return renderNode(c, node); @@ -1310,7 +1313,6 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { .bit_not, .opaque_literal, .not, - .optional_type, .address_of, .unwrap, .deref, @@ -1350,8 +1352,6 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { .tuple, .container_init, .block, - .c_pointer, - .single_pointer, .array_type, => return c.addNode(.{ .tag = .grouped_expression, @@ -1439,10 +1439,7 @@ fn renderStdImport(c: *Context, first: []const u8, second: []const u8) !NodeInde const std_node = try c.addNode(.{ .tag = .string_literal, .main_token = std_tok, - .data = .{ - .lhs = undefined, - .rhs = undefined, - }, + .data = undefined, }); _ = try c.addToken(.r_paren, ")"); @@ -1498,21 +1495,23 @@ fn renderCall(c: *Context, lhs: NodeIndex, args: []const Node) !NodeIndex { }); }, else => blk: { - const start = @intCast(u32, c.extra_data.items.len); - const end = @intCast(u32, start + args.len); - try c.extra_data.ensureCapacity(c.gpa, end + 2); // + 2 for span start + end + var rendered = try c.gpa.alloc(NodeIndex, args.len); + defer c.gpa.free(rendered); + for (args) |arg, i| { if (i != 0) _ = try c.addToken(.comma, ","); - c.extra_data.appendAssumeCapacity(try renderNode(c, arg)); + rendered[i] = try renderNode(c, arg); } - c.extra_data.appendAssumeCapacity(start); - c.extra_data.appendAssumeCapacity(end); + const span = try c.listToSpan(rendered); break :blk try c.addNode(.{ - .tag = .call_comma, + .tag = .call, .main_token = lparen, .data = .{ .lhs = lhs, - .rhs = end + 2, + .rhs = try c.addExtra(std.zig.ast.Node.SubRange{ + .start = span.start, + .end = span.end, + }), }, }); }, @@ -1653,20 +1652,20 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex { var span: NodeSubRange = undefined; if (payload.params.len > 1) { - var params = std.ArrayList(NodeIndex).init(c.gpa); - defer params.deinit(); + var params = try c.gpa.alloc(NodeIndex, payload.params.len); + defer c.gpa.free(params); - try params.append(first); - for (payload.params[1..]) |param| { + params[0] = first; + for (payload.params[1..]) |param, i| { _ = try c.addToken(.comma, ","); if (param.is_noalias) _ = try c.addToken(.keyword_noalias, "noalias"); if (param.name) |some| { _ = try c.addIdentifier(some); _ = try c.addToken(.colon, ":"); } - try params.append(try renderNode(c, param.type)); + params[i + 1] = try renderNode(c, param.type); } - span = try c.listToSpan(params.items); + span = try c.listToSpan(params); } if (payload.is_var_args) { if (payload.params.len != 0) _ = try c.addToken(.comma, ","); @@ -1674,8 +1673,6 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex { } _ = try c.addToken(.r_paren, ")"); - const return_type_expr = try renderNode(c, payload.return_type); - const align_expr = if (payload.alignment) |some| blk: { _ = try c.addToken(.keyword_align, "align"); _ = try c.addToken(.l_paren, "("); @@ -1701,18 +1698,20 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex { } else 0; const callconv_expr = if (payload.explicit_callconv) |some| blk: { - _ = try c.addToken(.keyword_linksection, "callconv"); + _ = try c.addToken(.keyword_callconv, "callconv"); _ = try c.addToken(.l_paren, "("); _ = try c.addToken(.period, "."); const res = try c.addNode(.{ .tag = .enum_literal, - .main_token = try c.addTokenFmt(.string_literal, "{}", .{some}), + .main_token = try c.addTokenFmt(.identifier, "{}", .{some}), .data = .{ .lhs = undefined, .rhs = undefined }, }); _ = try c.addToken(.r_paren, ")"); break :blk res; } else 0; + const return_type_expr = try renderNode(c, payload.return_type); + const fn_proto = try blk: { if (align_expr == 0 and section_expr == 0 and callconv_expr == 0) { if (payload.params.len < 2) @@ -1784,3 +1783,94 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex { }, }); } + +fn renderMacroFunc(c: *Context, node: Node) !NodeIndex { + const payload = node.castTag(.pub_inline_fn).?.data; + _ = try c.addToken(.keyword_pub, "pub"); + const fn_token = try c.addToken(.keyword_fn, "fn"); + _ = try c.addIdentifier(payload.name); + + _ = try c.addToken(.l_paren, "("); + const first = if (payload.params.len != 0) blk: { + const param = payload.params[0]; + if (param.is_noalias) _ = try c.addToken(.keyword_noalias, "noalias"); + if (param.name) |some| { + _ = try c.addIdentifier(some); + _ = try c.addToken(.colon, ":"); + } + break :blk try renderNode(c, param.type); + } else 0; + + var span: NodeSubRange = undefined; + if (payload.params.len > 1) { + var params = try c.gpa.alloc(NodeIndex, payload.params.len); + defer c.gpa.free(params); + + params[0] = first; + for (payload.params[1..]) |param, i| { + _ = try c.addToken(.comma, ","); + if (param.is_noalias) _ = try c.addToken(.keyword_noalias, "noalias"); + if (param.name) |some| { + _ = try c.addIdentifier(some); + _ = try c.addToken(.colon, ":"); + } + params[i + 1] = try renderNode(c, param.type); + } + span = try c.listToSpan(params); + } + _ = try c.addToken(.r_paren, ")"); + + const callconv_expr = blk: { + _ = try c.addToken(.keyword_callconv, "callconv"); + _ = try c.addToken(.l_paren, "("); + _ = try c.addToken(.period, "."); + const res = try c.addNode(.{ + .tag = .enum_literal, + .main_token = try c.addToken(.identifier, "Inline"), + .data = .{ .lhs = undefined, .rhs = undefined }, + }); + _ = try c.addToken(.r_paren, ")"); + break :blk res; + }; + const return_type_expr = try renderNode(c, payload.return_type); + + const fn_proto = try blk: { + if (payload.params.len < 2) + break :blk c.addNode(.{ + .tag = .fn_proto_one, + .main_token = fn_token, + .data = .{ + .lhs = try c.addExtra(std.zig.ast.Node.FnProtoOne{ + .param = first, + .align_expr = 0, + .section_expr = 0, + .callconv_expr = callconv_expr, + }), + .rhs = return_type_expr, + }, + }) + else + break :blk c.addNode(.{ + .tag = .fn_proto, + .main_token = fn_token, + .data = .{ + .lhs = try c.addExtra(std.zig.ast.Node.FnProto{ + .params_start = span.start, + .params_end = span.end, + .align_expr = 0, + .section_expr = 0, + .callconv_expr = callconv_expr, + }), + .rhs = return_type_expr, + }, + }); + }; + return c.addNode(.{ + .tag = .fn_decl, + .main_token = fn_token, + .data = .{ + .lhs = fn_proto, + .rhs = try renderNode(c, payload.body), + }, + }); +}