mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
stage2: VarDecl and FnProto take advantage of TrailerFlags API
These AST nodes now have a flags field and then a bunch of optional trailing objects. The end result is lower memory usage and consequently better performance. This is part of an ongoing effort to reduce the amount of memory parsed ASTs take up. Running `zig fmt` on the std lib: * cache-misses: 2,554,321 => 2,534,745 * instructions: 3,293,220,119 => 3,302,479,874 * peak memory: 74.0 MiB => 73.0 MiB Holding the entire std lib AST in memory at the same time: 93.9 MiB => 88.5 MiB
This commit is contained in:
parent
eac6280241
commit
804b51b179
@ -33,17 +33,30 @@ pub fn TrailerFlags(comptime Fields: type) type {
|
|||||||
self.bits |= 1 << field_index;
|
self.bits |= 1 << field_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(comptime names: anytype) Self {
|
/// `fields` is a struct with each field set to an optional value.
|
||||||
|
/// Missing fields are assumed to be `null`.
|
||||||
|
/// Only the non-null bits are observed and are used to set the flag bits.
|
||||||
|
pub fn init(fields: anytype) Self {
|
||||||
var self: Self = .{ .bits = 0 };
|
var self: Self = .{ .bits = 0 };
|
||||||
inline for (@typeInfo(@TypeOf(names)).Struct.fields) |field| {
|
inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| {
|
||||||
if (@field(names, field.name)) {
|
const opt: ?Field(field.name) = @field(fields, field.name);
|
||||||
const field_index = meta.fieldIndex(Fields, field.name).?;
|
const field_index = meta.fieldIndex(Fields, field.name).?;
|
||||||
self.bits |= 1 << field_index;
|
self.bits |= @as(Int, @boolToInt(opt != null)) << field_index;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `fields` is a struct with each field set to an optional value (same as `init`).
|
||||||
|
/// Missing fields are assumed to be `null`.
|
||||||
|
pub fn setMany(self: Self, p: [*]align(@alignOf(Fields)) u8, fields: anytype) void {
|
||||||
|
inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| {
|
||||||
|
const opt: ?Field(field.name) = @field(fields, field.name);
|
||||||
|
if (opt) |value| {
|
||||||
|
self.set(p, field.name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set(
|
pub fn set(
|
||||||
self: Self,
|
self: Self,
|
||||||
p: [*]align(@alignOf(Fields)) u8,
|
p: [*]align(@alignOf(Fields)) u8,
|
||||||
@ -54,11 +67,15 @@ pub fn TrailerFlags(comptime Fields: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn ptr(self: Self, p: [*]align(@alignOf(Fields)) u8, comptime name: []const u8) *Field(name) {
|
pub fn ptr(self: Self, p: [*]align(@alignOf(Fields)) u8, comptime name: []const u8) *Field(name) {
|
||||||
|
if (@sizeOf(Field(name)) == 0)
|
||||||
|
return undefined;
|
||||||
const off = self.offset(p, name);
|
const off = self.offset(p, name);
|
||||||
return @ptrCast(*Field(name), @alignCast(@alignOf(Field(name)), p + off));
|
return @ptrCast(*Field(name), @alignCast(@alignOf(Field(name)), p + off));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ptrConst(self: Self, p: [*]align(@alignOf(Fields)) const u8, comptime name: []const u8) *const Field(name) {
|
pub fn ptrConst(self: Self, p: [*]align(@alignOf(Fields)) const u8, comptime name: []const u8) *const Field(name) {
|
||||||
|
if (@sizeOf(Field(name)) == 0)
|
||||||
|
return undefined;
|
||||||
const off = self.offset(p, name);
|
const off = self.offset(p, name);
|
||||||
return @ptrCast(*const Field(name), @alignCast(@alignOf(Field(name)), p + off));
|
return @ptrCast(*const Field(name), @alignCast(@alignOf(Field(name)), p + off));
|
||||||
}
|
}
|
||||||
@ -85,6 +102,8 @@ pub fn TrailerFlags(comptime Fields: type) type {
|
|||||||
pub fn sizeInBytes(self: Self) usize {
|
pub fn sizeInBytes(self: Self) usize {
|
||||||
var off: usize = 0;
|
var off: usize = 0;
|
||||||
inline for (@typeInfo(Fields).Struct.fields) |field, i| {
|
inline for (@typeInfo(Fields).Struct.fields) |field, i| {
|
||||||
|
if (@sizeOf(field.field_type) == 0)
|
||||||
|
continue;
|
||||||
if ((self.bits & (1 << i)) != 0) {
|
if ((self.bits & (1 << i)) != 0) {
|
||||||
off = mem.alignForwardGeneric(usize, off, @alignOf(field.field_type));
|
off = mem.alignForwardGeneric(usize, off, @alignOf(field.field_type));
|
||||||
off += @sizeOf(field.field_type);
|
off += @sizeOf(field.field_type);
|
||||||
@ -103,7 +122,7 @@ test "TrailerFlags" {
|
|||||||
});
|
});
|
||||||
var flags = Flags.init(.{
|
var flags = Flags.init(.{
|
||||||
.b = true,
|
.b = true,
|
||||||
.c = true,
|
.c = 1234,
|
||||||
});
|
});
|
||||||
testing.expect(flags.sizeInBytes() == 16);
|
testing.expect(flags.sizeInBytes() == 16);
|
||||||
const slice = try testing.allocator.allocAdvanced(u8, 8, flags.sizeInBytes(), .exact);
|
const slice = try testing.allocator.allocAdvanced(u8, 8, flags.sizeInBytes(), .exact);
|
||||||
@ -115,4 +134,13 @@ test "TrailerFlags" {
|
|||||||
testing.expect(flags.get(slice.ptr, "a") == null);
|
testing.expect(flags.get(slice.ptr, "a") == null);
|
||||||
testing.expect(!flags.get(slice.ptr, "b").?);
|
testing.expect(!flags.get(slice.ptr, "b").?);
|
||||||
testing.expect(flags.get(slice.ptr, "c").? == 12345678);
|
testing.expect(flags.get(slice.ptr, "c").? == 12345678);
|
||||||
|
|
||||||
|
flags.setMany(slice.ptr, .{
|
||||||
|
.b = true,
|
||||||
|
.c = 5678,
|
||||||
|
});
|
||||||
|
|
||||||
|
testing.expect(flags.get(slice.ptr, "a") == null);
|
||||||
|
testing.expect(flags.get(slice.ptr, "b").?);
|
||||||
|
testing.expect(flags.get(slice.ptr, "c").? == 5678);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -675,42 +675,84 @@ pub const Node = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Trailed in memory by possibly many things, with each optional thing
|
||||||
|
/// determined by a bit in `trailer_flags`.
|
||||||
pub const VarDecl = struct {
|
pub const VarDecl = struct {
|
||||||
base: Node = Node{ .id = .VarDecl },
|
base: Node = Node{ .id = .VarDecl },
|
||||||
doc_comments: ?*DocComment,
|
trailer_flags: TrailerFlags,
|
||||||
visib_token: ?TokenIndex,
|
|
||||||
thread_local_token: ?TokenIndex,
|
|
||||||
name_token: TokenIndex,
|
|
||||||
eq_token: ?TokenIndex,
|
|
||||||
mut_token: TokenIndex,
|
mut_token: TokenIndex,
|
||||||
comptime_token: ?TokenIndex,
|
name_token: TokenIndex,
|
||||||
extern_export_token: ?TokenIndex,
|
|
||||||
lib_name: ?*Node,
|
|
||||||
type_node: ?*Node,
|
|
||||||
align_node: ?*Node,
|
|
||||||
section_node: ?*Node,
|
|
||||||
init_node: ?*Node,
|
|
||||||
semicolon_token: TokenIndex,
|
semicolon_token: TokenIndex,
|
||||||
|
|
||||||
|
pub const TrailerFlags = std.meta.TrailerFlags(struct {
|
||||||
|
doc_comments: *DocComment,
|
||||||
|
visib_token: TokenIndex,
|
||||||
|
thread_local_token: TokenIndex,
|
||||||
|
eq_token: TokenIndex,
|
||||||
|
comptime_token: TokenIndex,
|
||||||
|
extern_export_token: TokenIndex,
|
||||||
|
lib_name: *Node,
|
||||||
|
type_node: *Node,
|
||||||
|
align_node: *Node,
|
||||||
|
section_node: *Node,
|
||||||
|
init_node: *Node,
|
||||||
|
});
|
||||||
|
|
||||||
|
pub const RequiredFields = struct {
|
||||||
|
mut_token: TokenIndex,
|
||||||
|
name_token: TokenIndex,
|
||||||
|
semicolon_token: TokenIndex,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn getTrailer(self: *const VarDecl, comptime name: []const u8) ?TrailerFlags.Field(name) {
|
||||||
|
const trailers_start = @ptrCast([*]const u8, self) + @sizeOf(VarDecl);
|
||||||
|
return self.trailer_flags.get(trailers_start, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setTrailer(self: *VarDecl, comptime name: []const u8, value: TrailerFlags.Field(name)) void {
|
||||||
|
const trailers_start = @ptrCast([*]u8, self) + @sizeOf(VarDecl);
|
||||||
|
self.trailer_flags.set(trailers_start, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(allocator: *mem.Allocator, required: RequiredFields, trailers: anytype) !*VarDecl {
|
||||||
|
const trailer_flags = TrailerFlags.init(trailers);
|
||||||
|
const bytes = try allocator.alignedAlloc(u8, @alignOf(VarDecl), sizeInBytes(trailer_flags));
|
||||||
|
const var_decl = @ptrCast(*VarDecl, bytes.ptr);
|
||||||
|
var_decl.* = .{
|
||||||
|
.trailer_flags = trailer_flags,
|
||||||
|
.mut_token = required.mut_token,
|
||||||
|
.name_token = required.name_token,
|
||||||
|
.semicolon_token = required.semicolon_token,
|
||||||
|
};
|
||||||
|
const trailers_start = bytes.ptr + @sizeOf(VarDecl);
|
||||||
|
trailer_flags.setMany(trailers_start, trailers);
|
||||||
|
return var_decl;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *VarDecl, allocator: *mem.Allocator) void {
|
||||||
|
const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.trailer_flags)];
|
||||||
|
allocator.free(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iterate(self: *const VarDecl, index: usize) ?*Node {
|
pub fn iterate(self: *const VarDecl, index: usize) ?*Node {
|
||||||
var i = index;
|
var i = index;
|
||||||
|
|
||||||
if (self.type_node) |type_node| {
|
if (self.getTrailer("type_node")) |type_node| {
|
||||||
if (i < 1) return type_node;
|
if (i < 1) return type_node;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.align_node) |align_node| {
|
if (self.getTrailer("align_node")) |align_node| {
|
||||||
if (i < 1) return align_node;
|
if (i < 1) return align_node;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.section_node) |section_node| {
|
if (self.getTrailer("section_node")) |section_node| {
|
||||||
if (i < 1) return section_node;
|
if (i < 1) return section_node;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.init_node) |init_node| {
|
if (self.getTrailer("init_node")) |init_node| {
|
||||||
if (i < 1) return init_node;
|
if (i < 1) return init_node;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
@ -719,17 +761,21 @@ pub const Node = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn firstToken(self: *const VarDecl) TokenIndex {
|
pub fn firstToken(self: *const VarDecl) TokenIndex {
|
||||||
if (self.visib_token) |visib_token| return visib_token;
|
if (self.getTrailer("visib_token")) |visib_token| return visib_token;
|
||||||
if (self.thread_local_token) |thread_local_token| return thread_local_token;
|
if (self.getTrailer("thread_local_token")) |thread_local_token| return thread_local_token;
|
||||||
if (self.comptime_token) |comptime_token| return comptime_token;
|
if (self.getTrailer("comptime_token")) |comptime_token| return comptime_token;
|
||||||
if (self.extern_export_token) |extern_export_token| return extern_export_token;
|
if (self.getTrailer("extern_export_token")) |extern_export_token| return extern_export_token;
|
||||||
assert(self.lib_name == null);
|
assert(self.getTrailer("lib_name") == null);
|
||||||
return self.mut_token;
|
return self.mut_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lastToken(self: *const VarDecl) TokenIndex {
|
pub fn lastToken(self: *const VarDecl) TokenIndex {
|
||||||
return self.semicolon_token;
|
return self.semicolon_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sizeInBytes(trailer_flags: TrailerFlags) usize {
|
||||||
|
return @sizeOf(VarDecl) + trailer_flags.sizeInBytes();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Use = struct {
|
pub const Use = struct {
|
||||||
@ -972,25 +1018,34 @@ pub const Node = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// The params are directly after the FnProto in memory.
|
/// The params are directly after the FnProto in memory.
|
||||||
/// TODO have a flags field for the optional nodes, and have them appended
|
/// Next, each optional thing determined by a bit in `trailer_flags`.
|
||||||
/// before or after the parameters in memory.
|
|
||||||
pub const FnProto = struct {
|
pub const FnProto = struct {
|
||||||
base: Node = Node{ .id = .FnProto },
|
base: Node = Node{ .id = .FnProto },
|
||||||
doc_comments: ?*DocComment,
|
trailer_flags: TrailerFlags,
|
||||||
visib_token: ?TokenIndex,
|
|
||||||
fn_token: TokenIndex,
|
fn_token: TokenIndex,
|
||||||
name_token: ?TokenIndex,
|
|
||||||
params_len: NodeIndex,
|
params_len: NodeIndex,
|
||||||
return_type: ReturnType,
|
return_type: ReturnType,
|
||||||
var_args_token: ?TokenIndex,
|
|
||||||
extern_export_inline_token: ?TokenIndex,
|
pub const TrailerFlags = std.meta.TrailerFlags(struct {
|
||||||
body_node: ?*Node,
|
doc_comments: *DocComment,
|
||||||
lib_name: ?*Node, // populated if this is an extern declaration
|
body_node: *Node,
|
||||||
align_expr: ?*Node, // populated if align(A) is present
|
lib_name: *Node, // populated if this is an extern declaration
|
||||||
section_expr: ?*Node, // populated if linksection(A) is present
|
align_expr: *Node, // populated if align(A) is present
|
||||||
callconv_expr: ?*Node, // populated if callconv(A) is present
|
section_expr: *Node, // populated if linksection(A) is present
|
||||||
is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is
|
callconv_expr: *Node, // populated if callconv(A) is present
|
||||||
is_async: bool = false, // TODO: remove once async fn rewriting is
|
visib_token: TokenIndex,
|
||||||
|
name_token: TokenIndex,
|
||||||
|
var_args_token: TokenIndex,
|
||||||
|
extern_export_inline_token: TokenIndex,
|
||||||
|
is_extern_prototype: void, // TODO: Remove once extern fn rewriting is
|
||||||
|
is_async: void, // TODO: remove once async fn rewriting is
|
||||||
|
});
|
||||||
|
|
||||||
|
pub const RequiredFields = struct {
|
||||||
|
fn_token: TokenIndex,
|
||||||
|
params_len: NodeIndex,
|
||||||
|
return_type: ReturnType,
|
||||||
|
};
|
||||||
|
|
||||||
pub const ReturnType = union(enum) {
|
pub const ReturnType = union(enum) {
|
||||||
Explicit: *Node,
|
Explicit: *Node,
|
||||||
@ -1007,7 +1062,6 @@ pub const Node = struct {
|
|||||||
|
|
||||||
pub const ParamType = union(enum) {
|
pub const ParamType = union(enum) {
|
||||||
any_type: *Node,
|
any_type: *Node,
|
||||||
var_args: TokenIndex,
|
|
||||||
type_expr: *Node,
|
type_expr: *Node,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1016,7 +1070,6 @@ pub const Node = struct {
|
|||||||
|
|
||||||
if (i < 1) {
|
if (i < 1) {
|
||||||
switch (self.param_type) {
|
switch (self.param_type) {
|
||||||
.var_args => return null,
|
|
||||||
.any_type, .type_expr => |node| return node,
|
.any_type, .type_expr => |node| return node,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1030,34 +1083,79 @@ pub const Node = struct {
|
|||||||
if (self.noalias_token) |noalias_token| return noalias_token;
|
if (self.noalias_token) |noalias_token| return noalias_token;
|
||||||
if (self.name_token) |name_token| return name_token;
|
if (self.name_token) |name_token| return name_token;
|
||||||
switch (self.param_type) {
|
switch (self.param_type) {
|
||||||
.var_args => |tok| return tok,
|
|
||||||
.any_type, .type_expr => |node| return node.firstToken(),
|
.any_type, .type_expr => |node| return node.firstToken(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lastToken(self: *const ParamDecl) TokenIndex {
|
pub fn lastToken(self: *const ParamDecl) TokenIndex {
|
||||||
switch (self.param_type) {
|
switch (self.param_type) {
|
||||||
.var_args => |tok| return tok,
|
|
||||||
.any_type, .type_expr => |node| return node.lastToken(),
|
.any_type, .type_expr => |node| return node.lastToken(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// After this the caller must initialize the params list.
|
/// For debugging purposes.
|
||||||
pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*FnProto {
|
pub fn dump(self: *const FnProto) void {
|
||||||
const bytes = try allocator.alignedAlloc(u8, @alignOf(FnProto), sizeInBytes(params_len));
|
const trailers_start = @alignCast(
|
||||||
return @ptrCast(*FnProto, bytes.ptr);
|
@alignOf(ParamDecl),
|
||||||
|
@ptrCast([*]const u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len,
|
||||||
|
);
|
||||||
|
std.debug.print("{*} flags: {b} name_token: {} {*} params_len: {}\n", .{
|
||||||
|
self,
|
||||||
|
self.trailer_flags.bits,
|
||||||
|
self.getTrailer("name_token"),
|
||||||
|
self.trailer_flags.ptrConst(trailers_start, "name_token"),
|
||||||
|
self.params_len,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free(self: *FnProto, allocator: *mem.Allocator) void {
|
pub fn getTrailer(self: *const FnProto, comptime name: []const u8) ?TrailerFlags.Field(name) {
|
||||||
const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)];
|
const trailers_start = @alignCast(
|
||||||
|
@alignOf(ParamDecl),
|
||||||
|
@ptrCast([*]const u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len,
|
||||||
|
);
|
||||||
|
return self.trailer_flags.get(trailers_start, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setTrailer(self: *FnProto, comptime name: []const u8, value: TrailerFlags.Field(name)) void {
|
||||||
|
const trailers_start = @alignCast(
|
||||||
|
@alignOf(ParamDecl),
|
||||||
|
@ptrCast([*]u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len,
|
||||||
|
);
|
||||||
|
self.trailer_flags.set(trailers_start, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// After this the caller must initialize the params list.
|
||||||
|
pub fn create(allocator: *mem.Allocator, required: RequiredFields, trailers: anytype) !*FnProto {
|
||||||
|
const trailer_flags = TrailerFlags.init(trailers);
|
||||||
|
const bytes = try allocator.alignedAlloc(u8, @alignOf(FnProto), sizeInBytes(
|
||||||
|
required.params_len,
|
||||||
|
trailer_flags,
|
||||||
|
));
|
||||||
|
const fn_proto = @ptrCast(*FnProto, bytes.ptr);
|
||||||
|
fn_proto.* = .{
|
||||||
|
.trailer_flags = trailer_flags,
|
||||||
|
.fn_token = required.fn_token,
|
||||||
|
.params_len = required.params_len,
|
||||||
|
.return_type = required.return_type,
|
||||||
|
};
|
||||||
|
const trailers_start = @alignCast(
|
||||||
|
@alignOf(ParamDecl),
|
||||||
|
bytes.ptr + @sizeOf(FnProto) + @sizeOf(ParamDecl) * required.params_len,
|
||||||
|
);
|
||||||
|
trailer_flags.setMany(trailers_start, trailers);
|
||||||
|
return fn_proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *FnProto, allocator: *mem.Allocator) void {
|
||||||
|
const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len, self.trailer_flags)];
|
||||||
allocator.free(bytes);
|
allocator.free(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iterate(self: *const FnProto, index: usize) ?*Node {
|
pub fn iterate(self: *const FnProto, index: usize) ?*Node {
|
||||||
var i = index;
|
var i = index;
|
||||||
|
|
||||||
if (self.lib_name) |lib_name| {
|
if (self.getTrailer("lib_name")) |lib_name| {
|
||||||
if (i < 1) return lib_name;
|
if (i < 1) return lib_name;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
@ -1066,23 +1164,21 @@ pub const Node = struct {
|
|||||||
0
|
0
|
||||||
else switch (self.paramsConst()[self.params_len - 1].param_type) {
|
else switch (self.paramsConst()[self.params_len - 1].param_type) {
|
||||||
.any_type, .type_expr => self.params_len,
|
.any_type, .type_expr => self.params_len,
|
||||||
.var_args => self.params_len - 1,
|
|
||||||
};
|
};
|
||||||
if (i < params_len) {
|
if (i < params_len) {
|
||||||
switch (self.paramsConst()[i].param_type) {
|
switch (self.paramsConst()[i].param_type) {
|
||||||
.any_type => |n| return n,
|
.any_type => |n| return n,
|
||||||
.var_args => unreachable,
|
|
||||||
.type_expr => |n| return n,
|
.type_expr => |n| return n,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i -= params_len;
|
i -= params_len;
|
||||||
|
|
||||||
if (self.align_expr) |align_expr| {
|
if (self.getTrailer("align_expr")) |align_expr| {
|
||||||
if (i < 1) return align_expr;
|
if (i < 1) return align_expr;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.section_expr) |section_expr| {
|
if (self.getTrailer("section_expr")) |section_expr| {
|
||||||
if (i < 1) return section_expr;
|
if (i < 1) return section_expr;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
@ -1095,7 +1191,7 @@ pub const Node = struct {
|
|||||||
.Invalid => {},
|
.Invalid => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.body_node) |body_node| {
|
if (self.getTrailer("body_node")) |body_node| {
|
||||||
if (i < 1) return body_node;
|
if (i < 1) return body_node;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
@ -1104,14 +1200,14 @@ pub const Node = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn firstToken(self: *const FnProto) TokenIndex {
|
pub fn firstToken(self: *const FnProto) TokenIndex {
|
||||||
if (self.visib_token) |visib_token| return visib_token;
|
if (self.getTrailer("visib_token")) |visib_token| return visib_token;
|
||||||
if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
|
if (self.getTrailer("extern_export_inline_token")) |extern_export_inline_token| return extern_export_inline_token;
|
||||||
assert(self.lib_name == null);
|
assert(self.getTrailer("lib_name") == null);
|
||||||
return self.fn_token;
|
return self.fn_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lastToken(self: *const FnProto) TokenIndex {
|
pub fn lastToken(self: *const FnProto) TokenIndex {
|
||||||
if (self.body_node) |body_node| return body_node.lastToken();
|
if (self.getTrailer("body_node")) |body_node| return body_node.lastToken();
|
||||||
switch (self.return_type) {
|
switch (self.return_type) {
|
||||||
.Explicit, .InferErrorSet => |node| return node.lastToken(),
|
.Explicit, .InferErrorSet => |node| return node.lastToken(),
|
||||||
.Invalid => |tok| return tok,
|
.Invalid => |tok| return tok,
|
||||||
@ -1119,17 +1215,17 @@ pub const Node = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn params(self: *FnProto) []ParamDecl {
|
pub fn params(self: *FnProto) []ParamDecl {
|
||||||
const decls_start = @ptrCast([*]u8, self) + @sizeOf(FnProto);
|
const params_start = @ptrCast([*]u8, self) + @sizeOf(FnProto);
|
||||||
return @ptrCast([*]ParamDecl, decls_start)[0..self.params_len];
|
return @ptrCast([*]ParamDecl, params_start)[0..self.params_len];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paramsConst(self: *const FnProto) []const ParamDecl {
|
pub fn paramsConst(self: *const FnProto) []const ParamDecl {
|
||||||
const decls_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto);
|
const params_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto);
|
||||||
return @ptrCast([*]const ParamDecl, decls_start)[0..self.params_len];
|
return @ptrCast([*]const ParamDecl, params_start)[0..self.params_len];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sizeInBytes(params_len: NodeIndex) usize {
|
fn sizeInBytes(params_len: NodeIndex, trailer_flags: TrailerFlags) usize {
|
||||||
return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len);
|
return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len) + trailer_flags.sizeInBytes();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2829,6 +2925,9 @@ pub const Node = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// TODO remove from the Node base struct
|
||||||
|
/// TODO actually maybe remove entirely in favor of iterating backward from Node.firstToken()
|
||||||
|
/// and forwards to find same-line doc comments.
|
||||||
pub const DocComment = struct {
|
pub const DocComment = struct {
|
||||||
base: Node = Node{ .id = .DocComment },
|
base: Node = Node{ .id = .DocComment },
|
||||||
/// Points to the first doc comment token. API users are expected to iterate over the
|
/// Points to the first doc comment token. API users are expected to iterate over the
|
||||||
|
|||||||
@ -150,7 +150,7 @@ const Parser = struct {
|
|||||||
|
|
||||||
const visib_token = p.eatToken(.Keyword_pub);
|
const visib_token = p.eatToken(.Keyword_pub);
|
||||||
|
|
||||||
if (p.parseTopLevelDecl() catch |err| switch (err) {
|
if (p.parseTopLevelDecl(doc_comments, visib_token) catch |err| switch (err) {
|
||||||
error.OutOfMemory => return error.OutOfMemory,
|
error.OutOfMemory => return error.OutOfMemory,
|
||||||
error.ParseError => {
|
error.ParseError => {
|
||||||
p.findNextContainerMember();
|
p.findNextContainerMember();
|
||||||
@ -160,30 +160,7 @@ const Parser = struct {
|
|||||||
if (field_state == .seen) {
|
if (field_state == .seen) {
|
||||||
field_state = .{ .end = visib_token orelse node.firstToken() };
|
field_state = .{ .end = visib_token orelse node.firstToken() };
|
||||||
}
|
}
|
||||||
switch (node.id) {
|
|
||||||
.FnProto => {
|
|
||||||
node.cast(Node.FnProto).?.doc_comments = doc_comments;
|
|
||||||
node.cast(Node.FnProto).?.visib_token = visib_token;
|
|
||||||
},
|
|
||||||
.VarDecl => {
|
|
||||||
node.cast(Node.VarDecl).?.doc_comments = doc_comments;
|
|
||||||
node.cast(Node.VarDecl).?.visib_token = visib_token;
|
|
||||||
},
|
|
||||||
.Use => {
|
|
||||||
node.cast(Node.Use).?.doc_comments = doc_comments;
|
|
||||||
node.cast(Node.Use).?.visib_token = visib_token;
|
|
||||||
},
|
|
||||||
else => unreachable,
|
|
||||||
}
|
|
||||||
try list.append(node);
|
try list.append(node);
|
||||||
if (try p.parseAppendedDocComment(node.lastToken())) |appended_comment| {
|
|
||||||
switch (node.id) {
|
|
||||||
.FnProto => {},
|
|
||||||
.VarDecl => node.cast(Node.VarDecl).?.doc_comments = appended_comment,
|
|
||||||
.Use => node.cast(Node.Use).?.doc_comments = appended_comment,
|
|
||||||
else => unreachable,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +394,7 @@ const Parser = struct {
|
|||||||
/// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block)
|
/// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block)
|
||||||
/// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
|
/// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
|
||||||
/// / KEYWORD_usingnamespace Expr SEMICOLON
|
/// / KEYWORD_usingnamespace Expr SEMICOLON
|
||||||
fn parseTopLevelDecl(p: *Parser) !?*Node {
|
fn parseTopLevelDecl(p: *Parser, doc_comments: ?*Node.DocComment, visib_token: ?TokenIndex) !?*Node {
|
||||||
var lib_name: ?*Node = null;
|
var lib_name: ?*Node = null;
|
||||||
const extern_export_inline_token = blk: {
|
const extern_export_inline_token = blk: {
|
||||||
if (p.eatToken(.Keyword_export)) |token| break :blk token;
|
if (p.eatToken(.Keyword_export)) |token| break :blk token;
|
||||||
@ -430,20 +407,12 @@ const Parser = struct {
|
|||||||
break :blk null;
|
break :blk null;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (try p.parseFnProto()) |node| {
|
if (try p.parseFnProto(.top_level, .{
|
||||||
const fn_node = node.cast(Node.FnProto).?;
|
.doc_comments = doc_comments,
|
||||||
fn_node.*.extern_export_inline_token = extern_export_inline_token;
|
.visib_token = visib_token,
|
||||||
fn_node.*.lib_name = lib_name;
|
.extern_export_inline_token = extern_export_inline_token,
|
||||||
if (p.eatToken(.Semicolon)) |_| return node;
|
.lib_name = lib_name,
|
||||||
|
})) |node| {
|
||||||
if (try p.expectNodeRecoverable(parseBlock, .{
|
|
||||||
// since parseBlock only return error.ParseError on
|
|
||||||
// a missing '}' we can assume this function was
|
|
||||||
// supposed to end here.
|
|
||||||
.ExpectedSemiOrLBrace = .{ .token = p.tok_i },
|
|
||||||
})) |body_node| {
|
|
||||||
fn_node.body_node = body_node;
|
|
||||||
}
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,12 +429,13 @@ const Parser = struct {
|
|||||||
|
|
||||||
const thread_local_token = p.eatToken(.Keyword_threadlocal);
|
const thread_local_token = p.eatToken(.Keyword_threadlocal);
|
||||||
|
|
||||||
if (try p.parseVarDecl()) |node| {
|
if (try p.parseVarDecl(.{
|
||||||
var var_decl = node.cast(Node.VarDecl).?;
|
.doc_comments = doc_comments,
|
||||||
var_decl.*.thread_local_token = thread_local_token;
|
.visib_token = visib_token,
|
||||||
var_decl.*.comptime_token = null;
|
.thread_local_token = thread_local_token,
|
||||||
var_decl.*.extern_export_token = extern_export_inline_token;
|
.extern_export_token = extern_export_inline_token,
|
||||||
var_decl.*.lib_name = lib_name;
|
.lib_name = lib_name,
|
||||||
|
})) |node| {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,21 +455,41 @@ const Parser = struct {
|
|||||||
return error.ParseError;
|
return error.ParseError;
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.parseUse();
|
const use_token = p.eatToken(.Keyword_usingnamespace) orelse return null;
|
||||||
|
const expr = try p.expectNode(parseExpr, .{
|
||||||
|
.ExpectedExpr = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
const semicolon_token = try p.expectToken(.Semicolon);
|
||||||
|
|
||||||
|
const node = try p.arena.allocator.create(Node.Use);
|
||||||
|
node.* = .{
|
||||||
|
.doc_comments = doc_comments orelse try p.parseAppendedDocComment(semicolon_token),
|
||||||
|
.visib_token = visib_token,
|
||||||
|
.use_token = use_token,
|
||||||
|
.expr = expr,
|
||||||
|
.semicolon_token = semicolon_token,
|
||||||
|
};
|
||||||
|
|
||||||
|
return &node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr)
|
/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr)
|
||||||
fn parseFnProto(p: *Parser) !?*Node {
|
fn parseFnProto(p: *Parser, level: enum { top_level, as_type }, fields: struct {
|
||||||
|
doc_comments: ?*Node.DocComment = null,
|
||||||
|
visib_token: ?TokenIndex = null,
|
||||||
|
extern_export_inline_token: ?TokenIndex = null,
|
||||||
|
lib_name: ?*Node = null,
|
||||||
|
}) !?*Node {
|
||||||
// TODO: Remove once extern/async fn rewriting is
|
// TODO: Remove once extern/async fn rewriting is
|
||||||
var is_async = false;
|
var is_async: ?void = null;
|
||||||
var is_extern = false;
|
var is_extern_prototype: ?void = null;
|
||||||
const cc_token: ?TokenIndex = blk: {
|
const cc_token: ?TokenIndex = blk: {
|
||||||
if (p.eatToken(.Keyword_extern)) |token| {
|
if (p.eatToken(.Keyword_extern)) |token| {
|
||||||
is_extern = true;
|
is_extern_prototype = {};
|
||||||
break :blk token;
|
break :blk token;
|
||||||
}
|
}
|
||||||
if (p.eatToken(.Keyword_async)) |token| {
|
if (p.eatToken(.Keyword_async)) |token| {
|
||||||
is_async = true;
|
is_async = {};
|
||||||
break :blk token;
|
break :blk token;
|
||||||
}
|
}
|
||||||
break :blk null;
|
break :blk null;
|
||||||
@ -513,6 +503,7 @@ const Parser = struct {
|
|||||||
const lparen = try p.expectToken(.LParen);
|
const lparen = try p.expectToken(.LParen);
|
||||||
const params = try p.parseParamDeclList();
|
const params = try p.parseParamDeclList();
|
||||||
defer p.gpa.free(params);
|
defer p.gpa.free(params);
|
||||||
|
const var_args_token = p.eatToken(.Ellipsis3);
|
||||||
const rparen = try p.expectToken(.RParen);
|
const rparen = try p.expectToken(.RParen);
|
||||||
const align_expr = try p.parseByteAlign();
|
const align_expr = try p.parseByteAlign();
|
||||||
const section_expr = try p.parseLinkSection();
|
const section_expr = try p.parseLinkSection();
|
||||||
@ -535,37 +526,53 @@ const Parser = struct {
|
|||||||
else
|
else
|
||||||
R{ .Explicit = return_type_expr.? };
|
R{ .Explicit = return_type_expr.? };
|
||||||
|
|
||||||
const var_args_token = if (params.len > 0) blk: {
|
const body_node: ?*Node = switch (level) {
|
||||||
const param_type = params[params.len - 1].param_type;
|
.top_level => blk: {
|
||||||
break :blk if (param_type == .var_args) param_type.var_args else null;
|
if (p.eatToken(.Semicolon)) |_| {
|
||||||
} else
|
break :blk null;
|
||||||
null;
|
}
|
||||||
|
break :blk try p.expectNodeRecoverable(parseBlock, .{
|
||||||
|
// Since parseBlock only return error.ParseError on
|
||||||
|
// a missing '}' we can assume this function was
|
||||||
|
// supposed to end here.
|
||||||
|
.ExpectedSemiOrLBrace = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.as_type => null,
|
||||||
|
};
|
||||||
|
|
||||||
const fn_proto_node = try Node.FnProto.alloc(&p.arena.allocator, params.len);
|
const fn_proto_node = try Node.FnProto.create(&p.arena.allocator, .{
|
||||||
fn_proto_node.* = .{
|
|
||||||
.doc_comments = null,
|
|
||||||
.visib_token = null,
|
|
||||||
.fn_token = fn_token,
|
|
||||||
.name_token = name_token,
|
|
||||||
.params_len = params.len,
|
.params_len = params.len,
|
||||||
|
.fn_token = fn_token,
|
||||||
.return_type = return_type,
|
.return_type = return_type,
|
||||||
|
}, .{
|
||||||
|
.doc_comments = fields.doc_comments,
|
||||||
|
.visib_token = fields.visib_token,
|
||||||
|
.name_token = name_token,
|
||||||
.var_args_token = var_args_token,
|
.var_args_token = var_args_token,
|
||||||
.extern_export_inline_token = null,
|
.extern_export_inline_token = fields.extern_export_inline_token,
|
||||||
.body_node = null,
|
.body_node = body_node,
|
||||||
.lib_name = null,
|
.lib_name = fields.lib_name,
|
||||||
.align_expr = align_expr,
|
.align_expr = align_expr,
|
||||||
.section_expr = section_expr,
|
.section_expr = section_expr,
|
||||||
.callconv_expr = callconv_expr,
|
.callconv_expr = callconv_expr,
|
||||||
.is_extern_prototype = is_extern,
|
.is_extern_prototype = is_extern_prototype,
|
||||||
.is_async = is_async,
|
.is_async = is_async,
|
||||||
};
|
});
|
||||||
std.mem.copy(Node.FnProto.ParamDecl, fn_proto_node.params(), params);
|
std.mem.copy(Node.FnProto.ParamDecl, fn_proto_node.params(), params);
|
||||||
|
|
||||||
return &fn_proto_node.base;
|
return &fn_proto_node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
|
/// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
|
||||||
fn parseVarDecl(p: *Parser) !?*Node {
|
fn parseVarDecl(p: *Parser, fields: struct {
|
||||||
|
doc_comments: ?*Node.DocComment = null,
|
||||||
|
visib_token: ?TokenIndex = null,
|
||||||
|
thread_local_token: ?TokenIndex = null,
|
||||||
|
extern_export_token: ?TokenIndex = null,
|
||||||
|
lib_name: ?*Node = null,
|
||||||
|
comptime_token: ?TokenIndex = null,
|
||||||
|
}) !?*Node {
|
||||||
const mut_token = p.eatToken(.Keyword_const) orelse
|
const mut_token = p.eatToken(.Keyword_const) orelse
|
||||||
p.eatToken(.Keyword_var) orelse
|
p.eatToken(.Keyword_var) orelse
|
||||||
return null;
|
return null;
|
||||||
@ -587,23 +594,25 @@ const Parser = struct {
|
|||||||
} else null;
|
} else null;
|
||||||
const semicolon_token = try p.expectToken(.Semicolon);
|
const semicolon_token = try p.expectToken(.Semicolon);
|
||||||
|
|
||||||
const node = try p.arena.allocator.create(Node.VarDecl);
|
const doc_comments = fields.doc_comments orelse try p.parseAppendedDocComment(semicolon_token);
|
||||||
node.* = .{
|
|
||||||
.doc_comments = null,
|
const node = try Node.VarDecl.create(&p.arena.allocator, .{
|
||||||
.visib_token = null,
|
|
||||||
.thread_local_token = null,
|
|
||||||
.name_token = name_token,
|
|
||||||
.eq_token = eq_token,
|
|
||||||
.mut_token = mut_token,
|
.mut_token = mut_token,
|
||||||
.comptime_token = null,
|
.name_token = name_token,
|
||||||
.extern_export_token = null,
|
.semicolon_token = semicolon_token,
|
||||||
.lib_name = null,
|
}, .{
|
||||||
|
.doc_comments = doc_comments,
|
||||||
|
.visib_token = fields.visib_token,
|
||||||
|
.thread_local_token = fields.thread_local_token,
|
||||||
|
.eq_token = eq_token,
|
||||||
|
.comptime_token = fields.comptime_token,
|
||||||
|
.extern_export_token = fields.extern_export_token,
|
||||||
|
.lib_name = fields.lib_name,
|
||||||
.type_node = type_node,
|
.type_node = type_node,
|
||||||
.align_node = align_node,
|
.align_node = align_node,
|
||||||
.section_node = section_node,
|
.section_node = section_node,
|
||||||
.init_node = init_node,
|
.init_node = init_node,
|
||||||
.semicolon_token = semicolon_token,
|
});
|
||||||
};
|
|
||||||
return &node.base;
|
return &node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -663,10 +672,9 @@ const Parser = struct {
|
|||||||
fn parseStatement(p: *Parser) Error!?*Node {
|
fn parseStatement(p: *Parser) Error!?*Node {
|
||||||
const comptime_token = p.eatToken(.Keyword_comptime);
|
const comptime_token = p.eatToken(.Keyword_comptime);
|
||||||
|
|
||||||
const var_decl_node = try p.parseVarDecl();
|
if (try p.parseVarDecl(.{
|
||||||
if (var_decl_node) |node| {
|
.comptime_token = comptime_token,
|
||||||
const var_decl = node.cast(Node.VarDecl).?;
|
})) |node| {
|
||||||
var_decl.comptime_token = comptime_token;
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1527,7 +1535,7 @@ const Parser = struct {
|
|||||||
if (try p.parseAnonLiteral()) |node| return node;
|
if (try p.parseAnonLiteral()) |node| return node;
|
||||||
if (try p.parseErrorSetDecl()) |node| return node;
|
if (try p.parseErrorSetDecl()) |node| return node;
|
||||||
if (try p.parseFloatLiteral()) |node| return node;
|
if (try p.parseFloatLiteral()) |node| return node;
|
||||||
if (try p.parseFnProto()) |node| return node;
|
if (try p.parseFnProto(.as_type, .{})) |node| return node;
|
||||||
if (try p.parseGroupedExpr()) |node| return node;
|
if (try p.parseGroupedExpr()) |node| return node;
|
||||||
if (try p.parseLabeledTypeExpr()) |node| return node;
|
if (try p.parseLabeledTypeExpr()) |node| return node;
|
||||||
if (try p.parseIdentifier()) |node| return node;
|
if (try p.parseIdentifier()) |node| return node;
|
||||||
@ -2028,7 +2036,6 @@ const Parser = struct {
|
|||||||
// TODO cast from tuple to error union is broken
|
// TODO cast from tuple to error union is broken
|
||||||
const P = Node.FnProto.ParamDecl.ParamType;
|
const P = Node.FnProto.ParamDecl.ParamType;
|
||||||
if (try p.parseAnyType()) |node| return P{ .any_type = node };
|
if (try p.parseAnyType()) |node| return P{ .any_type = node };
|
||||||
if (p.eatToken(.Ellipsis3)) |token| return P{ .var_args = token };
|
|
||||||
if (try p.parseTypeExpr()) |node| return P{ .type_expr = node };
|
if (try p.parseTypeExpr()) |node| return P{ .type_expr = node };
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -3149,21 +3156,6 @@ const Parser = struct {
|
|||||||
return &node.base;
|
return &node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseUse(p: *Parser) !?*Node {
|
|
||||||
const token = p.eatToken(.Keyword_usingnamespace) orelse return null;
|
|
||||||
const node = try p.arena.allocator.create(Node.Use);
|
|
||||||
node.* = .{
|
|
||||||
.doc_comments = null,
|
|
||||||
.visib_token = null,
|
|
||||||
.use_token = token,
|
|
||||||
.expr = try p.expectNode(parseExpr, .{
|
|
||||||
.ExpectedExpr = .{ .token = p.tok_i },
|
|
||||||
}),
|
|
||||||
.semicolon_token = try p.expectToken(.Semicolon),
|
|
||||||
};
|
|
||||||
return &node.base;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// IfPrefix Body (KEYWORD_else Payload? Body)?
|
/// IfPrefix Body (KEYWORD_else Payload? Body)?
|
||||||
fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !?*Node {
|
fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !?*Node {
|
||||||
const node = (try p.parseIfPrefix()) orelse return null;
|
const node = (try p.parseIfPrefix()) orelse return null;
|
||||||
|
|||||||
@ -1,4 +1,32 @@
|
|||||||
const builtin = @import("builtin");
|
test "zig fmt: convert var to anytype" {
|
||||||
|
// TODO remove in next release cycle
|
||||||
|
try testTransform(
|
||||||
|
\\pub fn main(
|
||||||
|
\\ a: var,
|
||||||
|
\\ bar: var,
|
||||||
|
\\) void {}
|
||||||
|
,
|
||||||
|
\\pub fn main(
|
||||||
|
\\ a: anytype,
|
||||||
|
\\ bar: anytype,
|
||||||
|
\\) void {}
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "zig fmt: noasync to nosuspend" {
|
||||||
|
// TODO: remove this
|
||||||
|
try testTransform(
|
||||||
|
\\pub fn main() void {
|
||||||
|
\\ noasync call();
|
||||||
|
\\}
|
||||||
|
,
|
||||||
|
\\pub fn main() void {
|
||||||
|
\\ nosuspend call();
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
test "recovery: top level" {
|
test "recovery: top level" {
|
||||||
try testError(
|
try testError(
|
||||||
@ -3146,20 +3174,6 @@ test "zig fmt: hexadeciaml float literals with underscore separators" {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "zig fmt: noasync to nosuspend" {
|
|
||||||
// TODO: remove this
|
|
||||||
try testTransform(
|
|
||||||
\\pub fn main() void {
|
|
||||||
\\ noasync call();
|
|
||||||
\\}
|
|
||||||
,
|
|
||||||
\\pub fn main() void {
|
|
||||||
\\ nosuspend call();
|
|
||||||
\\}
|
|
||||||
\\
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "zig fmt: convert async fn into callconv(.Async)" {
|
test "zig fmt: convert async fn into callconv(.Async)" {
|
||||||
try testTransform(
|
try testTransform(
|
||||||
\\async fn foo() void {}
|
\\async fn foo() void {}
|
||||||
@ -3180,18 +3194,9 @@ test "zig fmt: convert extern fn proto into callconv(.C)" {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "zig fmt: convert var to anytype" {
|
test "zig fmt: C var args" {
|
||||||
// TODO remove in next release cycle
|
try testCanonical(
|
||||||
try testTransform(
|
\\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
|
||||||
\\pub fn main(
|
|
||||||
\\ a: var,
|
|
||||||
\\ bar: var,
|
|
||||||
\\) void {}
|
|
||||||
,
|
|
||||||
\\pub fn main(
|
|
||||||
\\ a: anytype,
|
|
||||||
\\ bar: anytype,
|
|
||||||
\\) void {}
|
|
||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -227,9 +227,9 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
|
|||||||
.FnProto => {
|
.FnProto => {
|
||||||
const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
|
const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
|
||||||
|
|
||||||
try renderDocComments(tree, stream, fn_proto, indent, start_col);
|
try renderDocComments(tree, stream, fn_proto, fn_proto.getTrailer("doc_comments"), indent, start_col);
|
||||||
|
|
||||||
if (fn_proto.body_node) |body_node| {
|
if (fn_proto.getTrailer("body_node")) |body_node| {
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, decl, .Space);
|
try renderExpression(allocator, stream, tree, indent, start_col, decl, .Space);
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, body_node, space);
|
try renderExpression(allocator, stream, tree, indent, start_col, body_node, space);
|
||||||
} else {
|
} else {
|
||||||
@ -252,14 +252,14 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
|
|||||||
.VarDecl => {
|
.VarDecl => {
|
||||||
const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
|
const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
|
||||||
|
|
||||||
try renderDocComments(tree, stream, var_decl, indent, start_col);
|
try renderDocComments(tree, stream, var_decl, var_decl.getTrailer("doc_comments"), indent, start_col);
|
||||||
try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);
|
try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);
|
||||||
},
|
},
|
||||||
|
|
||||||
.TestDecl => {
|
.TestDecl => {
|
||||||
const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
|
const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
|
||||||
|
|
||||||
try renderDocComments(tree, stream, test_decl, indent, start_col);
|
try renderDocComments(tree, stream, test_decl, test_decl.doc_comments, indent, start_col);
|
||||||
try renderToken(tree, stream, test_decl.test_token, indent, start_col, .Space);
|
try renderToken(tree, stream, test_decl.test_token, indent, start_col, .Space);
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, .Space);
|
try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, .Space);
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, space);
|
try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, space);
|
||||||
@ -268,7 +268,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
|
|||||||
.ContainerField => {
|
.ContainerField => {
|
||||||
const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl);
|
const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl);
|
||||||
|
|
||||||
try renderDocComments(tree, stream, field, indent, start_col);
|
try renderDocComments(tree, stream, field, field.doc_comments, indent, start_col);
|
||||||
if (field.comptime_token) |t| {
|
if (field.comptime_token) |t| {
|
||||||
try renderToken(tree, stream, t, indent, start_col, .Space); // comptime
|
try renderToken(tree, stream, t, indent, start_col, .Space); // comptime
|
||||||
}
|
}
|
||||||
@ -1409,7 +1409,7 @@ fn renderExpression(
|
|||||||
.ErrorTag => {
|
.ErrorTag => {
|
||||||
const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);
|
const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);
|
||||||
|
|
||||||
try renderDocComments(tree, stream, tag, indent, start_col);
|
try renderDocComments(tree, stream, tag, tag.doc_comments, indent, start_col);
|
||||||
return renderToken(tree, stream, tag.name_token, indent, start_col, space); // name
|
return renderToken(tree, stream, tag.name_token, indent, start_col, space); // name
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1483,23 +1483,23 @@ fn renderExpression(
|
|||||||
.FnProto => {
|
.FnProto => {
|
||||||
const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
|
const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
|
||||||
|
|
||||||
if (fn_proto.visib_token) |visib_token_index| {
|
if (fn_proto.getTrailer("visib_token")) |visib_token_index| {
|
||||||
const visib_token = tree.token_ids[visib_token_index];
|
const visib_token = tree.token_ids[visib_token_index];
|
||||||
assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
|
assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
|
||||||
|
|
||||||
try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub
|
try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
|
if (fn_proto.getTrailer("extern_export_inline_token")) |extern_export_inline_token| {
|
||||||
if (!fn_proto.is_extern_prototype)
|
if (fn_proto.getTrailer("is_extern_prototype") == null)
|
||||||
try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export/inline
|
try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export/inline
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fn_proto.lib_name) |lib_name| {
|
if (fn_proto.getTrailer("lib_name")) |lib_name| {
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space);
|
try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space);
|
||||||
}
|
}
|
||||||
|
|
||||||
const lparen = if (fn_proto.name_token) |name_token| blk: {
|
const lparen = if (fn_proto.getTrailer("name_token")) |name_token| blk: {
|
||||||
try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
|
try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
|
||||||
try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name
|
try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name
|
||||||
break :blk tree.nextToken(name_token);
|
break :blk tree.nextToken(name_token);
|
||||||
@ -1512,11 +1512,11 @@ fn renderExpression(
|
|||||||
const rparen = tree.prevToken(
|
const rparen = tree.prevToken(
|
||||||
// the first token for the annotation expressions is the left
|
// the first token for the annotation expressions is the left
|
||||||
// parenthesis, hence the need for two prevToken
|
// parenthesis, hence the need for two prevToken
|
||||||
if (fn_proto.align_expr) |align_expr|
|
if (fn_proto.getTrailer("align_expr")) |align_expr|
|
||||||
tree.prevToken(tree.prevToken(align_expr.firstToken()))
|
tree.prevToken(tree.prevToken(align_expr.firstToken()))
|
||||||
else if (fn_proto.section_expr) |section_expr|
|
else if (fn_proto.getTrailer("section_expr")) |section_expr|
|
||||||
tree.prevToken(tree.prevToken(section_expr.firstToken()))
|
tree.prevToken(tree.prevToken(section_expr.firstToken()))
|
||||||
else if (fn_proto.callconv_expr) |callconv_expr|
|
else if (fn_proto.getTrailer("callconv_expr")) |callconv_expr|
|
||||||
tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
|
tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
|
||||||
else switch (fn_proto.return_type) {
|
else switch (fn_proto.return_type) {
|
||||||
.Explicit => |node| node.firstToken(),
|
.Explicit => |node| node.firstToken(),
|
||||||
@ -1537,11 +1537,14 @@ fn renderExpression(
|
|||||||
for (fn_proto.params()) |param_decl, i| {
|
for (fn_proto.params()) |param_decl, i| {
|
||||||
try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None);
|
try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None);
|
||||||
|
|
||||||
if (i + 1 < fn_proto.params_len) {
|
if (i + 1 < fn_proto.params_len or fn_proto.getTrailer("var_args_token") != null) {
|
||||||
const comma = tree.nextToken(param_decl.lastToken());
|
const comma = tree.nextToken(param_decl.lastToken());
|
||||||
try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
|
try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
|
||||||
|
try renderToken(tree, stream, var_args_token, indent, start_col, Space.None);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// one param per line
|
// one param per line
|
||||||
const new_indent = indent + indent_delta;
|
const new_indent = indent + indent_delta;
|
||||||
@ -1551,12 +1554,16 @@ fn renderExpression(
|
|||||||
try stream.writeByteNTimes(' ', new_indent);
|
try stream.writeByteNTimes(' ', new_indent);
|
||||||
try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma);
|
try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma);
|
||||||
}
|
}
|
||||||
|
if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
|
||||||
|
try stream.writeByteNTimes(' ', new_indent);
|
||||||
|
try renderToken(tree, stream, var_args_token, new_indent, start_col, Space.Comma);
|
||||||
|
}
|
||||||
try stream.writeByteNTimes(' ', indent);
|
try stream.writeByteNTimes(' ', indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
|
try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
|
||||||
|
|
||||||
if (fn_proto.align_expr) |align_expr| {
|
if (fn_proto.getTrailer("align_expr")) |align_expr| {
|
||||||
const align_rparen = tree.nextToken(align_expr.lastToken());
|
const align_rparen = tree.nextToken(align_expr.lastToken());
|
||||||
const align_lparen = tree.prevToken(align_expr.firstToken());
|
const align_lparen = tree.prevToken(align_expr.firstToken());
|
||||||
const align_kw = tree.prevToken(align_lparen);
|
const align_kw = tree.prevToken(align_lparen);
|
||||||
@ -1567,7 +1574,7 @@ fn renderExpression(
|
|||||||
try renderToken(tree, stream, align_rparen, indent, start_col, Space.Space); // )
|
try renderToken(tree, stream, align_rparen, indent, start_col, Space.Space); // )
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fn_proto.section_expr) |section_expr| {
|
if (fn_proto.getTrailer("section_expr")) |section_expr| {
|
||||||
const section_rparen = tree.nextToken(section_expr.lastToken());
|
const section_rparen = tree.nextToken(section_expr.lastToken());
|
||||||
const section_lparen = tree.prevToken(section_expr.firstToken());
|
const section_lparen = tree.prevToken(section_expr.firstToken());
|
||||||
const section_kw = tree.prevToken(section_lparen);
|
const section_kw = tree.prevToken(section_lparen);
|
||||||
@ -1578,7 +1585,7 @@ fn renderExpression(
|
|||||||
try renderToken(tree, stream, section_rparen, indent, start_col, Space.Space); // )
|
try renderToken(tree, stream, section_rparen, indent, start_col, Space.Space); // )
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fn_proto.callconv_expr) |callconv_expr| {
|
if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| {
|
||||||
const callconv_rparen = tree.nextToken(callconv_expr.lastToken());
|
const callconv_rparen = tree.nextToken(callconv_expr.lastToken());
|
||||||
const callconv_lparen = tree.prevToken(callconv_expr.firstToken());
|
const callconv_lparen = tree.prevToken(callconv_expr.firstToken());
|
||||||
const callconv_kw = tree.prevToken(callconv_lparen);
|
const callconv_kw = tree.prevToken(callconv_lparen);
|
||||||
@ -1587,9 +1594,9 @@ fn renderExpression(
|
|||||||
try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // (
|
try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // (
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);
|
try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);
|
||||||
try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // )
|
try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // )
|
||||||
} else if (fn_proto.is_extern_prototype) {
|
} else if (fn_proto.getTrailer("is_extern_prototype") != null) {
|
||||||
try stream.writeAll("callconv(.C) ");
|
try stream.writeAll("callconv(.C) ");
|
||||||
} else if (fn_proto.is_async) {
|
} else if (fn_proto.getTrailer("is_async") != null) {
|
||||||
try stream.writeAll("callconv(.Async) ");
|
try stream.writeAll("callconv(.Async) ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2177,64 +2184,69 @@ fn renderVarDecl(
|
|||||||
start_col: *usize,
|
start_col: *usize,
|
||||||
var_decl: *ast.Node.VarDecl,
|
var_decl: *ast.Node.VarDecl,
|
||||||
) (@TypeOf(stream).Error || Error)!void {
|
) (@TypeOf(stream).Error || Error)!void {
|
||||||
if (var_decl.visib_token) |visib_token| {
|
if (var_decl.getTrailer("visib_token")) |visib_token| {
|
||||||
try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub
|
try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var_decl.extern_export_token) |extern_export_token| {
|
if (var_decl.getTrailer("extern_export_token")) |extern_export_token| {
|
||||||
try renderToken(tree, stream, extern_export_token, indent, start_col, Space.Space); // extern
|
try renderToken(tree, stream, extern_export_token, indent, start_col, Space.Space); // extern
|
||||||
|
|
||||||
if (var_decl.lib_name) |lib_name| {
|
if (var_decl.getTrailer("lib_name")) |lib_name| {
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); // "lib"
|
try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); // "lib"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var_decl.comptime_token) |comptime_token| {
|
if (var_decl.getTrailer("comptime_token")) |comptime_token| {
|
||||||
try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); // comptime
|
try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); // comptime
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var_decl.thread_local_token) |thread_local_token| {
|
if (var_decl.getTrailer("thread_local_token")) |thread_local_token| {
|
||||||
try renderToken(tree, stream, thread_local_token, indent, start_col, Space.Space); // threadlocal
|
try renderToken(tree, stream, thread_local_token, indent, start_col, Space.Space); // threadlocal
|
||||||
}
|
}
|
||||||
try renderToken(tree, stream, var_decl.mut_token, indent, start_col, Space.Space); // var
|
try renderToken(tree, stream, var_decl.mut_token, indent, start_col, Space.Space); // var
|
||||||
|
|
||||||
const name_space = if (var_decl.type_node == null and (var_decl.align_node != null or
|
const name_space = if (var_decl.getTrailer("type_node") == null and
|
||||||
var_decl.section_node != null or var_decl.init_node != null)) Space.Space else Space.None;
|
(var_decl.getTrailer("align_node") != null or
|
||||||
|
var_decl.getTrailer("section_node") != null or
|
||||||
|
var_decl.getTrailer("init_node") != null))
|
||||||
|
Space.Space
|
||||||
|
else
|
||||||
|
Space.None;
|
||||||
try renderToken(tree, stream, var_decl.name_token, indent, start_col, name_space);
|
try renderToken(tree, stream, var_decl.name_token, indent, start_col, name_space);
|
||||||
|
|
||||||
if (var_decl.type_node) |type_node| {
|
if (var_decl.getTrailer("type_node")) |type_node| {
|
||||||
try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, start_col, Space.Space);
|
try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, start_col, Space.Space);
|
||||||
const s = if (var_decl.align_node != null or
|
const s = if (var_decl.getTrailer("align_node") != null or
|
||||||
var_decl.section_node != null or
|
var_decl.getTrailer("section_node") != null or
|
||||||
var_decl.init_node != null) Space.Space else Space.None;
|
var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, type_node, s);
|
try renderExpression(allocator, stream, tree, indent, start_col, type_node, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var_decl.align_node) |align_node| {
|
if (var_decl.getTrailer("align_node")) |align_node| {
|
||||||
const lparen = tree.prevToken(align_node.firstToken());
|
const lparen = tree.prevToken(align_node.firstToken());
|
||||||
const align_kw = tree.prevToken(lparen);
|
const align_kw = tree.prevToken(lparen);
|
||||||
const rparen = tree.nextToken(align_node.lastToken());
|
const rparen = tree.nextToken(align_node.lastToken());
|
||||||
try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align
|
try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align
|
||||||
try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
|
try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, align_node, Space.None);
|
try renderExpression(allocator, stream, tree, indent, start_col, align_node, Space.None);
|
||||||
const s = if (var_decl.section_node != null or var_decl.init_node != null) Space.Space else Space.None;
|
const s = if (var_decl.getTrailer("section_node") != null or var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
|
||||||
try renderToken(tree, stream, rparen, indent, start_col, s); // )
|
try renderToken(tree, stream, rparen, indent, start_col, s); // )
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var_decl.section_node) |section_node| {
|
if (var_decl.getTrailer("section_node")) |section_node| {
|
||||||
const lparen = tree.prevToken(section_node.firstToken());
|
const lparen = tree.prevToken(section_node.firstToken());
|
||||||
const section_kw = tree.prevToken(lparen);
|
const section_kw = tree.prevToken(lparen);
|
||||||
const rparen = tree.nextToken(section_node.lastToken());
|
const rparen = tree.nextToken(section_node.lastToken());
|
||||||
try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // linksection
|
try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // linksection
|
||||||
try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
|
try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, section_node, Space.None);
|
try renderExpression(allocator, stream, tree, indent, start_col, section_node, Space.None);
|
||||||
const s = if (var_decl.init_node != null) Space.Space else Space.None;
|
const s = if (var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
|
||||||
try renderToken(tree, stream, rparen, indent, start_col, s); // )
|
try renderToken(tree, stream, rparen, indent, start_col, s); // )
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var_decl.init_node) |init_node| {
|
if (var_decl.getTrailer("init_node")) |init_node| {
|
||||||
const s = if (init_node.id == .MultilineStringLiteral) Space.None else Space.Space;
|
const s = if (init_node.id == .MultilineStringLiteral) Space.None else Space.Space;
|
||||||
try renderToken(tree, stream, var_decl.eq_token.?, indent, start_col, s); // =
|
try renderToken(tree, stream, var_decl.getTrailer("eq_token").?, indent, start_col, s); // =
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);
|
try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2250,7 +2262,7 @@ fn renderParamDecl(
|
|||||||
param_decl: ast.Node.FnProto.ParamDecl,
|
param_decl: ast.Node.FnProto.ParamDecl,
|
||||||
space: Space,
|
space: Space,
|
||||||
) (@TypeOf(stream).Error || Error)!void {
|
) (@TypeOf(stream).Error || Error)!void {
|
||||||
try renderDocComments(tree, stream, param_decl, indent, start_col);
|
try renderDocComments(tree, stream, param_decl, param_decl.doc_comments, indent, start_col);
|
||||||
|
|
||||||
if (param_decl.comptime_token) |comptime_token| {
|
if (param_decl.comptime_token) |comptime_token| {
|
||||||
try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space);
|
try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space);
|
||||||
@ -2263,7 +2275,6 @@ fn renderParamDecl(
|
|||||||
try renderToken(tree, stream, tree.nextToken(name_token), indent, start_col, Space.Space); // :
|
try renderToken(tree, stream, tree.nextToken(name_token), indent, start_col, Space.Space); // :
|
||||||
}
|
}
|
||||||
switch (param_decl.param_type) {
|
switch (param_decl.param_type) {
|
||||||
.var_args => |token| try renderToken(tree, stream, token, indent, start_col, space),
|
|
||||||
.any_type, .type_expr => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, space),
|
.any_type, .type_expr => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, space),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2519,10 +2530,11 @@ fn renderDocComments(
|
|||||||
tree: *ast.Tree,
|
tree: *ast.Tree,
|
||||||
stream: anytype,
|
stream: anytype,
|
||||||
node: anytype,
|
node: anytype,
|
||||||
|
doc_comments: ?*ast.Node.DocComment,
|
||||||
indent: usize,
|
indent: usize,
|
||||||
start_col: *usize,
|
start_col: *usize,
|
||||||
) (@TypeOf(stream).Error || Error)!void {
|
) (@TypeOf(stream).Error || Error)!void {
|
||||||
const comment = node.doc_comments orelse return;
|
const comment = doc_comments orelse return;
|
||||||
return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col);
|
return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1130,7 +1130,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
|||||||
};
|
};
|
||||||
defer fn_type_scope.instructions.deinit(self.gpa);
|
defer fn_type_scope.instructions.deinit(self.gpa);
|
||||||
|
|
||||||
const body_node = fn_proto.body_node orelse
|
const body_node = fn_proto.getTrailer("body_node") orelse
|
||||||
return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
|
return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
|
||||||
|
|
||||||
const param_decls = fn_proto.params();
|
const param_decls = fn_proto.params();
|
||||||
@ -1138,21 +1138,23 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
|||||||
for (param_decls) |param_decl, i| {
|
for (param_decls) |param_decl, i| {
|
||||||
const param_type_node = switch (param_decl.param_type) {
|
const param_type_node = switch (param_decl.param_type) {
|
||||||
.any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
|
.any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
|
||||||
.var_args => |tok| return self.failTok(&fn_type_scope.base, tok, "TODO implement var args", .{}),
|
|
||||||
.type_expr => |node| node,
|
.type_expr => |node| node,
|
||||||
};
|
};
|
||||||
param_types[i] = try self.astGenExpr(&fn_type_scope.base, param_type_node);
|
param_types[i] = try self.astGenExpr(&fn_type_scope.base, param_type_node);
|
||||||
}
|
}
|
||||||
if (fn_proto.lib_name) |lib_name| {
|
if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
|
||||||
|
return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{});
|
||||||
|
}
|
||||||
|
if (fn_proto.getTrailer("lib_name")) |lib_name| {
|
||||||
return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});
|
return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});
|
||||||
}
|
}
|
||||||
if (fn_proto.align_expr) |align_expr| {
|
if (fn_proto.getTrailer("align_expr")) |align_expr| {
|
||||||
return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{});
|
return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{});
|
||||||
}
|
}
|
||||||
if (fn_proto.section_expr) |sect_expr| {
|
if (fn_proto.getTrailer("section_expr")) |sect_expr| {
|
||||||
return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{});
|
return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{});
|
||||||
}
|
}
|
||||||
if (fn_proto.callconv_expr) |callconv_expr| {
|
if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| {
|
||||||
return self.failNode(
|
return self.failNode(
|
||||||
&fn_type_scope.base,
|
&fn_type_scope.base,
|
||||||
callconv_expr,
|
callconv_expr,
|
||||||
@ -1265,10 +1267,10 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
|||||||
self.bin_file.freeDecl(decl);
|
self.bin_file.freeDecl(decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fn_proto.extern_export_inline_token) |maybe_export_token| {
|
if (fn_proto.getTrailer("extern_export_inline_token")) |maybe_export_token| {
|
||||||
if (tree.token_ids[maybe_export_token] == .Keyword_export) {
|
if (tree.token_ids[maybe_export_token] == .Keyword_export) {
|
||||||
const export_src = tree.token_locs[maybe_export_token].start;
|
const export_src = tree.token_locs[maybe_export_token].start;
|
||||||
const name_loc = tree.token_locs[fn_proto.name_token.?];
|
const name_loc = tree.token_locs[fn_proto.getTrailer("name_token").?];
|
||||||
const name = tree.tokenSliceLoc(name_loc);
|
const name = tree.tokenSliceLoc(name_loc);
|
||||||
// The scope needs to have the decl in it.
|
// The scope needs to have the decl in it.
|
||||||
try self.analyzeExport(&block_scope.base, export_src, name, decl);
|
try self.analyzeExport(&block_scope.base, export_src, name, decl);
|
||||||
@ -1867,7 +1869,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
|
|||||||
for (decls) |src_decl, decl_i| {
|
for (decls) |src_decl, decl_i| {
|
||||||
if (src_decl.cast(ast.Node.FnProto)) |fn_proto| {
|
if (src_decl.cast(ast.Node.FnProto)) |fn_proto| {
|
||||||
// We will create a Decl for it regardless of analysis status.
|
// We will create a Decl for it regardless of analysis status.
|
||||||
const name_tok = fn_proto.name_token orelse {
|
const name_tok = fn_proto.getTrailer("name_token") orelse {
|
||||||
@panic("TODO missing function name");
|
@panic("TODO missing function name");
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1893,7 +1895,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
|
|||||||
} else {
|
} else {
|
||||||
const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
|
const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
|
||||||
root_scope.decls.appendAssumeCapacity(new_decl);
|
root_scope.decls.appendAssumeCapacity(new_decl);
|
||||||
if (fn_proto.extern_export_inline_token) |maybe_export_token| {
|
if (fn_proto.getTrailer("extern_export_inline_token")) |maybe_export_token| {
|
||||||
if (tree.token_ids[maybe_export_token] == .Keyword_export) {
|
if (tree.token_ids[maybe_export_token] == .Keyword_export) {
|
||||||
self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
|
self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -586,11 +586,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
|
|||||||
for (proto_node.params()) |*param, i| {
|
for (proto_node.params()) |*param, i| {
|
||||||
const param_name = if (param.name_token) |name_tok|
|
const param_name = if (param.name_token) |name_tok|
|
||||||
tokenSlice(c, name_tok)
|
tokenSlice(c, name_tok)
|
||||||
else if (param.param_type == .var_args) {
|
else
|
||||||
assert(i + 1 == proto_node.params_len);
|
|
||||||
proto_node.params_len -= 1;
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name});
|
return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name});
|
||||||
|
|
||||||
const c_param = ZigClangFunctionDecl_getParamDecl(fn_decl, param_id);
|
const c_param = ZigClangFunctionDecl_getParamDecl(fn_decl, param_id);
|
||||||
@ -602,10 +598,20 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
|
|||||||
if (!is_const) {
|
if (!is_const) {
|
||||||
const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{}", .{mangled_param_name});
|
const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{}", .{mangled_param_name});
|
||||||
const arg_name = try block_scope.makeMangledName(c, bare_arg_name);
|
const arg_name = try block_scope.makeMangledName(c, bare_arg_name);
|
||||||
const node = try transCreateNodeVarDecl(c, false, false, mangled_param_name);
|
|
||||||
node.eq_token = try appendToken(c, .Equal, "=");
|
const mut_tok = try appendToken(c, .Keyword_var, "var");
|
||||||
node.init_node = try transCreateNodeIdentifier(c, arg_name);
|
const name_tok = try appendIdentifier(c, mangled_param_name);
|
||||||
node.semicolon_token = try appendToken(c, .Semicolon, ";");
|
const eq_token = try appendToken(c, .Equal, "=");
|
||||||
|
const init_node = try transCreateNodeIdentifier(c, arg_name);
|
||||||
|
const semicolon_token = try appendToken(c, .Semicolon, ";");
|
||||||
|
const node = try ast.Node.VarDecl.create(c.arena, .{
|
||||||
|
.mut_token = mut_tok,
|
||||||
|
.name_token = name_tok,
|
||||||
|
.semicolon_token = semicolon_token,
|
||||||
|
}, .{
|
||||||
|
.eq_token = eq_token,
|
||||||
|
.init_node = init_node,
|
||||||
|
});
|
||||||
try block_scope.statements.append(&node.base);
|
try block_scope.statements.append(&node.base);
|
||||||
param.name_token = try appendIdentifier(c, arg_name);
|
param.name_token = try appendIdentifier(c, arg_name);
|
||||||
_ = try appendToken(c, .Colon, ":");
|
_ = try appendToken(c, .Colon, ":");
|
||||||
@ -622,7 +628,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
|
|||||||
=> return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
|
=> return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
|
||||||
};
|
};
|
||||||
const body_node = try block_scope.complete(rp.c);
|
const body_node = try block_scope.complete(rp.c);
|
||||||
proto_node.body_node = &body_node.base;
|
proto_node.setTrailer("body_node", &body_node.base);
|
||||||
return addTopLevelDecl(c, fn_name, &proto_node.base);
|
return addTopLevelDecl(c, fn_name, &proto_node.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,23 +731,20 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
|
|||||||
break :blk null;
|
break :blk null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const node = try c.arena.create(ast.Node.VarDecl);
|
const node = try ast.Node.VarDecl.create(c.arena, .{
|
||||||
node.* = .{
|
.name_token = name_tok,
|
||||||
.doc_comments = null,
|
.mut_token = mut_tok,
|
||||||
|
.semicolon_token = try appendToken(c, .Semicolon, ";"),
|
||||||
|
}, .{
|
||||||
.visib_token = visib_tok,
|
.visib_token = visib_tok,
|
||||||
.thread_local_token = thread_local_token,
|
.thread_local_token = thread_local_token,
|
||||||
.name_token = name_tok,
|
|
||||||
.eq_token = eq_tok,
|
.eq_token = eq_tok,
|
||||||
.mut_token = mut_tok,
|
|
||||||
.comptime_token = null,
|
|
||||||
.extern_export_token = extern_tok,
|
.extern_export_token = extern_tok,
|
||||||
.lib_name = null,
|
|
||||||
.type_node = type_node,
|
.type_node = type_node,
|
||||||
.align_node = align_expr,
|
.align_node = align_expr,
|
||||||
.section_node = linksection_expr,
|
.section_node = linksection_expr,
|
||||||
.init_node = init_node,
|
.init_node = init_node,
|
||||||
.semicolon_token = try appendToken(c, .Semicolon, ";"),
|
});
|
||||||
};
|
|
||||||
return addTopLevelDecl(c, checked_name, &node.base);
|
return addTopLevelDecl(c, checked_name, &node.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,26 +798,41 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l
|
|||||||
|
|
||||||
_ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), checked_name);
|
_ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), checked_name);
|
||||||
const node = (try transCreateNodeTypedef(rp, typedef_decl, true, checked_name)) orelse return null;
|
const node = (try transCreateNodeTypedef(rp, typedef_decl, true, checked_name)) orelse return null;
|
||||||
try addTopLevelDecl(c, checked_name, &node.base);
|
try addTopLevelDecl(c, checked_name, node);
|
||||||
return transCreateNodeIdentifier(c, checked_name);
|
return transCreateNodeIdentifier(c, checked_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transCreateNodeTypedef(rp: RestorePoint, typedef_decl: *const ZigClangTypedefNameDecl, toplevel: bool, checked_name: []const u8) Error!?*ast.Node.VarDecl {
|
fn transCreateNodeTypedef(
|
||||||
const node = try transCreateNodeVarDecl(rp.c, toplevel, true, checked_name);
|
rp: RestorePoint,
|
||||||
node.eq_token = try appendToken(rp.c, .Equal, "=");
|
typedef_decl: *const ZigClangTypedefNameDecl,
|
||||||
|
toplevel: bool,
|
||||||
|
checked_name: []const u8,
|
||||||
|
) Error!?*ast.Node {
|
||||||
|
const visib_tok = if (toplevel) try appendToken(rp.c, .Keyword_pub, "pub") else null;
|
||||||
|
const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
|
||||||
|
const name_tok = try appendIdentifier(rp.c, checked_name);
|
||||||
|
const eq_token = try appendToken(rp.c, .Equal, "=");
|
||||||
const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
|
const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
|
||||||
const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl);
|
const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl);
|
||||||
node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
|
const init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
|
||||||
error.UnsupportedType => {
|
error.UnsupportedType => {
|
||||||
try failDecl(rp.c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});
|
try failDecl(rp.c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
error.OutOfMemory => |e| return e,
|
error.OutOfMemory => |e| return e,
|
||||||
};
|
};
|
||||||
|
const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
||||||
|
|
||||||
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
const node = try ast.Node.VarDecl.create(rp.c.arena, .{
|
||||||
return node;
|
.name_token = name_tok,
|
||||||
|
.mut_token = mut_tok,
|
||||||
|
.semicolon_token = semicolon_token,
|
||||||
|
}, .{
|
||||||
|
.visib_token = visib_tok,
|
||||||
|
.eq_token = eq_token,
|
||||||
|
.init_node = init_node,
|
||||||
|
});
|
||||||
|
return &node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {
|
fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {
|
||||||
@ -847,12 +865,14 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
|
|||||||
const name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ container_kind_name, bare_name });
|
const name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ container_kind_name, bare_name });
|
||||||
_ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);
|
_ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);
|
||||||
|
|
||||||
const node = try transCreateNodeVarDecl(c, !is_unnamed, true, 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);
|
||||||
|
|
||||||
node.eq_token = try appendToken(c, .Equal, "=");
|
const eq_token = try appendToken(c, .Equal, "=");
|
||||||
|
|
||||||
var semicolon: ast.TokenIndex = undefined;
|
var semicolon: ast.TokenIndex = undefined;
|
||||||
node.init_node = blk: {
|
const init_node = blk: {
|
||||||
const rp = makeRestorePoint(c);
|
const rp = makeRestorePoint(c);
|
||||||
const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
|
const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
|
||||||
const opaque = try transCreateNodeOpaqueType(c);
|
const opaque = try transCreateNodeOpaqueType(c);
|
||||||
@ -959,7 +979,16 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
|
|||||||
semicolon = try appendToken(c, .Semicolon, ";");
|
semicolon = try appendToken(c, .Semicolon, ";");
|
||||||
break :blk &container_node.base;
|
break :blk &container_node.base;
|
||||||
};
|
};
|
||||||
node.semicolon_token = semicolon;
|
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
|
||||||
try addTopLevelDecl(c, name, &node.base);
|
try addTopLevelDecl(c, name, &node.base);
|
||||||
if (!is_unnamed)
|
if (!is_unnamed)
|
||||||
@ -982,10 +1011,13 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
|
|||||||
|
|
||||||
const name = try std.fmt.allocPrint(c.arena, "enum_{}", .{bare_name});
|
const name = try std.fmt.allocPrint(c.arena, "enum_{}", .{bare_name});
|
||||||
_ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
|
_ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
|
||||||
const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
|
|
||||||
node.eq_token = try appendToken(c, .Equal, "=");
|
|
||||||
|
|
||||||
node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {
|
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 init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {
|
||||||
var pure_enum = true;
|
var pure_enum = true;
|
||||||
var it = ZigClangEnumDecl_enumerator_begin(enum_def);
|
var it = ZigClangEnumDecl_enumerator_begin(enum_def);
|
||||||
var end_it = ZigClangEnumDecl_enumerator_end(enum_def);
|
var end_it = ZigClangEnumDecl_enumerator_end(enum_def);
|
||||||
@ -1063,8 +1095,10 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
|
|||||||
|
|
||||||
// In C each enum value is in the global namespace. So we put them there too.
|
// 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.
|
// At this point we can rely on the enum emitting successfully.
|
||||||
const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name);
|
const tld_visib_tok = try appendToken(c, .Keyword_pub, "pub");
|
||||||
tld_node.eq_token = try appendToken(c, .Equal, "=");
|
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 cast_node = try rp.c.createBuiltinCall("@enumToInt", 1);
|
||||||
const enum_ident = try transCreateNodeIdentifier(c, name);
|
const enum_ident = try transCreateNodeIdentifier(c, name);
|
||||||
const period_tok = try appendToken(c, .Period, ".");
|
const period_tok = try appendToken(c, .Period, ".");
|
||||||
@ -1078,8 +1112,17 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
|
|||||||
};
|
};
|
||||||
cast_node.params()[0] = &field_access_node.base;
|
cast_node.params()[0] = &field_access_node.base;
|
||||||
cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||||
tld_node.init_node = &cast_node.base;
|
const tld_init_node = &cast_node.base;
|
||||||
tld_node.semicolon_token = try appendToken(c, .Semicolon, ";");
|
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, &tld_node.base);
|
||||||
}
|
}
|
||||||
// make non exhaustive
|
// make non exhaustive
|
||||||
@ -1109,7 +1152,16 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
|
|||||||
} else
|
} else
|
||||||
try transCreateNodeOpaqueType(c);
|
try transCreateNodeOpaqueType(c);
|
||||||
|
|
||||||
node.semicolon_token = try appendToken(c, .Semicolon, ";");
|
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,
|
||||||
|
});
|
||||||
|
|
||||||
try addTopLevelDecl(c, name, &node.base);
|
try addTopLevelDecl(c, name, &node.base);
|
||||||
if (!is_unnamed)
|
if (!is_unnamed)
|
||||||
@ -1118,10 +1170,22 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn createAlias(c: *Context, alias: anytype) !void {
|
fn createAlias(c: *Context, alias: anytype) !void {
|
||||||
const node = try transCreateNodeVarDecl(c, true, true, alias.alias);
|
const visib_tok = try appendToken(c, .Keyword_pub, "pub");
|
||||||
node.eq_token = try appendToken(c, .Equal, "=");
|
const mut_tok = try appendToken(c, .Keyword_const, "const");
|
||||||
node.init_node = try transCreateNodeIdentifier(c, alias.name);
|
const name_tok = try appendIdentifier(c, alias.alias);
|
||||||
node.semicolon_token = try appendToken(c, .Semicolon, ";");
|
const eq_token = try appendToken(c, .Equal, "=");
|
||||||
|
const init_node = try transCreateNodeIdentifier(c, alias.name);
|
||||||
|
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,
|
||||||
|
});
|
||||||
return addTopLevelDecl(c, alias.alias, &node.base);
|
return addTopLevelDecl(c, alias.alias, &node.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1461,13 +1525,17 @@ fn transDeclStmtOne(
|
|||||||
@ptrCast(*const ZigClangNamedDecl, var_decl),
|
@ptrCast(*const ZigClangNamedDecl, var_decl),
|
||||||
));
|
));
|
||||||
const mangled_name = try block_scope.makeMangledName(c, name);
|
const mangled_name = try block_scope.makeMangledName(c, name);
|
||||||
const node = try transCreateNodeVarDecl(c, false, ZigClangQualType_isConstQualified(qual_type), mangled_name);
|
const mut_tok = if (ZigClangQualType_isConstQualified(qual_type))
|
||||||
|
try appendToken(c, .Keyword_const, "const")
|
||||||
|
else
|
||||||
|
try appendToken(c, .Keyword_var, "var");
|
||||||
|
const name_tok = try appendIdentifier(c, mangled_name);
|
||||||
|
|
||||||
_ = try appendToken(c, .Colon, ":");
|
_ = try appendToken(c, .Colon, ":");
|
||||||
const loc = ZigClangDecl_getLocation(decl);
|
const loc = ZigClangDecl_getLocation(decl);
|
||||||
node.type_node = try transQualType(rp, qual_type, loc);
|
const type_node = try transQualType(rp, qual_type, loc);
|
||||||
|
|
||||||
node.eq_token = try appendToken(c, .Equal, "=");
|
const eq_token = try appendToken(c, .Equal, "=");
|
||||||
var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
|
var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
|
||||||
try transExprCoercing(rp, scope, expr, .used, .r_value)
|
try transExprCoercing(rp, scope, expr, .used, .r_value)
|
||||||
else
|
else
|
||||||
@ -1478,8 +1546,17 @@ fn transDeclStmtOne(
|
|||||||
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||||
init_node = &builtin_node.base;
|
init_node = &builtin_node.base;
|
||||||
}
|
}
|
||||||
node.init_node = init_node;
|
const semicolon_token = try appendToken(c, .Semicolon, ";");
|
||||||
node.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,
|
||||||
|
}, .{
|
||||||
|
.thread_local_token = thread_local_token,
|
||||||
|
.eq_token = eq_token,
|
||||||
|
.type_node = type_node,
|
||||||
|
.init_node = init_node,
|
||||||
|
});
|
||||||
return &node.base;
|
return &node.base;
|
||||||
},
|
},
|
||||||
.Typedef => {
|
.Typedef => {
|
||||||
@ -1494,7 +1571,7 @@ fn transDeclStmtOne(
|
|||||||
const mangled_name = try block_scope.makeMangledName(c, name);
|
const mangled_name = try block_scope.makeMangledName(c, name);
|
||||||
const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse
|
const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse
|
||||||
return error.UnsupportedTranslation;
|
return error.UnsupportedTranslation;
|
||||||
return &node.base;
|
return node;
|
||||||
},
|
},
|
||||||
else => |kind| return revertAndWarn(
|
else => |kind| return revertAndWarn(
|
||||||
rp,
|
rp,
|
||||||
@ -3105,12 +3182,21 @@ fn transCreatePreCrement(
|
|||||||
defer block_scope.deinit();
|
defer block_scope.deinit();
|
||||||
const ref = try block_scope.makeMangledName(rp.c, "ref");
|
const ref = try block_scope.makeMangledName(rp.c, "ref");
|
||||||
|
|
||||||
const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
|
const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
|
||||||
node.eq_token = try appendToken(rp.c, .Equal, "=");
|
const name_tok = try appendIdentifier(rp.c, ref);
|
||||||
|
const eq_token = try appendToken(rp.c, .Equal, "=");
|
||||||
const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
|
const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
|
||||||
rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
|
rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
|
||||||
node.init_node = &rhs_node.base;
|
const init_node = &rhs_node.base;
|
||||||
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
||||||
|
const node = try ast.Node.VarDecl.create(rp.c.arena, .{
|
||||||
|
.name_token = name_tok,
|
||||||
|
.mut_token = mut_tok,
|
||||||
|
.semicolon_token = semicolon_token,
|
||||||
|
}, .{
|
||||||
|
.eq_token = eq_token,
|
||||||
|
.init_node = init_node,
|
||||||
|
});
|
||||||
try block_scope.statements.append(&node.base);
|
try block_scope.statements.append(&node.base);
|
||||||
|
|
||||||
const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
|
const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
|
||||||
@ -3171,12 +3257,21 @@ fn transCreatePostCrement(
|
|||||||
defer block_scope.deinit();
|
defer block_scope.deinit();
|
||||||
const ref = try block_scope.makeMangledName(rp.c, "ref");
|
const ref = try block_scope.makeMangledName(rp.c, "ref");
|
||||||
|
|
||||||
const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
|
const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
|
||||||
node.eq_token = try appendToken(rp.c, .Equal, "=");
|
const name_tok = try appendIdentifier(rp.c, ref);
|
||||||
|
const eq_token = try appendToken(rp.c, .Equal, "=");
|
||||||
const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
|
const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
|
||||||
rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
|
rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
|
||||||
node.init_node = &rhs_node.base;
|
const init_node = &rhs_node.base;
|
||||||
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
||||||
|
const node = try ast.Node.VarDecl.create(rp.c.arena, .{
|
||||||
|
.name_token = name_tok,
|
||||||
|
.mut_token = mut_tok,
|
||||||
|
.semicolon_token = semicolon_token,
|
||||||
|
}, .{
|
||||||
|
.eq_token = eq_token,
|
||||||
|
.init_node = init_node,
|
||||||
|
});
|
||||||
try block_scope.statements.append(&node.base);
|
try block_scope.statements.append(&node.base);
|
||||||
|
|
||||||
const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
|
const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
|
||||||
@ -3184,10 +3279,19 @@ fn transCreatePostCrement(
|
|||||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||||
|
|
||||||
const tmp = try block_scope.makeMangledName(rp.c, "tmp");
|
const tmp = try block_scope.makeMangledName(rp.c, "tmp");
|
||||||
const tmp_node = try transCreateNodeVarDecl(rp.c, false, true, tmp);
|
const tmp_mut_tok = try appendToken(rp.c, .Keyword_const, "const");
|
||||||
tmp_node.eq_token = try appendToken(rp.c, .Equal, "=");
|
const tmp_name_tok = try appendIdentifier(rp.c, tmp);
|
||||||
tmp_node.init_node = ref_node;
|
const tmp_eq_token = try appendToken(rp.c, .Equal, "=");
|
||||||
tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
const tmp_init_node = ref_node;
|
||||||
|
const tmp_semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
||||||
|
const tmp_node = try ast.Node.VarDecl.create(rp.c.arena, .{
|
||||||
|
.name_token = tmp_name_tok,
|
||||||
|
.mut_token = tmp_mut_tok,
|
||||||
|
.semicolon_token = semicolon_token,
|
||||||
|
}, .{
|
||||||
|
.eq_token = tmp_eq_token,
|
||||||
|
.init_node = tmp_init_node,
|
||||||
|
});
|
||||||
try block_scope.statements.append(&tmp_node.base);
|
try block_scope.statements.append(&tmp_node.base);
|
||||||
|
|
||||||
const token = try appendToken(rp.c, op_tok_id, bytes);
|
const token = try appendToken(rp.c, op_tok_id, bytes);
|
||||||
@ -3325,12 +3429,21 @@ fn transCreateCompoundAssign(
|
|||||||
defer block_scope.deinit();
|
defer block_scope.deinit();
|
||||||
const ref = try block_scope.makeMangledName(rp.c, "ref");
|
const ref = try block_scope.makeMangledName(rp.c, "ref");
|
||||||
|
|
||||||
const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
|
const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
|
||||||
node.eq_token = try appendToken(rp.c, .Equal, "=");
|
const name_tok = try appendIdentifier(rp.c, ref);
|
||||||
|
const eq_token = try appendToken(rp.c, .Equal, "=");
|
||||||
const addr_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
|
const addr_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
|
||||||
addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
|
addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
|
||||||
node.init_node = &addr_node.base;
|
const init_node = &addr_node.base;
|
||||||
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
||||||
|
const node = try ast.Node.VarDecl.create(rp.c.arena, .{
|
||||||
|
.name_token = name_tok,
|
||||||
|
.mut_token = mut_tok,
|
||||||
|
.semicolon_token = semicolon_token,
|
||||||
|
}, .{
|
||||||
|
.eq_token = eq_token,
|
||||||
|
.init_node = init_node,
|
||||||
|
});
|
||||||
try block_scope.statements.append(&node.base);
|
try block_scope.statements.append(&node.base);
|
||||||
|
|
||||||
const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
|
const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
|
||||||
@ -3375,8 +3488,8 @@ fn transCreateCompoundAssign(
|
|||||||
const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
|
const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
|
||||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||||
|
|
||||||
const eq_token = try appendToken(rp.c, .Equal, "=");
|
const ass_eq_token = try appendToken(rp.c, .Equal, "=");
|
||||||
const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);
|
const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, ass_eq_token, rhs_bin, .used, false);
|
||||||
try block_scope.statements.append(assign);
|
try block_scope.statements.append(assign);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3494,10 +3607,19 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
|
|||||||
defer block_scope.deinit();
|
defer block_scope.deinit();
|
||||||
|
|
||||||
const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");
|
const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");
|
||||||
const tmp_var = try transCreateNodeVarDecl(rp.c, false, true, mangled_name);
|
const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
|
||||||
tmp_var.eq_token = try appendToken(rp.c, .Equal, "=");
|
const name_tok = try appendIdentifier(rp.c, mangled_name);
|
||||||
tmp_var.init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value);
|
const eq_token = try appendToken(rp.c, .Equal, "=");
|
||||||
tmp_var.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
const init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value);
|
||||||
|
const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
||||||
|
const tmp_var = try ast.Node.VarDecl.create(rp.c.arena, .{
|
||||||
|
.name_token = name_tok,
|
||||||
|
.mut_token = mut_tok,
|
||||||
|
.semicolon_token = semicolon_token,
|
||||||
|
}, .{
|
||||||
|
.eq_token = eq_token,
|
||||||
|
.init_node = init_node,
|
||||||
|
});
|
||||||
try block_scope.statements.append(&tmp_var.base);
|
try block_scope.statements.append(&tmp_var.base);
|
||||||
|
|
||||||
const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
|
const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
|
||||||
@ -3932,9 +4054,9 @@ fn transCreateNodeAssign(
|
|||||||
defer block_scope.deinit();
|
defer block_scope.deinit();
|
||||||
|
|
||||||
const tmp = try block_scope.makeMangledName(rp.c, "tmp");
|
const tmp = try block_scope.makeMangledName(rp.c, "tmp");
|
||||||
|
const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
|
||||||
const node = try transCreateNodeVarDecl(rp.c, false, true, tmp);
|
const name_tok = try appendIdentifier(rp.c, tmp);
|
||||||
node.eq_token = try appendToken(rp.c, .Equal, "=");
|
const eq_token = try appendToken(rp.c, .Equal, "=");
|
||||||
var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value);
|
var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value);
|
||||||
if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
|
if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
|
||||||
const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
|
const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
|
||||||
@ -3942,16 +4064,24 @@ fn transCreateNodeAssign(
|
|||||||
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||||
rhs_node = &builtin_node.base;
|
rhs_node = &builtin_node.base;
|
||||||
}
|
}
|
||||||
node.init_node = rhs_node;
|
const init_node = rhs_node;
|
||||||
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
||||||
|
const node = try ast.Node.VarDecl.create(rp.c.arena, .{
|
||||||
|
.name_token = name_tok,
|
||||||
|
.mut_token = mut_tok,
|
||||||
|
.semicolon_token = semicolon_token,
|
||||||
|
}, .{
|
||||||
|
.eq_token = eq_token,
|
||||||
|
.init_node = init_node,
|
||||||
|
});
|
||||||
try block_scope.statements.append(&node.base);
|
try block_scope.statements.append(&node.base);
|
||||||
|
|
||||||
const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value);
|
const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value);
|
||||||
const eq_token = try appendToken(rp.c, .Equal, "=");
|
const lhs_eq_token = try appendToken(rp.c, .Equal, "=");
|
||||||
const ident = try transCreateNodeIdentifier(rp.c, tmp);
|
const ident = try transCreateNodeIdentifier(rp.c, tmp);
|
||||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||||
|
|
||||||
const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, eq_token, ident, .used, false);
|
const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, lhs_eq_token, ident, .used, false);
|
||||||
try block_scope.statements.append(assign);
|
try block_scope.statements.append(assign);
|
||||||
|
|
||||||
const break_node = try transCreateNodeBreak(rp.c, label_name);
|
const break_node = try transCreateNodeBreak(rp.c, label_name);
|
||||||
@ -4232,28 +4362,10 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
|
|||||||
|
|
||||||
_ = try appendToken(c, .RParen, ")");
|
_ = try appendToken(c, .RParen, ")");
|
||||||
|
|
||||||
const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len);
|
|
||||||
fn_proto.* = .{
|
|
||||||
.doc_comments = null,
|
|
||||||
.visib_token = pub_tok,
|
|
||||||
.fn_token = fn_tok,
|
|
||||||
.name_token = name_tok,
|
|
||||||
.params_len = fn_params.items.len,
|
|
||||||
.return_type = proto_alias.return_type,
|
|
||||||
.var_args_token = null,
|
|
||||||
.extern_export_inline_token = inline_tok,
|
|
||||||
.body_node = null,
|
|
||||||
.lib_name = null,
|
|
||||||
.align_expr = null,
|
|
||||||
.section_expr = null,
|
|
||||||
.callconv_expr = null,
|
|
||||||
};
|
|
||||||
mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
|
|
||||||
|
|
||||||
const block_lbrace = try appendToken(c, .LBrace, "{");
|
const block_lbrace = try appendToken(c, .LBrace, "{");
|
||||||
|
|
||||||
const return_expr = try transCreateNodeReturnExpr(c);
|
const return_expr = try transCreateNodeReturnExpr(c);
|
||||||
const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?);
|
const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.getTrailer("init_node").?);
|
||||||
|
|
||||||
const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);
|
const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);
|
||||||
const call_params = call_expr.params();
|
const call_params = call_expr.params();
|
||||||
@ -4277,7 +4389,18 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
|
|||||||
.rbrace = try appendToken(c, .RBrace, "}"),
|
.rbrace = try appendToken(c, .RBrace, "}"),
|
||||||
};
|
};
|
||||||
block.statements()[0] = &return_expr.base;
|
block.statements()[0] = &return_expr.base;
|
||||||
fn_proto.body_node = &block.base;
|
|
||||||
|
const fn_proto = try ast.Node.FnProto.create(c.arena, .{
|
||||||
|
.params_len = fn_params.items.len,
|
||||||
|
.fn_token = fn_tok,
|
||||||
|
.return_type = proto_alias.return_type,
|
||||||
|
}, .{
|
||||||
|
.visib_token = pub_tok,
|
||||||
|
.name_token = name_tok,
|
||||||
|
.extern_export_inline_token = inline_tok,
|
||||||
|
.body_node = &block.base,
|
||||||
|
});
|
||||||
|
mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
|
||||||
return &fn_proto.base;
|
return &fn_proto.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4356,31 +4479,6 @@ fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowE
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transCreateNodeVarDecl(c: *Context, is_pub: bool, is_const: bool, name: []const u8) !*ast.Node.VarDecl {
|
|
||||||
const visib_tok = if (is_pub) try appendToken(c, .Keyword_pub, "pub") else null;
|
|
||||||
const mut_tok = if (is_const) try appendToken(c, .Keyword_const, "const") else try appendToken(c, .Keyword_var, "var");
|
|
||||||
const name_tok = try appendIdentifier(c, name);
|
|
||||||
|
|
||||||
const node = try c.arena.create(ast.Node.VarDecl);
|
|
||||||
node.* = .{
|
|
||||||
.doc_comments = null,
|
|
||||||
.visib_token = visib_tok,
|
|
||||||
.thread_local_token = null,
|
|
||||||
.name_token = name_tok,
|
|
||||||
.eq_token = undefined,
|
|
||||||
.mut_token = mut_tok,
|
|
||||||
.comptime_token = null,
|
|
||||||
.extern_export_token = null,
|
|
||||||
.lib_name = null,
|
|
||||||
.type_node = null,
|
|
||||||
.align_node = null,
|
|
||||||
.section_node = null,
|
|
||||||
.init_node = null,
|
|
||||||
.semicolon_token = undefined,
|
|
||||||
};
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
|
fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
|
||||||
const while_tok = try appendToken(c, .Keyword_while, "while");
|
const while_tok = try appendToken(c, .Keyword_while, "while");
|
||||||
_ = try appendToken(c, .LParen, "(");
|
_ = try appendToken(c, .LParen, "(");
|
||||||
@ -4782,19 +4880,12 @@ fn finishTransFnProto(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_var_args) {
|
const var_args_token: ?ast.TokenIndex = if (is_var_args) blk: {
|
||||||
if (param_count > 0) {
|
if (param_count > 0) {
|
||||||
_ = try appendToken(rp.c, .Comma, ",");
|
_ = try appendToken(rp.c, .Comma, ",");
|
||||||
}
|
}
|
||||||
|
break :blk try appendToken(rp.c, .Ellipsis3, "...");
|
||||||
fn_params.addOneAssumeCapacity().* = .{
|
} else null;
|
||||||
.doc_comments = null,
|
|
||||||
.comptime_token = null,
|
|
||||||
.noalias_token = null,
|
|
||||||
.name_token = null,
|
|
||||||
.param_type = .{ .var_args = try appendToken(rp.c, .Ellipsis3, "...") },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const rparen_tok = try appendToken(rp.c, .RParen, ")");
|
const rparen_tok = try appendToken(rp.c, .RParen, ")");
|
||||||
|
|
||||||
@ -4860,22 +4951,31 @@ fn finishTransFnProto(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fn_proto = try ast.Node.FnProto.alloc(rp.c.arena, fn_params.items.len);
|
// We need to reserve an undefined (but non-null) body node to set later.
|
||||||
fn_proto.* = .{
|
var body_node: ?*ast.Node = null;
|
||||||
.doc_comments = null,
|
if (fn_decl_context) |ctx| {
|
||||||
.visib_token = pub_tok,
|
if (ctx.has_body) {
|
||||||
.fn_token = fn_tok,
|
// TODO: we should be able to use undefined here but
|
||||||
.name_token = name_tok,
|
// it causes a bug. This is undefined without zig language
|
||||||
|
// being aware of it.
|
||||||
|
body_node = @intToPtr(*ast.Node, 0x08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn_proto = try ast.Node.FnProto.create(rp.c.arena, .{
|
||||||
.params_len = fn_params.items.len,
|
.params_len = fn_params.items.len,
|
||||||
.return_type = .{ .Explicit = return_type_node },
|
.return_type = .{ .Explicit = return_type_node },
|
||||||
.var_args_token = null, // TODO this field is broken in the AST data model
|
.fn_token = fn_tok,
|
||||||
|
}, .{
|
||||||
|
.visib_token = pub_tok,
|
||||||
|
.name_token = name_tok,
|
||||||
.extern_export_inline_token = extern_export_inline_tok,
|
.extern_export_inline_token = extern_export_inline_tok,
|
||||||
.body_node = null,
|
|
||||||
.lib_name = null,
|
|
||||||
.align_expr = align_expr,
|
.align_expr = align_expr,
|
||||||
.section_expr = linksection_expr,
|
.section_expr = linksection_expr,
|
||||||
.callconv_expr = callconv_expr,
|
.callconv_expr = callconv_expr,
|
||||||
};
|
.body_node = body_node,
|
||||||
|
.var_args_token = var_args_token,
|
||||||
|
});
|
||||||
mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
|
mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
|
||||||
return fn_proto;
|
return fn_proto;
|
||||||
}
|
}
|
||||||
@ -4923,23 +5023,15 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp
|
|||||||
};
|
};
|
||||||
call_node.params()[0] = &msg_node.base;
|
call_node.params()[0] = &msg_node.base;
|
||||||
|
|
||||||
const var_decl_node = try c.arena.create(ast.Node.VarDecl);
|
const var_decl_node = try ast.Node.VarDecl.create(c.arena, .{
|
||||||
var_decl_node.* = .{
|
|
||||||
.doc_comments = null,
|
|
||||||
.visib_token = pub_tok,
|
|
||||||
.thread_local_token = null,
|
|
||||||
.name_token = name_tok,
|
.name_token = name_tok,
|
||||||
.eq_token = eq_tok,
|
|
||||||
.mut_token = const_tok,
|
.mut_token = const_tok,
|
||||||
.comptime_token = null,
|
|
||||||
.extern_export_token = null,
|
|
||||||
.lib_name = null,
|
|
||||||
.type_node = null,
|
|
||||||
.align_node = null,
|
|
||||||
.section_node = null,
|
|
||||||
.init_node = &call_node.base,
|
|
||||||
.semicolon_token = semi_tok,
|
.semicolon_token = semi_tok,
|
||||||
};
|
}, .{
|
||||||
|
.visib_token = pub_tok,
|
||||||
|
.eq_token = eq_tok,
|
||||||
|
.init_node = &call_node.base,
|
||||||
|
});
|
||||||
try addTopLevelDecl(c, name, &var_decl_node.base);
|
try addTopLevelDecl(c, name, &var_decl_node.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5132,10 +5224,12 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
|
|||||||
fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {
|
fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {
|
||||||
const scope = &c.global_scope.base;
|
const scope = &c.global_scope.base;
|
||||||
|
|
||||||
const node = try transCreateNodeVarDecl(c, true, true, name);
|
const visib_tok = try appendToken(c, .Keyword_pub, "pub");
|
||||||
node.eq_token = try appendToken(c, .Equal, "=");
|
const mut_tok = try appendToken(c, .Keyword_const, "const");
|
||||||
|
const name_tok = try appendIdentifier(c, name);
|
||||||
|
const eq_token = try appendToken(c, .Equal, "=");
|
||||||
|
|
||||||
node.init_node = try parseCExpr(c, it, source, source_loc, scope);
|
const init_node = try parseCExpr(c, it, source, source_loc, scope);
|
||||||
const last = it.next().?;
|
const last = it.next().?;
|
||||||
if (last.id != .Eof and last.id != .Nl)
|
if (last.id != .Eof and last.id != .Nl)
|
||||||
return failDecl(
|
return failDecl(
|
||||||
@ -5146,7 +5240,16 @@ fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, n
|
|||||||
.{@tagName(last.id)},
|
.{@tagName(last.id)},
|
||||||
);
|
);
|
||||||
|
|
||||||
node.semicolon_token = try appendToken(c, .Semicolon, ";");
|
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,
|
||||||
|
});
|
||||||
_ = try c.global_scope.macro_table.put(name, &node.base);
|
_ = try c.global_scope.macro_table.put(name, &node.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5223,24 +5326,6 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
|||||||
|
|
||||||
const type_of = try c.createBuiltinCall("@TypeOf", 1);
|
const type_of = try c.createBuiltinCall("@TypeOf", 1);
|
||||||
|
|
||||||
const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len);
|
|
||||||
fn_proto.* = .{
|
|
||||||
.visib_token = pub_tok,
|
|
||||||
.extern_export_inline_token = inline_tok,
|
|
||||||
.fn_token = fn_tok,
|
|
||||||
.name_token = name_tok,
|
|
||||||
.params_len = fn_params.items.len,
|
|
||||||
.return_type = .{ .Explicit = &type_of.base },
|
|
||||||
.doc_comments = null,
|
|
||||||
.var_args_token = null,
|
|
||||||
.body_node = null,
|
|
||||||
.lib_name = null,
|
|
||||||
.align_expr = null,
|
|
||||||
.section_expr = null,
|
|
||||||
.callconv_expr = null,
|
|
||||||
};
|
|
||||||
mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
|
|
||||||
|
|
||||||
const return_expr = try transCreateNodeReturnExpr(c);
|
const return_expr = try transCreateNodeReturnExpr(c);
|
||||||
const expr = try parseCExpr(c, it, source, source_loc, scope);
|
const expr = try parseCExpr(c, it, source, source_loc, scope);
|
||||||
const last = it.next().?;
|
const last = it.next().?;
|
||||||
@ -5266,7 +5351,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
|||||||
|
|
||||||
try block_scope.statements.append(&return_expr.base);
|
try block_scope.statements.append(&return_expr.base);
|
||||||
const block_node = try block_scope.complete(c);
|
const block_node = try block_scope.complete(c);
|
||||||
fn_proto.body_node = &block_node.base;
|
const fn_proto = try ast.Node.FnProto.create(c.arena, .{
|
||||||
|
.fn_token = fn_tok,
|
||||||
|
.params_len = fn_params.items.len,
|
||||||
|
.return_type = .{ .Explicit = &type_of.base },
|
||||||
|
}, .{
|
||||||
|
.visib_token = pub_tok,
|
||||||
|
.extern_export_inline_token = inline_tok,
|
||||||
|
.name_token = name_tok,
|
||||||
|
.body_node = &block_node.base,
|
||||||
|
});
|
||||||
|
mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
|
||||||
|
|
||||||
_ = try c.global_scope.macro_table.put(name, &fn_proto.base);
|
_ = try c.global_scope.macro_table.put(name, &fn_proto.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6030,7 +6126,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
|
|||||||
const ident = node.cast(ast.Node.Identifier).?;
|
const ident = node.cast(ast.Node.Identifier).?;
|
||||||
if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
|
if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
|
||||||
if (value.cast(ast.Node.VarDecl)) |var_decl|
|
if (value.cast(ast.Node.VarDecl)) |var_decl|
|
||||||
return getContainer(c, var_decl.init_node.?);
|
return getContainer(c, var_decl.getTrailer("init_node").?);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -6060,7 +6156,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
|
|||||||
if (ref.cast(ast.Node.Identifier)) |ident| {
|
if (ref.cast(ast.Node.Identifier)) |ident| {
|
||||||
if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
|
if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
|
||||||
if (value.cast(ast.Node.VarDecl)) |var_decl| {
|
if (value.cast(ast.Node.VarDecl)) |var_decl| {
|
||||||
if (var_decl.type_node) |ty|
|
if (var_decl.getTrailer("type_node")) |ty|
|
||||||
return getContainer(c, ty);
|
return getContainer(c, ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6084,7 +6180,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
|
fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
|
||||||
const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null;
|
const init = if (ref.cast(ast.Node.VarDecl)) |v| v.getTrailer("init_node").? else return null;
|
||||||
if (getContainerTypeOf(c, init)) |ty_node| {
|
if (getContainerTypeOf(c, init)) |ty_node| {
|
||||||
if (ty_node.cast(ast.Node.OptionalType)) |prefix| {
|
if (ty_node.cast(ast.Node.OptionalType)) |prefix| {
|
||||||
if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
|
if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
|
||||||
|
|||||||
@ -2797,7 +2797,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\pub fn a() callconv(.C) void {}
|
\\pub fn a() callconv(.C) void {}
|
||||||
\\pub fn b() callconv(.C) void {}
|
\\pub fn b() callconv(.C) void {}
|
||||||
\\pub export fn c() void {}
|
\\pub export fn c() void {}
|
||||||
\\pub fn foo() callconv(.C) void {}
|
\\pub fn foo(...) callconv(.C) void {}
|
||||||
});
|
});
|
||||||
|
|
||||||
cases.add("casting away const and volatile",
|
cases.add("casting away const and volatile",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user