aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2021-02-13 20:50:39 +0200
committerVeikka Tuominen <git@vexu.eu>2021-02-16 16:40:42 +0200
commit1147ecc5fda6d46c5e4d02eeda18238f34ae56dd (patch)
tree27949e56cc75f6dad3a0c2c27c01ddd8e2ed9a37
parentd7460db044ef6649486a27f2b9ebb1de9e2ce2b0 (diff)
downloadzig-1147ecc5fda6d46c5e4d02eeda18238f34ae56dd.tar.gz
zig-1147ecc5fda6d46c5e4d02eeda18238f34ae56dd.zip
translate-c: render variables and builtin calls
-rw-r--r--src/translate_c.zig31
-rw-r--r--src/translate_c/ast.zig312
2 files changed, 282 insertions, 61 deletions
diff --git a/src/translate_c.zig b/src/translate_c.zig
index 9b80582ab5..821f3c5b74 100644
--- a/src/translate_c.zig
+++ b/src/translate_c.zig
@@ -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 => {
diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig
index 4e91f13757..282e645f2e 100644
--- a/src/translate_c/ast.zig
+++ b/src/translate_c/ast.zig
@@ -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,
+ },
+ });
+ }
+}