translate-c: render variables and builtin calls

This commit is contained in:
Veikka Tuominen 2021-02-13 20:50:39 +02:00
parent d7460db044
commit 1147ecc5fd
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
2 changed files with 282 additions and 61 deletions

View File

@ -769,7 +769,7 @@ fn transCreateNodeTypedef(
const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
payload.* = .{
.base = .{ .tag = ([2]Tag{ .typedef, .pub_typedef })[@boolToInt(toplevel)] },
.base = .{ .tag = ([2]Tag{ .var_simple, .pub_var_simple })[@boolToInt(toplevel)] },
.data = .{
.name = checked_name,
.init = init_node,
@ -1678,7 +1678,7 @@ fn transStringLiteralAsArray(
init_list[i] = try transCreateCharLitNode(c, narrow, code_unit);
}
while (i < array_size) : (i += 1) {
init_list[i] = try transCreateNodeNumber(c, 0);
init_list[i] = try transCreateNodeNumber(c, 0, .int);
}
return Tag.array_init.create(c.arena, init_list);
@ -2345,7 +2345,7 @@ fn transCharLiteral(
// C has a somewhat obscure feature called multi-character character constant
// e.g. 'abcd'
const int_lit_node = if (kind == .Ascii and val > 255)
try transCreateNodeNumber(c, val)
try transCreateNodeNumber(c, val, .int)
else
try transCreateCharLitNode(c, narrow, val);
@ -2948,7 +2948,7 @@ fn transBreak(c: *Context, scope: *Scope) TransError!Node {
fn transFloatingLiteral(c: *Context, scope: *Scope, stmt: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node {
// TODO use something more accurate
const dbl = stmt.getValueAsApproximateDouble();
const node = try transCreateNodeNumber(c, dbl);
const node = try transCreateNodeNumber(c, dbl, .float);
return maybeSuppressResult(c, scope, used, node);
}
@ -3471,13 +3471,16 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {
const str = big.toStringAlloc(c.arena, 10, false) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
};
return Tag.number_literal.create(c.arena, str);
return Tag.integer_literal.create(c.arena, str);
}
fn transCreateNodeNumber(c: *Context, int: anytype) !Node {
const fmt_s = if (comptime std.meta.trait.isNumber(@TypeOf(int))) "{d}" else "{s}";
const str = try std.fmt.allocPrint(c.arena, fmt_s, .{int});
return Tag.number_literal.create(c.arena, str);
fn transCreateNodeNumber(c: *Context, num: anytype, num_kind: enum { int, float }) !Node {
const fmt_s = if (comptime std.meta.trait.isNumber(@TypeOf(num))) "{d}" else "{s}";
const str = try std.fmt.allocPrint(c.arena, fmt_s, .{num});
if (num_kind == .float)
return Tag.float_literal.create(c.arena, str)
else
return Tag.integer_literal.create(c.arena, str);
}
fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: Node, proto_alias: *ast.Payload.Func) !Node {
@ -4162,7 +4165,7 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {
}
if (suffix == .none) {
return transCreateNodeNumber(c, lit_bytes);
return transCreateNodeNumber(c, lit_bytes, .int);
}
const type_node = try Tag.type.create(c.arena, switch (suffix) {
@ -4179,21 +4182,21 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {
.llu => 3,
else => unreachable,
}];
const rhs = try transCreateNodeNumber(c, lit_bytes);
const rhs = try transCreateNodeNumber(c, lit_bytes, .int);
return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
},
.FloatLiteral => |suffix| {
if (lit_bytes[0] == '.')
lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes});
if (suffix == .none) {
return transCreateNodeNumber(c, lit_bytes);
return transCreateNodeNumber(c, lit_bytes, .float);
}
const type_node = try Tag.type.create(c.arena, switch (suffix) {
.f => "f32",
.l => "c_longdouble",
else => unreachable,
});
const rhs = try transCreateNodeNumber(c, lit_bytes[0 .. lit_bytes.len - 1]);
const rhs = try transCreateNodeNumber(c, lit_bytes[0 .. lit_bytes.len - 1], .float);
return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
},
else => unreachable,
@ -4369,7 +4372,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
return Tag.char_literal.create(c.arena, try zigifyEscapeSequences(c, m));
} else {
const str = try std.fmt.allocPrint(c.arena, "0x{x}", .{slice[1 .. slice.len - 1]});
return Tag.number_literal.create(c.arena, str);
return Tag.integer_literal.create(c.arena, str);
}
},
.StringLiteral => {

View File

@ -27,8 +27,8 @@ pub const Node = extern union {
usingnamespace_builtins,
// After this, the tag requires a payload.
// int or float, doesn't really matter
number_literal,
integer_literal,
float_literal,
string_literal,
char_literal,
identifier,
@ -193,10 +193,8 @@ pub const Node = extern union {
/// pub const alias = actual;
alias,
/// const name = init;
typedef,
var_simple,
/// pub const name = init;
pub_typedef,
pub_var_simple,
/// pub const enum_field_name = @enumToInt(enum_name.field_name);
enum_redecl,
@ -333,7 +331,8 @@ pub const Node = extern union {
.ptr_cast,
=> Payload.BinOp,
.number_literal,
.integer_literal,
.float_literal,
.string_literal,
.char_literal,
.identifier,
@ -358,7 +357,7 @@ pub const Node = extern union {
.array_type => Payload.Array,
.arg_redecl, .alias, .fail_decl => Payload.ArgRedecl,
.log2_int_type => Payload.Log2IntType,
.typedef, .pub_typedef, .var_simple, .pub_var_simple => Payload.SimpleVarDecl,
.var_simple, .pub_var_simple => Payload.SimpleVarDecl,
.enum_redecl => Payload.EnumRedecl,
.array_filler => Payload.ArrayFiller,
.pub_inline_fn => Payload.PubInlineFn,
@ -705,7 +704,6 @@ const Context = struct {
}
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});
}
@ -726,6 +724,17 @@ const Context = struct {
try c.nodes.append(c.gpa, elem);
return result;
}
fn addExtra(c: *Context, extra: anytype) Allocator.Error!NodeIndex {
const fields = std.meta.fields(@TypeOf(extra));
try c.extra_data.ensureCapacity(c.gpa, c.extra_data.items.len + fields.len);
const result = @intCast(u32, c.extra_data.items.len);
inline for (fields) |field| {
comptime std.debug.assert(field.field_type == NodeIndex);
c.extra_data.appendAssumeCapacity(@field(extra, field.name));
}
return result;
}
};
fn renderNodes(c: *Context, nodes: []const Node) Allocator.Error!NodeSubRange {
@ -734,7 +743,8 @@ fn renderNodes(c: *Context, nodes: []const Node) Allocator.Error!NodeSubRange {
for (nodes) |node| {
const res = try renderNode(c, node);
if (res == 0) continue;
if (node.tag() == .warning) continue;
if (c.nodes.items(.tag)[res] == .identifier) continue; // TODO remove
try result.append(res);
}
@ -744,10 +754,10 @@ fn renderNodes(c: *Context, nodes: []const Node) Allocator.Error!NodeSubRange {
fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
switch (node.tag()) {
.warning => {
const payload = node.castTag(.warning).?;
try c.buf.appendSlice(payload.data);
const payload = node.castTag(.warning).?.data;
try c.buf.appendSlice(payload);
try c.buf.append('\n');
return 0;
return @as(NodeIndex, 0); // error: integer value 0 cannot be coerced to type 'std.mem.Allocator.Error!u32'
},
.usingnamespace_builtins => {
// pub usingnamespace @import("std").c.builtins;
@ -766,34 +776,34 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
});
},
.std_math_Log2Int => {
const payload = node.castTag(.std_math_Log2Int).?;
const payload = node.castTag(.std_math_Log2Int).?.data;
const import_node = try renderStdImport(c, "math", "Log2Int");
return renderCall(c, import_node, &.{payload.data});
return renderCall(c, import_node, &.{payload});
},
.std_meta_cast => {
const payload = node.castTag(.std_meta_cast).?;
const payload = node.castTag(.std_meta_cast).?.data;
const import_node = try renderStdImport(c, "meta", "cast");
return renderCall(c, import_node, &.{ payload.data.lhs, payload.data.rhs });
return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
},
.std_meta_sizeof => {
const payload = node.castTag(.std_meta_sizeof).?;
const payload = node.castTag(.std_meta_sizeof).?.data;
const import_node = try renderStdImport(c, "meta", "sizeof");
return renderCall(c, import_node, &.{payload.data});
return renderCall(c, import_node, &.{payload});
},
.std_mem_zeroes => {
const payload = node.castTag(.std_mem_zeroes).?;
const payload = node.castTag(.std_mem_zeroes).?.data;
const import_node = try renderStdImport(c, "mem", "zeroes");
return renderCall(c, import_node, &.{payload.data});
return renderCall(c, import_node, &.{payload});
},
.std_mem_zeroinit => {
const payload = node.castTag(.std_mem_zeroinit).?;
const payload = node.castTag(.std_mem_zeroinit).?.data;
const import_node = try renderStdImport(c, "mem", "zeroInit");
return renderCall(c, import_node, &.{ payload.data.lhs, payload.data.rhs });
return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
},
.call => {
const payload = node.castTag(.call).?;
const lhs = try renderNode(c, payload.data.lhs);
return renderCall(c, lhs, payload.data.args);
const payload = node.castTag(.call).?.data;
const lhs = try renderNode(c, payload.lhs);
return renderCall(c, lhs, payload.args);
},
.null_literal => return c.addNode(.{
.tag = .null_literal,
@ -860,10 +870,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
},
}),
.type => {
const payload = node.castTag(.type).?;
const payload = node.castTag(.type).?.data;
return c.addNode(.{
.tag = .identifier,
.main_token = try c.addToken(.identifier, payload.data),
.main_token = try c.addToken(.identifier, payload),
.data = .{
.lhs = undefined,
.rhs = undefined,
@ -871,22 +881,32 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
});
},
.identifier => {
const payload = node.castTag(.identifier).?;
const payload = node.castTag(.identifier).?.data;
return c.addNode(.{
.tag = .identifier,
.main_token = try c.addIdentifier(payload.data),
.main_token = try c.addIdentifier(payload),
.data = .{
.lhs = undefined,
.rhs = undefined,
},
});
},
.number_literal => {
const payload = node.castTag(.number_literal).?;
.float_literal => {
const payload = node.castTag(.float_literal).?.data;
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),
.tag = .float_literal,
.main_token = try c.addToken(.float_literal, payload),
.data = .{
.lhs = undefined,
.rhs = undefined,
},
});
},
.integer_literal => {
const payload = node.castTag(.integer_literal).?.data;
return c.addNode(.{
.tag = .integer_literal,
.main_token = try c.addToken(.integer_literal, payload),
.data = .{
.lhs = undefined,
.rhs = undefined,
@ -894,10 +914,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
});
},
.string_literal => {
const payload = node.castTag(.string_literal).?;
const payload = node.castTag(.string_literal).?.data;
return c.addNode(.{
.tag = .identifier,
.main_token = try c.addToken(.char_literal, payload.data),
.main_token = try c.addToken(.string_literal, payload),
.data = .{
.lhs = undefined,
.rhs = undefined,
@ -905,10 +925,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
});
},
.char_literal => {
const payload = node.castTag(.char_literal).?;
const payload = node.castTag(.char_literal).?.data;
return c.addNode(.{
.tag = .identifier,
.main_token = try c.addToken(.string_literal, payload.data),
.main_token = try c.addToken(.string_literal, payload),
.data = .{
.lhs = undefined,
.rhs = undefined,
@ -916,17 +936,16 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
});
},
.fail_decl => {
const payload = node.castTag(.fail_decl).?;
const payload = node.castTag(.fail_decl).?.data;
// 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);
const const_tok = try c.addToken(.keyword_const, "const");
_ = try c.addIdentifier(payload.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_tok = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(payload.mangled)});
const err_msg = try c.addNode(.{
.tag = .string_literal,
.main_token = err_msg_tok,
@ -948,17 +967,105 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
return c.addNode(.{
.tag = .simple_var_decl,
.main_token = const_kw,
.main_token = const_tok,
.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'
.pub_var_simple, .var_simple => {
const payload = @fieldParentPtr(Payload.SimpleVarDecl, "base", node.ptr_otherwise).data;
if (node.tag() == .pub_var_simple) _ = try c.addToken(.keyword_pub, "pub");
const const_tok = try c.addToken(.keyword_const, "const");
_ = try c.addIdentifier(payload.name);
_ = try c.addToken(.equal, "=");
const init = try renderNode(c, payload.init);
_ = try c.addToken(.semicolon, ";");
return c.addNode(.{
.tag = .simple_var_decl,
.main_token = const_tok,
.data = .{
.lhs = 0,
.rhs = init,
},
});
},
.var_decl => return renderVar(c, node),
.int_cast => {
const payload = node.castTag(.int_cast).?.data;
return renderBuiltinCall(c, "@intCast", &.{ payload.lhs, payload.rhs });
},
.rem => {
const payload = node.castTag(.rem).?.data;
return renderBuiltinCall(c, "@rem", &.{ payload.lhs, payload.rhs });
},
.div_trunc => {
const payload = node.castTag(.div_trunc).?.data;
return renderBuiltinCall(c, "@divTrunc", &.{ payload.lhs, payload.rhs });
},
.bool_to_int => {
const payload = node.castTag(.bool_to_int).?.data;
return renderBuiltinCall(c, "@boolToInt", &.{payload});
},
.as => {
const payload = node.castTag(.as).?.data;
return renderBuiltinCall(c, "@as", &.{ payload.lhs, payload.rhs });
},
.truncate => {
const payload = node.castTag(.truncate).?.data;
return renderBuiltinCall(c, "@truncate", &.{ payload.lhs, payload.rhs });
},
.bit_cast => {
const payload = node.castTag(.bit_cast).?.data;
return renderBuiltinCall(c, "@bitCast", &.{ payload.lhs, payload.rhs });
},
.float_cast => {
const payload = node.castTag(.float_cast).?.data;
return renderBuiltinCall(c, "@floatCast", &.{ payload.lhs, payload.rhs });
},
.float_to_int => {
const payload = node.castTag(.float_to_int).?.data;
return renderBuiltinCall(c, "@floatToInt", &.{ payload.lhs, payload.rhs });
},
.int_to_float => {
const payload = node.castTag(.int_to_float).?.data;
return renderBuiltinCall(c, "@intToFloat", &.{ payload.lhs, payload.rhs });
},
.int_to_enum => {
const payload = node.castTag(.int_to_enum).?.data;
return renderBuiltinCall(c, "@intToEnum", &.{ payload.lhs, payload.rhs });
},
.enum_to_int => {
const payload = node.castTag(.enum_to_int).?.data;
return renderBuiltinCall(c, "@enumToInt", &.{payload});
},
.int_to_ptr => {
const payload = node.castTag(.int_to_ptr).?.data;
return renderBuiltinCall(c, "@intToPtr", &.{ payload.lhs, payload.rhs });
},
.ptr_to_int => {
const payload = node.castTag(.ptr_to_int).?.data;
return renderBuiltinCall(c, "@ptrToInt", &.{payload});
},
.align_cast => {
const payload = node.castTag(.align_cast).?.data;
return renderBuiltinCall(c, "@alignCast", &.{ payload.lhs, payload.rhs });
},
.ptr_cast => {
const payload = node.castTag(.ptr_cast).?.data;
return renderBuiltinCall(c, "@ptrCast", &.{ payload.lhs, payload.rhs });
},
else => return c.addNode(.{
.tag = .identifier,
.main_token = try c.addTokenFmt(.identifier, "@\"TODO {}\"", .{node.tag()}),
.data = .{
.lhs = undefined,
.rhs = undefined,
},
}),
}
}
@ -1050,3 +1157,114 @@ fn renderCall(c: *Context, lhs: NodeIndex, args: []const Node) !NodeIndex {
_ = try c.addToken(.r_paren, ")");
return res;
}
fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !NodeIndex {
const builtin_tok = try c.addToken(.builtin, builtin);
_ = try c.addToken(.l_paren, "(");
var arg_1: NodeIndex = 0;
var arg_2: NodeIndex = 0;
switch (args.len) {
0 => {},
1 => {
arg_1 = try renderNode(c, args[0]);
},
2 => {
arg_1 = try renderNode(c, args[0]);
_ = try c.addToken(.comma, ",");
arg_2 = try renderNode(c, args[1]);
},
else => unreachable, // expand this function as needed.
}
_ = try c.addToken(.r_paren, ")");
return c.addNode(.{
.tag = .builtin_call_two,
.main_token = builtin_tok,
.data = .{
.lhs = arg_1,
.rhs = arg_2,
},
});
}
fn renderVar(c: *Context, node: Node) !NodeIndex {
const payload = node.castTag(.var_decl).?.data;
if (payload.is_pub) _ = try c.addToken(.keyword_pub, "pub");
if (payload.is_extern) _ = try c.addToken(.keyword_extern, "extern");
if (payload.is_export) _ = try c.addToken(.keyword_export, "export");
const mut_tok = if (payload.is_const)
try c.addToken(.keyword_const, "const")
else
try c.addToken(.keyword_var, "var");
_ = try c.addIdentifier(payload.name);
_ = try c.addToken(.colon, ":");
const type_node = try renderNode(c, payload.type);
const align_node = if (payload.alignment) |some| blk: {
_ = try c.addToken(.keyword_align, "align");
_ = try c.addToken(.l_paren, "(");
const res = try c.addNode(.{
.tag = .integer_literal,
.main_token = try c.addTokenFmt(.integer_literal, "{d}", .{some}),
.data = .{ .lhs = undefined, .rhs = undefined },
});
_ = try c.addToken(.r_paren, ")");
break :blk res;
} else 0;
const section_node = if (payload.linksection_string) |some| blk: {
_ = try c.addToken(.keyword_linksection, "linksection");
_ = try c.addToken(.l_paren, "(");
const res = try c.addNode(.{
.tag = .string_literal,
.main_token = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(some)}),
.data = .{ .lhs = undefined, .rhs = undefined },
});
_ = try c.addToken(.r_paren, ")");
break :blk res;
} else 0;
const init_node = if (payload.init) |some| blk: {
_ = try c.addToken(.equal, "=");
break :blk try renderNode(c, some);
} else 0;
_ = try c.addToken(.semicolon, ";");
if (section_node == 0) {
if (align_node == 0) {
return c.addNode(.{
.tag = .simple_var_decl,
.main_token = mut_tok,
.data = .{
.lhs = type_node,
.rhs = init_node,
},
});
} else {
return c.addNode(.{
.tag = .local_var_decl,
.main_token = mut_tok,
.data = .{
.lhs = try c.addExtra(std.zig.ast.Node.LocalVarDecl{
.type_node = type_node,
.align_node = align_node,
}),
.rhs = init_node,
},
});
}
} else {
return c.addNode(.{
.tag = .global_var_decl,
.main_token = mut_tok,
.data = .{
.lhs = try c.addExtra(std.zig.ast.Node.GlobalVarDecl{
.type_node = type_node,
.align_node = align_node,
.section_node = section_node,
}),
.rhs = init_node,
},
});
}
}