Commit 5dac3683c9
Changed files (2)
src
translate_c
src/translate_c/ast.zig
@@ -10,6 +10,7 @@ pub const Node = extern union {
pub const Tag = enum {
null_literal,
undefined_literal,
+ /// opaque {}
opaque_literal,
true_literal,
false_literal,
@@ -42,6 +43,7 @@ pub const Node = extern union {
func,
warning,
failed_decl,
+ /// All enums are non-exhaustive
@"enum",
@"struct",
@"union",
@@ -145,8 +147,12 @@ pub const Node = extern union {
arg_redecl,
/// 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,
pub const last_no_payload_tag = Tag.usingnamespace_builtins;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
@@ -266,7 +272,8 @@ pub const Node = extern union {
.array_type => Payload.Array,
.arg_redecl => Payload.ArgRedecl,
.log2_int_type => Payload.Log2IntType,
- .typedef, .pub_typedef => Payload.Typedef,
+ .typedef, .pub_typedef, .pub_var_simple => Payload.SimpleVarDecl,
+ .enum_redecl => Payload.EnumRedecl,
};
}
@@ -419,41 +426,37 @@ pub const Payload = struct {
return_type: Node,
body: ?Node,
alignment: ?c_uint,
-
- pub const Param = struct {
- is_noalias: bool,
- name: ?[]const u8,
- type: Node,
- };
},
+
+ pub const Param = struct {
+ is_noalias: bool,
+ name: ?[]const u8,
+ type: Node,
+ };
};
pub const Enum = struct {
base: Node = .{ .tag = .@"enum" },
- data: struct {
- name: ?[]const u8,
- fields: []Field,
+ data: []Field,
- pub const Field = struct {
- name: []const u8,
- value: ?[]const u8,
- };
- },
+ pub const Field = struct {
+ name: []const u8,
+ value: ?Node,
+ };
};
pub const Record = struct {
base: Node,
data: struct {
- name: ?[]const u8,
@"packed": bool,
fields: []Field,
-
- pub const Field = struct {
- name: []const u8,
- type: Type,
- alignment: c_uint,
- };
},
+
+ pub const Field = struct {
+ name: []const u8,
+ type: Node,
+ alignment: ?c_uint,
+ };
};
pub const ArrayInit = struct {
@@ -514,13 +517,22 @@ pub const Payload = struct {
data: std.math.Log2Int(u64),
};
- pub const Typedef = struct {
+ pub const SimpleVarDecl = struct {
base: Node,
data: struct {
name: []const u8,
init: Node,
},
};
+
+ pub const EnumRedecl = struct {
+ base: Node,
+ data: struct {
+ enum_val_name: []const u8,
+ field_name: []const u8,
+ enum_name: []const u8,
+ },
+ };
};
/// Converts the nodes into a Zig ast.
src/translate_c.zig
@@ -783,7 +783,7 @@ fn transCreateNodeTypedef(
const payload = try c.arena.create(ast.Payload.Typedef);
payload.* = .{
- .base = .{ .tag = ([2]ast.Node.Tag{ .typedef, .pub_typedef })[toplevel] },
+ .base = .{ .tag = ([2]ast.Node.Tag{ .typedef, .pub_typedef })[@boolToInt(toplevel)] },
.data = .{
.name = checked_name,
.init = init_node,
@@ -792,7 +792,7 @@ fn transCreateNodeTypedef(
return Node.initPayload(&payload.base);
}
-fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*ast.Node {
+fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Node {
if (c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl()))) |name|
return try transCreateNodeIdentifier(c, name); // Avoid processing this decl twice
const record_loc = record_decl.getLocation();
@@ -807,46 +807,30 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as
}
var container_kind_name: []const u8 = undefined;
- var container_kind: std.zig.Token.Id = undefined;
+ var is_union = false;
if (record_decl.isUnion()) {
container_kind_name = "union";
- container_kind = .Keyword_union;
+ is_union = true;
} else if (record_decl.isStruct()) {
container_kind_name = "struct";
- container_kind = .Keyword_struct;
} else {
- try emitWarning(c, record_loc, "record {s} is not a struct or union", .{bare_name});
+ try warn(c, record_loc, "record {s} is not a struct or union", .{bare_name});
return null;
}
const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name });
_ = try c.decl_table.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), name);
- const visib_tok = if (!is_unnamed) try appendToken(c, .Keyword_pub, "pub") else null;
- const mut_tok = try appendToken(c, .Keyword_const, "const");
- const name_tok = try appendIdentifier(c, name);
-
- const eq_token = try appendToken(c, .Equal, "=");
-
- var semicolon: ast.TokenIndex = undefined;
+ const is_pub = !is_unnamed;
const init_node = blk: {
- const rp = makeRestorePoint(c);
const record_def = record_decl.getDefinition() orelse {
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
- const opaque_type = try transCreateNodeOpaqueType(c);
- semicolon = try appendToken(c, .Semicolon, ";");
- break :blk opaque_type;
+ break :blk Node.opaque_literal.init();
};
- const layout_tok = try if (record_decl.getPackedAttribute())
- appendToken(c, .Keyword_packed, "packed")
- else
- appendToken(c, .Keyword_extern, "extern");
- const container_tok = try appendToken(c, container_kind, container_kind_name);
- const lbrace_token = try appendToken(c, .LBrace, "{");
-
- var fields_and_decls = std.ArrayList(*ast.Node).init(c.gpa);
- defer fields_and_decls.deinit();
+ const is_packed = record_decl.getPackedAttribute();
+ var fields = std.ArrayList(ast.Payload.Record.Field).init(c.gpa);
+ defer fields.deinit();
var unnamed_field_count: u32 = 0;
var it = record_def.field_begin();
@@ -858,110 +842,82 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as
if (field_decl.isBitField()) {
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
- const opaque_type = try transCreateNodeOpaqueType(c);
- semicolon = try appendToken(c, .Semicolon, ";");
- try emitWarning(c, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name});
- break :blk opaque_type;
+ try warn(c, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name});
+ break :blk Node.opaque_literal.init();
}
if (qualTypeCanon(field_qt).isIncompleteOrZeroLengthArrayType(c.clang_context)) {
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
- const opaque_type = try transCreateNodeOpaqueType(c);
- semicolon = try appendToken(c, .Semicolon, ";");
- try emitWarning(c, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name});
- break :blk opaque_type;
+ try warn(c, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name});
+ break :blk Node.opaque_literal.init();
}
var is_anon = false;
- var raw_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
- if (field_decl.isAnonymousStructOrUnion() or raw_name.len == 0) {
+ var field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
+ if (field_decl.isAnonymousStructOrUnion() or field_name.len == 0) {
// Context.getMangle() is not used here because doing so causes unpredictable field names for anonymous fields.
- raw_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{unnamed_field_count});
+ field_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{unnamed_field_count});
unnamed_field_count += 1;
is_anon = true;
}
- const field_name = try appendIdentifier(c, raw_name);
- _ = try appendToken(c, .Colon, ":");
- const field_type = transQualType(rp, field_qt, field_loc) catch |err| switch (err) {
+ const field_type = transQualType(c, field_qt, field_loc) catch |err| switch (err) {
error.UnsupportedType => {
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
- const opaque_type = try transCreateNodeOpaqueType(c);
- semicolon = try appendToken(c, .Semicolon, ";");
- try emitWarning(c, record_loc, "{s} demoted to opaque type - unable to translate type of field {s}", .{ container_kind_name, raw_name });
- break :blk opaque_type;
+ try warn(c, record_loc, "{s} demoted to opaque type - unable to translate type of field {s}", .{ container_kind_name, raw_name });
+ break :blk Node.opaque_literal.init();
},
else => |e| return e,
};
- const align_expr = blk_2: {
+ const alignment = blk_2: {
const alignment = field_decl.getAlignedAttribute(c.clang_context);
if (alignment != 0) {
- _ = try appendToken(c, .Keyword_align, "align");
- _ = try appendToken(c, .LParen, "(");
// Clang reports the alignment in bits
- const expr = try transCreateNodeInt(c, alignment / 8);
- _ = try appendToken(c, .RParen, ")");
-
- break :blk_2 expr;
+ break :blk_2 alignment / 8;
}
break :blk_2 null;
};
- const field_node = try c.arena.create(ast.Node.ContainerField);
- field_node.* = .{
- .doc_comments = null,
- .comptime_token = null,
- .name_token = field_name,
- .type_expr = field_type,
- .value_expr = null,
- .align_expr = align_expr,
- };
-
if (is_anon) {
- _ = try c.decl_table.put(
- c.gpa,
- @ptrToInt(field_decl.getCanonicalDecl()),
- raw_name,
- );
+ _ = try c.decl_table.put(c.gpa, @ptrToInt(field_decl.getCanonicalDecl()), field_name);
}
- try fields_and_decls.append(&field_node.base);
- _ = try appendToken(c, .Comma, ",");
+ try fields.append(.{
+ .name = field_name,
+ .type = field_type,
+ .alignment = alignment,
+ });
}
- const container_node = try ast.Node.ContainerDecl.alloc(c.arena, fields_and_decls.items.len);
+
+ const payload = try c.arena.create(ast.Payload.Record);
container_node.* = .{
- .layout_token = layout_tok,
- .kind_token = container_tok,
- .init_arg_expr = .None,
- .fields_and_decls_len = fields_and_decls.items.len,
- .lbrace_token = lbrace_token,
- .rbrace_token = try appendToken(c, .RBrace, "}"),
+ .base = .{ .tag = ([2]ast.Node.Tag{ .@"struct", .@"union" })[@boolToInt(is_union)] },
+ .data = .{
+ .is_packed = is_packed,
+ .fields = try c.arena.dupe(ast.Payload.Record.Field, fields.items),
+ },
};
- mem.copy(*ast.Node, container_node.fieldsAndDecls(), fields_and_decls.items);
- semicolon = try appendToken(c, .Semicolon, ";");
- break :blk &container_node.base;
+ break :blk Node.initPayload(&container_node.base);
};
- const node = try ast.Node.VarDecl.create(c.arena, .{
- .name_token = name_tok,
- .mut_token = mut_tok,
- .semicolon_token = semicolon,
- }, .{
- .visib_token = visib_tok,
- .eq_token = eq_token,
- .init_node = init_node,
- });
+ const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
+ payload.* = .{
+ .base = .{ .tag = ([2]ast.Node.Tag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] },
+ .data = .{
+ .name = name,
+ .init = init_node,
+ },
+ };
- try addTopLevelDecl(c, name, &node.base);
+ try addTopLevelDecl(c, name, Node.initPayload(&payload.base));
if (!is_unnamed)
try c.alias_list.append(.{ .alias = bare_name, .name = name });
- return transCreateNodeIdentifier(c, name);
+ return Node.identifier.create(c.arena, name);
}
-fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node {
+fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?Node {
if (c.decl_table.get(@ptrToInt(enum_decl.getCanonicalDecl()))) |name|
return try transCreateNodeIdentifier(c, name); // Avoid processing this decl twice
- const rp = makeRestorePoint(c);
const enum_loc = enum_decl.getLocation();
var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_decl).getName_bytes_begin());
@@ -974,10 +930,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
const name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
_ = try c.decl_table.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), name);
- const visib_tok = if (!is_unnamed) try appendToken(c, .Keyword_pub, "pub") else null;
- const mut_tok = try appendToken(c, .Keyword_const, "const");
- const name_tok = try appendIdentifier(c, name);
- const eq_token = try appendToken(c, .Equal, "=");
+ const is_pub = !is_unnamed;
const init_node = if (enum_decl.getDefinition()) |enum_def| blk: {
var pure_enum = true;
@@ -991,11 +944,8 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
}
}
- const extern_tok = try appendToken(c, .Keyword_extern, "extern");
- const container_tok = try appendToken(c, .Keyword_enum, "enum");
-
- var fields_and_decls = std.ArrayList(*ast.Node).init(c.gpa);
- defer fields_and_decls.deinit();
+ var fields = std.ArrayList(ast.Payload.Enum.Field).init(c.gpa);
+ defer fields.deinit();
const int_type = enum_decl.getIntegerType();
// The underlying type may be null in case of forward-declared enum
@@ -1003,30 +953,23 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
// default to the usual integer type used for all the enums.
// default to c_int since msvc and gcc default to different types
- _ = try appendToken(c, .LParen, "(");
- const init_arg_expr = ast.Node.ContainerDecl.InitArg{
- .Type = if (int_type.ptr != null and
- !isCBuiltinType(int_type, .UInt) and
- !isCBuiltinType(int_type, .Int))
- transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
- error.UnsupportedType => {
- try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
- return null;
- },
- else => |e| return e,
- }
- else
- try transCreateNodeIdentifier(c, "c_int"),
- };
- _ = try appendToken(c, .RParen, ")");
-
- const lbrace_token = try appendToken(c, .LBrace, "{");
+ const init_arg_expr = if (int_type.ptr != null and
+ !isCBuiltinType(int_type, .UInt) and
+ !isCBuiltinType(int_type, .Int))
+ transQualType(c, int_type, enum_loc) catch |err| switch (err) {
+ error.UnsupportedType => {
+ try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
+ return null;
+ },
+ else => |e| return e,
+ }
+ else
+ try Node.type.create(c.arena, "c_int");
it = enum_def.enumerator_begin();
end_it = enum_def.enumerator_end();
while (it.neq(end_it)) : (it = it.next()) {
const enum_const = it.deref();
-
const enum_val_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_const).getName_bytes_begin());
const field_name = if (!is_unnamed and mem.startsWith(u8, enum_val_name, bare_name))
@@ -1034,100 +977,41 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
else
enum_val_name;
- const field_name_tok = try appendIdentifier(c, field_name);
-
- const int_node = if (!pure_enum) blk_2: {
- _ = try appendToken(c, .Colon, "=");
- break :blk_2 try transCreateNodeAPInt(c, enum_const.getInitVal());
- } else
+ const int_node = if (!pure_enum)
+ try transCreateNodeAPInt(c, enum_const.getInitVal())
+ else
null;
- const field_node = try c.arena.create(ast.Node.ContainerField);
- field_node.* = .{
- .doc_comments = null,
- .comptime_token = null,
- .name_token = field_name_tok,
- .type_expr = null,
- .value_expr = int_node,
- .align_expr = null,
- };
-
- try fields_and_decls.append(&field_node.base);
- _ = try appendToken(c, .Comma, ",");
+ try fields_and_decls.append(.{
+ .name = field_name,
+ .value = int_node,
+ });
// In C each enum value is in the global namespace. So we put them there too.
// At this point we can rely on the enum emitting successfully.
- const tld_visib_tok = try appendToken(c, .Keyword_pub, "pub");
- const tld_mut_tok = try appendToken(c, .Keyword_const, "const");
- const tld_name_tok = try appendIdentifier(c, enum_val_name);
- const tld_eq_token = try appendToken(c, .Equal, "=");
- const cast_node = try rp.c.createBuiltinCall("@enumToInt", 1);
- const enum_ident = try transCreateNodeIdentifier(c, name);
- const period_tok = try appendToken(c, .Period, ".");
- const field_ident = try transCreateNodeIdentifier(c, field_name);
- const field_access_node = try c.arena.create(ast.Node.SimpleInfixOp);
- field_access_node.* = .{
- .base = .{ .tag = .Period },
- .op_token = period_tok,
- .lhs = enum_ident,
- .rhs = field_ident,
- };
- cast_node.params()[0] = &field_access_node.base;
- cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
- const tld_init_node = &cast_node.base;
- const tld_semicolon_token = try appendToken(c, .Semicolon, ";");
- const tld_node = try ast.Node.VarDecl.create(c.arena, .{
- .name_token = tld_name_tok,
- .mut_token = tld_mut_tok,
- .semicolon_token = tld_semicolon_token,
- }, .{
- .visib_token = tld_visib_tok,
- .eq_token = tld_eq_token,
- .init_node = tld_init_node,
- });
- try addTopLevelDecl(c, field_name, &tld_node.base);
+ try addTopLevelDecl(c, field_name, try Node.enum_redecl.create(c.arena, .{
+ .enum_val_name = enum_val_name,
+ .field_name = field_name,
+ .enum_name = name,
+ }));
}
- // make non exhaustive
- const field_node = try c.arena.create(ast.Node.ContainerField);
- field_node.* = .{
- .doc_comments = null,
- .comptime_token = null,
- .name_token = try appendIdentifier(c, "_"),
- .type_expr = null,
- .value_expr = null,
- .align_expr = null,
- };
- try fields_and_decls.append(&field_node.base);
- _ = try appendToken(c, .Comma, ",");
- const container_node = try ast.Node.ContainerDecl.alloc(c.arena, fields_and_decls.items.len);
- container_node.* = .{
- .layout_token = extern_tok,
- .kind_token = container_tok,
- .init_arg_expr = init_arg_expr,
- .fields_and_decls_len = fields_and_decls.items.len,
- .lbrace_token = lbrace_token,
- .rbrace_token = try appendToken(c, .RBrace, "}"),
- };
- mem.copy(*ast.Node, container_node.fieldsAndDecls(), fields_and_decls.items);
- break :blk &container_node.base;
+ break :blk try Node.@"enum".create(c.arena, try c.arena.dupe(ast.Payload.Enum.Field, fields.items));
} else blk: {
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {});
- break :blk try transCreateNodeOpaqueType(c);
+ break :blk Node.opaque_literal.init();
};
- const semicolon_token = try appendToken(c, .Semicolon, ";");
- const node = try ast.Node.VarDecl.create(c.arena, .{
- .name_token = name_tok,
- .mut_token = mut_tok,
- .semicolon_token = semicolon_token,
- }, .{
- .visib_token = visib_tok,
- .eq_token = eq_token,
- .init_node = init_node,
- });
+ const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
+ payload.* = .{
+ .base = .{ .tag = ([2]ast.Node.Tag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] },
+ .data = .{
+ .name = name,
+ .init = init_node,
+ },
+ };
- try addTopLevelDecl(c, name, &node.base);
+ try addTopLevelDecl(c, name, Node.initPayload(&payload.base));
if (!is_unnamed)
try c.alias_list.append(.{ .alias = bare_name, .name = name });
return transCreateNodeIdentifier(c, name);
@@ -1382,22 +1266,22 @@ fn transCompoundStmt(c: *Context, scope: *Scope, stmt: *const clang.CompoundStmt
}
fn transCStyleCastExprClass(
- rp: RestorePoint,
+ c: *Context,
scope: *Scope,
stmt: *const clang.CStyleCastExpr,
result_used: ResultUsed,
lrvalue: LRValue,
-) TransError!*ast.Node {
+) TransError!Node {
const sub_expr = stmt.getSubExpr();
const cast_node = (try transCCast(
- rp,
+ c,
scope,
stmt.getBeginLoc(),
stmt.getType(),
sub_expr.getType(),
- try transExpr(rp, scope, sub_expr, .used, lrvalue),
+ try transExpr(c, scope, sub_expr, .used, lrvalue),
));
- return maybeSuppressResult(rp, scope, result_used, cast_node);
+ return maybeSuppressResult(c, scope, result_used, cast_node);
}
fn transDeclStmtOne(