From d7460db044ef6649486a27f2b9ebb1de9e2ce2b0 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 13 Feb 2021 17:57:52 +0200 Subject: [PATCH] translate-c: render a bunch of simple nodes and calls --- lib/std/zig/render.zig | 9 +- src/translate_c.zig | 5 +- src/translate_c/ast.zig | 297 +++++++++++++++++++++++++++++++++++----- 3 files changed, 270 insertions(+), 41 deletions(-) diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 2d9c2ae9a9..6fd091d32c 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -550,14 +550,11 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac .builtin_call_two, .builtin_call_two_comma => { if (datas[node].lhs == 0) { - const params = [_]ast.Node.Index{}; - return renderBuiltinCall(ais, tree, main_tokens[node], ¶ms, space); + return renderBuiltinCall(ais, tree, main_tokens[node], &.{}, space); } else if (datas[node].rhs == 0) { - const params = [_]ast.Node.Index{datas[node].lhs}; - return renderBuiltinCall(ais, tree, main_tokens[node], ¶ms, space); + return renderBuiltinCall(ais, tree, main_tokens[node], &.{datas[node].lhs}, space); } else { - const params = [_]ast.Node.Index{ datas[node].lhs, datas[node].rhs }; - return renderBuiltinCall(ais, tree, main_tokens[node], ¶ms, space); + return renderBuiltinCall(ais, tree, main_tokens[node], &.{ datas[node].lhs, datas[node].rhs }, space); } }, .builtin_call, .builtin_call_comma => { diff --git a/src/translate_c.zig b/src/translate_c.zig index c7a30ff919..9b80582ab5 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -3054,6 +3054,7 @@ fn maybeSuppressResult( fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void { _ = try c.global_scope.sym_table.put(name, decl_node); + try c.global_scope.nodes.append(decl_node); } /// Translate a qual type for a variable with an initializer. The initializer @@ -3903,10 +3904,10 @@ fn fail( pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, comptime format: []const u8, args: anytype) Error!void { // location // pub const name = @compileError(msg); + const fail_msg = try std.fmt.allocPrint(c.arena, format, args); + try c.global_scope.nodes.append(try Tag.fail_decl.create(c.arena, .{ .actual = name, .mangled = fail_msg })); const location_comment = try std.fmt.allocPrint(c.arena, "// {s}", .{c.locStr(loc)}); try c.global_scope.nodes.append(try Tag.warning.create(c.arena, location_comment)); - const fail_msg = try std.fmt.allocPrint(c.arena, format, args); - try c.global_scope.nodes.append(try Tag.fail_decl.create(c.arena, fail_msg)); } pub fn freeErrors(errors: []ClangErrMsg) void { diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 8e18b55c04..4e91f13757 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -52,7 +52,6 @@ pub const Node = extern union { var_decl, func, warning, - failed_decl, /// All enums are non-exhaustive @"enum", @"struct", @@ -339,9 +338,7 @@ pub const Node = extern union { .char_literal, .identifier, .warning, - .failed_decl, .type, - .fail_decl, => Payload.Value, .@"if" => Payload.If, .@"while" => Payload.While, @@ -359,7 +356,7 @@ pub const Node = extern union { .block => Payload.Block, .c_pointer, .single_pointer => Payload.Pointer, .array_type => Payload.Array, - .arg_redecl, .alias => Payload.ArgRedecl, + .arg_redecl, .alias, .fail_decl => Payload.ArgRedecl, .log2_int_type => Payload.Log2IntType, .typedef, .pub_typedef, .var_simple, .pub_var_simple => Payload.SimpleVarDecl, .enum_redecl => Payload.EnumRedecl, @@ -695,7 +692,7 @@ const Context = struct { extra_data: std.ArrayListUnmanaged(std.zig.ast.Node.Index) = .{}, tokens: std.zig.ast.TokenList = .{}, - fn appendTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex { + fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex { const start_index = c.buf.items.len; try c.buf.writer().print(format ++ " ", args); @@ -707,13 +704,13 @@ const Context = struct { return @intCast(u32, c.tokens.len - 1); } - fn appendToken(c: *Context, tag: TokenTag, bytes: []const u8) Allocator.Error!TokenIndex { - std.debug.assert(tag != .identifier); // use appendIdentifier - return appendTokenFmt(c, tag, "{s}", .{bytes}); + fn addToken(c: *Context, tag: TokenTag, bytes: []const u8) Allocator.Error!TokenIndex { + std.debug.assert(tag != .identifier); // use addIdentifier + return addTokenFmt(c, tag, "{s}", .{bytes}); } - fn appendIdentifier(c: *Context, bytes: []const u8) Allocator.Error!TokenIndex { - return appendTokenFmt(c, .identifier, "{s}", .{std.zig.fmtId(bytes)}); + fn addIdentifier(c: *Context, bytes: []const u8) Allocator.Error!TokenIndex { + return addTokenFmt(c, .identifier, "{s}", .{std.zig.fmtId(bytes)}); } fn listToSpan(c: *Context, list: []const NodeIndex) Allocator.Error!NodeSubRange { @@ -724,14 +721,14 @@ const Context = struct { }; } - fn appendNode(c: *Context, elem: std.zig.ast.NodeList.Elem) Allocator.Error!NodeIndex { + fn addNode(c: *Context, elem: std.zig.ast.NodeList.Elem) Allocator.Error!NodeIndex { const result = @intCast(NodeIndex, c.nodes.len); try c.nodes.append(c.gpa, elem); return result; } }; -fn renderNodes(c: *Context, nodes: []const Node) !NodeSubRange { +fn renderNodes(c: *Context, nodes: []const Node) Allocator.Error!NodeSubRange { var result = std.ArrayList(NodeIndex).init(c.gpa); defer result.deinit(); @@ -744,7 +741,7 @@ fn renderNodes(c: *Context, nodes: []const Node) !NodeSubRange { return try c.listToSpan(result.items); } -fn renderNode(c: *Context, node: Node) !NodeIndex { +fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { switch (node.tag()) { .warning => { const payload = node.castTag(.warning).?; @@ -754,12 +751,12 @@ fn renderNode(c: *Context, node: Node) !NodeIndex { }, .usingnamespace_builtins => { // pub usingnamespace @import("std").c.builtins; - _ = try c.appendToken(.keyword_pub, "pub"); - const usingnamespace_token = try c.appendToken(.keyword_usingnamespace, "usingnamespace"); + _ = try c.addToken(.keyword_pub, "pub"); + const usingnamespace_token = try c.addToken(.keyword_usingnamespace, "usingnamespace"); const import_node = try renderStdImport(c, "c", "builtins"); - _ = try c.appendToken(.semicolon, ";"); + _ = try c.addToken(.semicolon, ";"); - return c.appendNode(.{ + return c.addNode(.{ .tag = .@"usingnamespace", .main_token = usingnamespace_token, .data = .{ @@ -768,6 +765,196 @@ fn renderNode(c: *Context, node: Node) !NodeIndex { }, }); }, + .std_math_Log2Int => { + const payload = node.castTag(.std_math_Log2Int).?; + const import_node = try renderStdImport(c, "math", "Log2Int"); + return renderCall(c, import_node, &.{payload.data}); + }, + .std_meta_cast => { + const payload = node.castTag(.std_meta_cast).?; + const import_node = try renderStdImport(c, "meta", "cast"); + return renderCall(c, import_node, &.{ payload.data.lhs, payload.data.rhs }); + }, + .std_meta_sizeof => { + const payload = node.castTag(.std_meta_sizeof).?; + const import_node = try renderStdImport(c, "meta", "sizeof"); + return renderCall(c, import_node, &.{payload.data}); + }, + .std_mem_zeroes => { + const payload = node.castTag(.std_mem_zeroes).?; + const import_node = try renderStdImport(c, "mem", "zeroes"); + return renderCall(c, import_node, &.{payload.data}); + }, + .std_mem_zeroinit => { + const payload = node.castTag(.std_mem_zeroinit).?; + const import_node = try renderStdImport(c, "mem", "zeroInit"); + return renderCall(c, import_node, &.{ payload.data.lhs, payload.data.rhs }); + }, + .call => { + const payload = node.castTag(.call).?; + const lhs = try renderNode(c, payload.data.lhs); + return renderCall(c, lhs, payload.data.args); + }, + .null_literal => return c.addNode(.{ + .tag = .null_literal, + .main_token = try c.addToken(.keyword_null, "null"), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + .undefined_literal => return c.addNode(.{ + .tag = .undefined_literal, + .main_token = try c.addToken(.keyword_undefined, "undefined"), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + .true_literal => return c.addNode(.{ + .tag = .true_literal, + .main_token = try c.addToken(.keyword_true, "true"), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + .false_literal => return c.addNode(.{ + .tag = .false_literal, + .main_token = try c.addToken(.keyword_false, "false"), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + .zero_literal => return c.addNode(.{ + .tag = .integer_literal, + .main_token = try c.addToken(.integer_literal, "0"), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + .one_literal => return c.addNode(.{ + .tag = .integer_literal, + .main_token = try c.addToken(.integer_literal, "1"), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + .void_type => return c.addNode(.{ + .tag = .identifier, + .main_token = try c.addToken(.identifier, "void"), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + .@"anytype" => return try c.addNode(.{ + .tag = .@"anytype", + .main_token = try c.addToken(.keyword_anytype, "anytype"), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }), + .type => { + const payload = node.castTag(.type).?; + return c.addNode(.{ + .tag = .identifier, + .main_token = try c.addToken(.identifier, payload.data), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }); + }, + .identifier => { + const payload = node.castTag(.identifier).?; + return c.addNode(.{ + .tag = .identifier, + .main_token = try c.addIdentifier(payload.data), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }); + }, + .number_literal => { + const payload = node.castTag(.number_literal).?; + return c.addNode(.{ + .tag = .identifier, + // might be integer or float, but it doesn't matter for rendering + .main_token = try c.addToken(.integer_literal, payload.data), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }); + }, + .string_literal => { + const payload = node.castTag(.string_literal).?; + return c.addNode(.{ + .tag = .identifier, + .main_token = try c.addToken(.char_literal, payload.data), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }); + }, + .char_literal => { + const payload = node.castTag(.char_literal).?; + return c.addNode(.{ + .tag = .identifier, + .main_token = try c.addToken(.string_literal, payload.data), + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }); + }, + .fail_decl => { + const payload = node.castTag(.fail_decl).?; + // pub const name = @compileError(msg); + _ = try c.addToken(.keyword_pub, "pub"); + const const_kw = try c.addToken(.keyword_const, "const"); + _ = try c.addIdentifier(payload.data.actual); + _ = try c.addToken(.equal, "="); + + + const compile_error_tok = try c.addToken(.builtin, "@compileError"); + _ = try c.addToken(.l_paren, "("); + const err_msg_tok = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(payload.data.mangled)}); + const err_msg = try c.addNode(.{ + .tag = .string_literal, + .main_token = err_msg_tok, + .data = .{ + .lhs = undefined, + .rhs = undefined, + }, + }); + _ = try c.addToken(.r_paren, ")"); + const compile_error = try c.addNode(.{ + .tag = .builtin_call_two, + .main_token = compile_error_tok, + .data = .{ + .lhs = err_msg, + .rhs = 0, + }, + }); + _ = try c.addToken(.semicolon, ";"); + + return c.addNode(.{ + .tag = .simple_var_decl, + .main_token = const_kw, + .data = .{ + .lhs = 0, + .rhs = compile_error, + } + }); + }, else => { try c.buf.writer().print("// TODO renderNode {}\n", .{node.tag()}); return @as(u32, 0); // error: integer value 0 cannot be coerced to type 'std.mem.Allocator.Error!u32' @@ -776,22 +963,20 @@ fn renderNode(c: *Context, node: Node) !NodeIndex { } fn renderStdImport(c: *Context, first: []const u8, second: []const u8) !NodeIndex { - const import_tok = try c.appendToken(.builtin, "@import"); - _ = try c.appendToken(.l_paren, "("); - - const std_tok = try c.appendToken(.string_literal, "\"std\""); - const std_node = try c.appendNode(.{ + const import_tok = try c.addToken(.builtin, "@import"); + _ = try c.addToken(.l_paren, "("); + const std_tok = try c.addToken(.string_literal, "\"std\""); + const std_node = try c.addNode(.{ .tag = .string_literal, .main_token = std_tok, .data = .{ - .lhs = std_tok, - .rhs = std_tok, + .lhs = undefined, + .rhs = undefined, }, }); + _ = try c.addToken(.r_paren, ")"); - _ = try c.appendToken(.r_paren, ")"); - - const import_node = try c.appendNode(.{ + const import_node = try c.addNode(.{ .tag = .builtin_call_two, .main_token = import_tok, .data = .{ @@ -801,21 +986,67 @@ fn renderStdImport(c: *Context, first: []const u8, second: []const u8) !NodeInde }); var access_chain = import_node; - access_chain = try c.appendNode(.{ + access_chain = try c.addNode(.{ .tag = .field_access, - .main_token = try c.appendToken(.period, "."), + .main_token = try c.addToken(.period, "."), .data = .{ .lhs = access_chain, - .rhs = try c.appendIdentifier(first), + .rhs = try c.addIdentifier(first), }, }); - access_chain = try c.appendNode(.{ + access_chain = try c.addNode(.{ .tag = .field_access, - .main_token = try c.appendToken(.period, "."), + .main_token = try c.addToken(.period, "."), .data = .{ .lhs = access_chain, - .rhs = try c.appendIdentifier(second), + .rhs = try c.addIdentifier(second), }, }); return access_chain; } + +fn renderCall(c: *Context, lhs: NodeIndex, args: []const Node) !NodeIndex { + const lparen = try c.addToken(.l_paren, "("); + const res = switch (args.len) { + 0 => try c.addNode(.{ + .tag = .call_one, + .main_token = lparen, + .data = .{ + .lhs = lhs, + .rhs = 0, + }, + }), + 1 => blk: { + const arg = try renderNode(c, args[0]); + break :blk try c.addNode(.{ + .tag = .call_one, + .main_token = lparen, + .data = .{ + .lhs = lhs, + .rhs = arg, + }, + }); + }, + 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 + for (args) |arg, i| { + if (i != 0) _ = try c.addToken(.comma, ","); + c.extra_data.appendAssumeCapacity(try renderNode(c, arg)); + } + c.extra_data.appendAssumeCapacity(start); + c.extra_data.appendAssumeCapacity(end); + break :blk try c.addNode(.{ + .tag = .call_comma, + .main_token = lparen, + .data = .{ + .lhs = lhs, + .rhs = end + 2, + }, + }); + }, + }; + _ = try c.addToken(.r_paren, ")"); + return res; +}