mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
stage2 parser performance/API improvements
* Extract Call ast node tag out of SuffixOp; parameters go in memory after Call. * Demote AsmInput and AsmOutput from AST nodes to structs inside the Asm node. * The following ast nodes get their sub-node lists directly following them in memory: - ErrorSetDecl - Switch - BuiltinCall * ast.Node.Asm gets slices for inputs, outputs, clobbers instead of singly linked lists Performance changes: throughput: 72.7 MiB/s => 74.0 MiB/s maxrss: 72 KB => 69 KB (nice)
This commit is contained in:
parent
32ecb416f3
commit
d37b81d43b
@ -323,7 +323,7 @@ pub const Error = union(enum) {
|
|||||||
node: *Node,
|
node: *Node,
|
||||||
|
|
||||||
pub fn render(self: *const ExpectedCall, tokens: []const Token, stream: var) !void {
|
pub fn render(self: *const ExpectedCall, tokens: []const Token, stream: var) !void {
|
||||||
return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}", .{
|
return stream.print("expected " ++ @tagName(Node.Id.Call) ++ ", found {}", .{
|
||||||
@tagName(self.node.id),
|
@tagName(self.node.id),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -333,7 +333,7 @@ pub const Error = union(enum) {
|
|||||||
node: *Node,
|
node: *Node,
|
||||||
|
|
||||||
pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token, stream: var) !void {
|
pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token, stream: var) !void {
|
||||||
return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++
|
return stream.print("expected " ++ @tagName(Node.Id.Call) ++ " or " ++
|
||||||
@tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});
|
@tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -428,15 +428,19 @@ pub const Node = struct {
|
|||||||
// Operators
|
// Operators
|
||||||
InfixOp,
|
InfixOp,
|
||||||
PrefixOp,
|
PrefixOp,
|
||||||
|
/// Not all suffix operations are under this tag. To save memory, some
|
||||||
|
/// suffix operations have dedicated Node tags.
|
||||||
SuffixOp,
|
SuffixOp,
|
||||||
/// This is a suffix operation but to save memory we have a dedicated Node id for it.
|
/// `T{a, b}`
|
||||||
ArrayInitializer,
|
ArrayInitializer,
|
||||||
/// ArrayInitializer but with `.` instead of a left-hand-side operand.
|
/// ArrayInitializer but with `.` instead of a left-hand-side operand.
|
||||||
ArrayInitializerDot,
|
ArrayInitializerDot,
|
||||||
/// This is a suffix operation but to save memory we have a dedicated Node id for it.
|
/// `T{.a = b}`
|
||||||
StructInitializer,
|
StructInitializer,
|
||||||
/// StructInitializer but with `.` instead of a left-hand-side operand.
|
/// StructInitializer but with `.` instead of a left-hand-side operand.
|
||||||
StructInitializerDot,
|
StructInitializerDot,
|
||||||
|
/// `foo()`
|
||||||
|
Call,
|
||||||
|
|
||||||
// Control flow
|
// Control flow
|
||||||
Switch,
|
Switch,
|
||||||
@ -483,8 +487,6 @@ pub const Node = struct {
|
|||||||
PointerIndexPayload,
|
PointerIndexPayload,
|
||||||
ContainerField,
|
ContainerField,
|
||||||
ErrorTag,
|
ErrorTag,
|
||||||
AsmInput,
|
|
||||||
AsmOutput,
|
|
||||||
FieldInitializer,
|
FieldInitializer,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -780,13 +782,22 @@ pub const Node = struct {
|
|||||||
pub const ErrorSetDecl = struct {
|
pub const ErrorSetDecl = struct {
|
||||||
base: Node = Node{ .id = .ErrorSetDecl },
|
base: Node = Node{ .id = .ErrorSetDecl },
|
||||||
error_token: TokenIndex,
|
error_token: TokenIndex,
|
||||||
decls: DeclList,
|
|
||||||
rbrace_token: TokenIndex,
|
rbrace_token: TokenIndex,
|
||||||
|
decls_len: NodeIndex,
|
||||||
|
|
||||||
pub const DeclList = LinkedList(*Node);
|
/// After this the caller must initialize the decls list.
|
||||||
|
pub fn alloc(allocator: *mem.Allocator, decls_len: NodeIndex) !*ErrorSetDecl {
|
||||||
|
const bytes = try allocator.alignedAlloc(u8, @alignOf(ErrorSetDecl), sizeInBytes(decls_len));
|
||||||
|
return @ptrCast(*ErrorSetDecl, bytes.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free(self: *ErrorSetDecl, allocator: *mem.Allocator) void {
|
||||||
|
const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.decls_len)];
|
||||||
|
allocator.free(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iterate(self: *const ErrorSetDecl) Node.Iterator {
|
pub fn iterate(self: *const ErrorSetDecl) Node.Iterator {
|
||||||
return .{ .parent_node = &self.base, .index = 0, .node = self.decls.first };
|
return .{ .parent_node = &self.base, .index = 0, .node = null };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iterateNext(self: *const ErrorSetDecl, it: *Node.Iterator) ?*Node {
|
pub fn iterateNext(self: *const ErrorSetDecl, it: *Node.Iterator) ?*Node {
|
||||||
@ -802,6 +813,20 @@ pub const Node = struct {
|
|||||||
pub fn lastToken(self: *const ErrorSetDecl) TokenIndex {
|
pub fn lastToken(self: *const ErrorSetDecl) TokenIndex {
|
||||||
return self.rbrace_token;
|
return self.rbrace_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decls(self: *ErrorSetDecl) []*Node {
|
||||||
|
const decls_start = @ptrCast([*]u8, self) + @sizeOf(ErrorSetDecl);
|
||||||
|
return @ptrCast([*]*Node, decls_start)[0..self.decls_len];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declsConst(self: *const ErrorSetDecl) []const *Node {
|
||||||
|
const decls_start = @ptrCast([*]const u8, self) + @sizeOf(ErrorSetDecl);
|
||||||
|
return @ptrCast([*]const *Node, decls_start)[0..self.decls_len];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sizeInBytes(decls_len: NodeIndex) usize {
|
||||||
|
return @sizeOf(ErrorSetDecl) + @sizeOf(*Node) * @as(usize, decls_len);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The fields and decls Node pointers directly follow this struct in memory.
|
/// The fields and decls Node pointers directly follow this struct in memory.
|
||||||
@ -1464,19 +1489,28 @@ pub const Node = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The cases node pointers are found in memory after Switch.
|
||||||
|
/// They must be SwitchCase or SwitchElse nodes.
|
||||||
pub const Switch = struct {
|
pub const Switch = struct {
|
||||||
base: Node = Node{ .id = .Switch },
|
base: Node = Node{ .id = .Switch },
|
||||||
switch_token: TokenIndex,
|
switch_token: TokenIndex,
|
||||||
|
rbrace: TokenIndex,
|
||||||
|
cases_len: NodeIndex,
|
||||||
expr: *Node,
|
expr: *Node,
|
||||||
|
|
||||||
/// these must be SwitchCase nodes
|
/// After this the caller must initialize the fields_and_decls list.
|
||||||
cases: CaseList,
|
pub fn alloc(allocator: *mem.Allocator, cases_len: NodeIndex) !*Switch {
|
||||||
rbrace: TokenIndex,
|
const bytes = try allocator.alignedAlloc(u8, @alignOf(Switch), sizeInBytes(cases_len));
|
||||||
|
return @ptrCast(*Switch, bytes.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
pub const CaseList = LinkedList(*Node);
|
pub fn free(self: *Switch, allocator: *mem.Allocator) void {
|
||||||
|
const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.cases_len)];
|
||||||
|
allocator.free(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iterate(self: *const Switch) Node.Iterator {
|
pub fn iterate(self: *const Switch) Node.Iterator {
|
||||||
return .{ .parent_node = &self.base, .index = 0, .node = self.cases.first };
|
return .{ .parent_node = &self.base, .index = 0, .node = null };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iterateNext(self: *const Switch, it: *Node.Iterator) ?*Node {
|
pub fn iterateNext(self: *const Switch, it: *Node.Iterator) ?*Node {
|
||||||
@ -1502,6 +1536,20 @@ pub const Node = struct {
|
|||||||
pub fn lastToken(self: *const Switch) TokenIndex {
|
pub fn lastToken(self: *const Switch) TokenIndex {
|
||||||
return self.rbrace;
|
return self.rbrace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cases(self: *Switch) []*Node {
|
||||||
|
const decls_start = @ptrCast([*]u8, self) + @sizeOf(Switch);
|
||||||
|
return @ptrCast([*]*Node, decls_start)[0..self.cases_len];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn casesConst(self: *const Switch) []const *Node {
|
||||||
|
const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Switch);
|
||||||
|
return @ptrCast([*]const *Node, decls_start)[0..self.cases_len];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sizeInBytes(cases_len: NodeIndex) usize {
|
||||||
|
return @sizeOf(Switch) + @sizeOf(*Node) * @as(usize, cases_len);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const SwitchCase = struct {
|
pub const SwitchCase = struct {
|
||||||
@ -2120,6 +2168,66 @@ pub const Node = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Parameter nodes directly follow Call in memory.
|
||||||
|
pub const Call = struct {
|
||||||
|
base: Node = Node{ .id = .Call },
|
||||||
|
lhs: *Node,
|
||||||
|
rtoken: TokenIndex,
|
||||||
|
params_len: NodeIndex,
|
||||||
|
async_token: ?TokenIndex,
|
||||||
|
|
||||||
|
/// After this the caller must initialize the fields_and_decls list.
|
||||||
|
pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*Call {
|
||||||
|
const bytes = try allocator.alignedAlloc(u8, @alignOf(Call), sizeInBytes(params_len));
|
||||||
|
return @ptrCast(*Call, bytes.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free(self: *Call, allocator: *mem.Allocator) void {
|
||||||
|
const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)];
|
||||||
|
allocator.free(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iterate(self: *const Call) Node.Iterator {
|
||||||
|
return .{ .parent_node = &self.base, .index = 0, .node = null};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iterateNext(self: *const Call, it: *Node.Iterator) ?*Node {
|
||||||
|
var i = it.index;
|
||||||
|
it.index += 1;
|
||||||
|
|
||||||
|
if (i < 1) return self.lhs;
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
if (i < self.params_len) return self.paramsConst()[i];
|
||||||
|
i -= self.params_len;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn firstToken(self: *const Call) TokenIndex {
|
||||||
|
if (self.async_token) |async_token| return async_token;
|
||||||
|
return self.lhs.firstToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lastToken(self: *const Call) TokenIndex {
|
||||||
|
return self.rtoken;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn params(self: *Call) []*Node {
|
||||||
|
const decls_start = @ptrCast([*]u8, self) + @sizeOf(Call);
|
||||||
|
return @ptrCast([*]*Node, decls_start)[0..self.params_len];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn paramsConst(self: *const Call) []const *Node {
|
||||||
|
const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Call);
|
||||||
|
return @ptrCast([*]const *Node, decls_start)[0..self.params_len];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sizeInBytes(params_len: NodeIndex) usize {
|
||||||
|
return @sizeOf(Call) + @sizeOf(*Node) * @as(usize, params_len);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const SuffixOp = struct {
|
pub const SuffixOp = struct {
|
||||||
base: Node = Node{ .id = .SuffixOp },
|
base: Node = Node{ .id = .SuffixOp },
|
||||||
op: Op,
|
op: Op,
|
||||||
@ -2127,19 +2235,11 @@ pub const Node = struct {
|
|||||||
rtoken: TokenIndex,
|
rtoken: TokenIndex,
|
||||||
|
|
||||||
pub const Op = union(enum) {
|
pub const Op = union(enum) {
|
||||||
Call: Call,
|
|
||||||
ArrayAccess: *Node,
|
ArrayAccess: *Node,
|
||||||
Slice: Slice,
|
Slice: Slice,
|
||||||
Deref,
|
Deref,
|
||||||
UnwrapOptional,
|
UnwrapOptional,
|
||||||
|
|
||||||
pub const Call = struct {
|
|
||||||
params: ParamList,
|
|
||||||
async_token: ?TokenIndex,
|
|
||||||
|
|
||||||
pub const ParamList = LinkedList(*Node);
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Slice = struct {
|
pub const Slice = struct {
|
||||||
start: *Node,
|
start: *Node,
|
||||||
end: ?*Node,
|
end: ?*Node,
|
||||||
@ -2148,12 +2248,7 @@ pub const Node = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn iterate(self: *const SuffixOp) Node.Iterator {
|
pub fn iterate(self: *const SuffixOp) Node.Iterator {
|
||||||
return .{ .parent_node = &self.base, .index = 0,
|
return .{ .parent_node = &self.base, .index = 0, .node = null};
|
||||||
.node = switch(self.op) {
|
|
||||||
.Call => |call| call.params.first,
|
|
||||||
else => null,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iterateNext(self: *const SuffixOp, it: *Node.Iterator) ?*Node {
|
pub fn iterateNext(self: *const SuffixOp, it: *Node.Iterator) ?*Node {
|
||||||
@ -2164,13 +2259,6 @@ pub const Node = struct {
|
|||||||
i -= 1;
|
i -= 1;
|
||||||
|
|
||||||
switch (self.op) {
|
switch (self.op) {
|
||||||
.Call => |call_info| {
|
|
||||||
if (it.node) |child| {
|
|
||||||
it.index -= 1;
|
|
||||||
it.node = child.next;
|
|
||||||
return child.data;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.ArrayAccess => |index_expr| {
|
.ArrayAccess => |index_expr| {
|
||||||
if (i < 1) return index_expr;
|
if (i < 1) return index_expr;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
@ -2197,10 +2285,6 @@ pub const Node = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn firstToken(self: *const SuffixOp) TokenIndex {
|
pub fn firstToken(self: *const SuffixOp) TokenIndex {
|
||||||
switch (self.op) {
|
|
||||||
.Call => |*call_info| if (call_info.async_token) |async_token| return async_token,
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
return self.lhs.firstToken();
|
return self.lhs.firstToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2396,22 +2480,36 @@ pub const Node = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Parameters are in memory following BuiltinCall.
|
||||||
pub const BuiltinCall = struct {
|
pub const BuiltinCall = struct {
|
||||||
base: Node = Node{ .id = .BuiltinCall },
|
base: Node = Node{ .id = .BuiltinCall },
|
||||||
|
params_len: NodeIndex,
|
||||||
builtin_token: TokenIndex,
|
builtin_token: TokenIndex,
|
||||||
params: ParamList,
|
|
||||||
rparen_token: TokenIndex,
|
rparen_token: TokenIndex,
|
||||||
|
|
||||||
pub const ParamList = LinkedList(*Node);
|
/// After this the caller must initialize the fields_and_decls list.
|
||||||
|
pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*BuiltinCall {
|
||||||
|
const bytes = try allocator.alignedAlloc(u8, @alignOf(BuiltinCall), sizeInBytes(params_len));
|
||||||
|
return @ptrCast(*BuiltinCall, bytes.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free(self: *BuiltinCall, allocator: *mem.Allocator) void {
|
||||||
|
const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)];
|
||||||
|
allocator.free(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iterate(self: *const BuiltinCall) Node.Iterator {
|
pub fn iterate(self: *const BuiltinCall) Node.Iterator {
|
||||||
return .{ .parent_node = &self.base, .index = 0, .node = self.params.first };
|
return .{ .parent_node = &self.base, .index = 0, .node = null };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iterateNext(self: *const BuiltinCall, it: *Node.Iterator) ?*Node {
|
pub fn iterateNext(self: *const BuiltinCall, it: *Node.Iterator) ?*Node {
|
||||||
const param = it.node orelse return null;
|
var i = it.index;
|
||||||
it.node = param.next;
|
it.index += 1;
|
||||||
return param.data;
|
|
||||||
|
if (i < self.params_len) return self.paramsConst()[i];
|
||||||
|
i -= self.params_len;
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn firstToken(self: *const BuiltinCall) TokenIndex {
|
pub fn firstToken(self: *const BuiltinCall) TokenIndex {
|
||||||
@ -2421,6 +2519,20 @@ pub const Node = struct {
|
|||||||
pub fn lastToken(self: *const BuiltinCall) TokenIndex {
|
pub fn lastToken(self: *const BuiltinCall) TokenIndex {
|
||||||
return self.rparen_token;
|
return self.rparen_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn params(self: *BuiltinCall) []*Node {
|
||||||
|
const decls_start = @ptrCast([*]u8, self) + @sizeOf(BuiltinCall);
|
||||||
|
return @ptrCast([*]*Node, decls_start)[0..self.params_len];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn paramsConst(self: *const BuiltinCall) []const *Node {
|
||||||
|
const decls_start = @ptrCast([*]const u8, self) + @sizeOf(BuiltinCall);
|
||||||
|
return @ptrCast([*]const *Node, decls_start)[0..self.params_len];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sizeInBytes(params_len: NodeIndex) usize {
|
||||||
|
return @sizeOf(BuiltinCall) + @sizeOf(*Node) * @as(usize, params_len);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const StringLiteral = struct {
|
pub const StringLiteral = struct {
|
||||||
@ -2554,106 +2666,102 @@ pub const Node = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const AsmOutput = struct {
|
|
||||||
base: Node = Node{ .id = .AsmOutput },
|
|
||||||
lbracket: TokenIndex,
|
|
||||||
symbolic_name: *Node,
|
|
||||||
constraint: *Node,
|
|
||||||
kind: Kind,
|
|
||||||
rparen: TokenIndex,
|
|
||||||
|
|
||||||
pub const Kind = union(enum) {
|
|
||||||
Variable: *Identifier,
|
|
||||||
Return: *Node,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn iterate(self: *const AsmOutput) Node.Iterator {
|
|
||||||
return .{ .parent_node = &self.base, .index = 0, .node = null };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iterateNext(self: *const AsmOutput, it: *Node.Iterator) ?*Node {
|
|
||||||
var i = it.index;
|
|
||||||
it.index += 1;
|
|
||||||
|
|
||||||
if (i < 1) return self.symbolic_name;
|
|
||||||
i -= 1;
|
|
||||||
|
|
||||||
if (i < 1) return self.constraint;
|
|
||||||
i -= 1;
|
|
||||||
|
|
||||||
switch (self.kind) {
|
|
||||||
.Variable => |variable_name| {
|
|
||||||
if (i < 1) return &variable_name.base;
|
|
||||||
i -= 1;
|
|
||||||
},
|
|
||||||
.Return => |return_type| {
|
|
||||||
if (i < 1) return return_type;
|
|
||||||
i -= 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn firstToken(self: *const AsmOutput) TokenIndex {
|
|
||||||
return self.lbracket;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lastToken(self: *const AsmOutput) TokenIndex {
|
|
||||||
return self.rparen;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const AsmInput = struct {
|
|
||||||
base: Node = Node{ .id = .AsmInput },
|
|
||||||
lbracket: TokenIndex,
|
|
||||||
symbolic_name: *Node,
|
|
||||||
constraint: *Node,
|
|
||||||
expr: *Node,
|
|
||||||
rparen: TokenIndex,
|
|
||||||
|
|
||||||
pub fn iterate(self: *const AsmInput) Node.Iterator {
|
|
||||||
return .{ .parent_node = &self.base, .index = 0, .node = null };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iterateNext(self: *const AsmInput, it: *Node.Iterator) ?*Node {
|
|
||||||
var i = it.index;
|
|
||||||
it.index += 1;
|
|
||||||
|
|
||||||
if (i < 1) return self.symbolic_name;
|
|
||||||
i -= 1;
|
|
||||||
|
|
||||||
if (i < 1) return self.constraint;
|
|
||||||
i -= 1;
|
|
||||||
|
|
||||||
if (i < 1) return self.expr;
|
|
||||||
i -= 1;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn firstToken(self: *const AsmInput) TokenIndex {
|
|
||||||
return self.lbracket;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lastToken(self: *const AsmInput) TokenIndex {
|
|
||||||
return self.rparen;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Asm = struct {
|
pub const Asm = struct {
|
||||||
base: Node = Node{ .id = .Asm },
|
base: Node = Node{ .id = .Asm },
|
||||||
asm_token: TokenIndex,
|
asm_token: TokenIndex,
|
||||||
|
rparen: TokenIndex,
|
||||||
volatile_token: ?TokenIndex,
|
volatile_token: ?TokenIndex,
|
||||||
template: *Node,
|
template: *Node,
|
||||||
outputs: OutputList,
|
outputs: []Output,
|
||||||
inputs: InputList,
|
inputs: []Input,
|
||||||
clobbers: ClobberList,
|
/// A clobber node must be a StringLiteral or MultilineStringLiteral.
|
||||||
rparen: TokenIndex,
|
clobbers: []*Node,
|
||||||
|
|
||||||
|
pub const Output = struct {
|
||||||
|
lbracket: TokenIndex,
|
||||||
|
symbolic_name: *Node,
|
||||||
|
constraint: *Node,
|
||||||
|
kind: Kind,
|
||||||
|
rparen: TokenIndex,
|
||||||
|
|
||||||
|
pub const Kind = union(enum) {
|
||||||
|
Variable: *Identifier,
|
||||||
|
Return: *Node,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn iterate(self: *const Output) Node.Iterator {
|
||||||
|
return .{ .parent_node = &self.base, .index = 0, .node = null };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iterateNext(self: *const Output, it: *Node.Iterator) ?*Node {
|
||||||
|
var i = it.index;
|
||||||
|
it.index += 1;
|
||||||
|
|
||||||
|
if (i < 1) return self.symbolic_name;
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
if (i < 1) return self.constraint;
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
switch (self.kind) {
|
||||||
|
.Variable => |variable_name| {
|
||||||
|
if (i < 1) return &variable_name.base;
|
||||||
|
i -= 1;
|
||||||
|
},
|
||||||
|
.Return => |return_type| {
|
||||||
|
if (i < 1) return return_type;
|
||||||
|
i -= 1;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn firstToken(self: *const Output) TokenIndex {
|
||||||
|
return self.lbracket;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lastToken(self: *const Output) TokenIndex {
|
||||||
|
return self.rparen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Input = struct {
|
||||||
|
lbracket: TokenIndex,
|
||||||
|
symbolic_name: *Node,
|
||||||
|
constraint: *Node,
|
||||||
|
expr: *Node,
|
||||||
|
rparen: TokenIndex,
|
||||||
|
|
||||||
|
pub fn iterate(self: *const Input) Node.Iterator {
|
||||||
|
return .{ .parent_node = &self.base, .index = 0, .node = null };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iterateNext(self: *const Input, it: *Node.Iterator) ?*Node {
|
||||||
|
var i = it.index;
|
||||||
|
it.index += 1;
|
||||||
|
|
||||||
|
if (i < 1) return self.symbolic_name;
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
if (i < 1) return self.constraint;
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
if (i < 1) return self.expr;
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn firstToken(self: *const Input) TokenIndex {
|
||||||
|
return self.lbracket;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lastToken(self: *const Input) TokenIndex {
|
||||||
|
return self.rparen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const OutputList = LinkedList(*AsmOutput);
|
|
||||||
pub const InputList = LinkedList(*AsmInput);
|
|
||||||
pub const ClobberList = LinkedList(*Node);
|
|
||||||
|
|
||||||
pub fn iterate(self: *const Asm) Node.Iterator {
|
pub fn iterate(self: *const Asm) Node.Iterator {
|
||||||
return .{ .parent_node = &self.base, .index = 0, .node = null};
|
return .{ .parent_node = &self.base, .index = 0, .node = null};
|
||||||
@ -2663,19 +2771,24 @@ pub const Node = struct {
|
|||||||
var i = it.index;
|
var i = it.index;
|
||||||
it.index += 1;
|
it.index += 1;
|
||||||
|
|
||||||
var output: ?*LinkedList(*AsmOutput).Node = self.outputs.first;
|
if (i < self.outputs.len * 3) switch (i % 3) {
|
||||||
while (output) |o| {
|
0 => return self.outputs[i / 3].symbolic_name,
|
||||||
if (i < 1) return &o.data.base;
|
1 => return self.outputs[i / 3].constraint,
|
||||||
i -= 1;
|
2 => switch (self.outputs[i / 3].kind) {
|
||||||
output = o.next;
|
.Variable => |variable_name| return &variable_name.base,
|
||||||
}
|
.Return => |return_type| return return_type,
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
i -= self.outputs.len * 3;
|
||||||
|
|
||||||
var input: ?*LinkedList(*AsmInput).Node = self.inputs.first;
|
if (i < self.inputs.len * 3) switch (i % 3) {
|
||||||
while (input) |o| {
|
0 => return self.inputs[i / 3].symbolic_name,
|
||||||
if (i < 1) return &o.data.base;
|
1 => return self.inputs[i / 3].constraint,
|
||||||
i -= 1;
|
2 => return self.inputs[i / 3].expr,
|
||||||
input = o.next;
|
else => unreachable,
|
||||||
}
|
};
|
||||||
|
i -= self.inputs.len * 3;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -520,10 +520,9 @@ const Parser = struct {
|
|||||||
p.putBackToken(token);
|
p.putBackToken(token);
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
var var_args_token: ?TokenIndex = null;
|
|
||||||
const name_token = p.eatToken(.Identifier);
|
const name_token = p.eatToken(.Identifier);
|
||||||
const lparen = try p.expectToken(.LParen);
|
const lparen = try p.expectToken(.LParen);
|
||||||
const params = try p.parseParamDeclList(&var_args_token);
|
const params = try p.parseParamDeclList();
|
||||||
defer p.gpa.free(params);
|
defer p.gpa.free(params);
|
||||||
const rparen = try p.expectToken(.RParen);
|
const rparen = try p.expectToken(.RParen);
|
||||||
const align_expr = try p.parseByteAlign();
|
const align_expr = try p.parseByteAlign();
|
||||||
@ -547,15 +546,19 @@ const Parser = struct {
|
|||||||
else
|
else
|
||||||
R{ .Explicit = return_type_expr.? };
|
R{ .Explicit = return_type_expr.? };
|
||||||
|
|
||||||
const params_len = @intCast(NodeIndex, params.len);
|
const var_args_token = if (params.len > 0) blk: {
|
||||||
|
const param_type = params[params.len - 1].param_type;
|
||||||
|
break :blk if (param_type == .var_args) param_type.var_args else null;
|
||||||
|
} else
|
||||||
|
null;
|
||||||
|
|
||||||
const fn_proto_node = try Node.FnProto.alloc(&p.arena.allocator, params_len);
|
const fn_proto_node = try Node.FnProto.alloc(&p.arena.allocator, params.len);
|
||||||
fn_proto_node.* = .{
|
fn_proto_node.* = .{
|
||||||
.doc_comments = null,
|
.doc_comments = null,
|
||||||
.visib_token = null,
|
.visib_token = null,
|
||||||
.fn_token = fn_token,
|
.fn_token = fn_token,
|
||||||
.name_token = name_token,
|
.name_token = name_token,
|
||||||
.params_len = params_len,
|
.params_len = params.len,
|
||||||
.return_type = return_type,
|
.return_type = return_type,
|
||||||
.var_args_token = var_args_token,
|
.var_args_token = var_args_token,
|
||||||
.extern_export_inline_token = null,
|
.extern_export_inline_token = null,
|
||||||
@ -1455,17 +1458,15 @@ const Parser = struct {
|
|||||||
// ignore this, continue parsing
|
// ignore this, continue parsing
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
const node = try p.arena.allocator.create(Node.SuffixOp);
|
defer p.gpa.free(params.list);
|
||||||
|
const node = try Node.Call.alloc(&p.arena.allocator, params.list.len);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.lhs = res,
|
.lhs = res,
|
||||||
.op = .{
|
.params_len = params.list.len,
|
||||||
.Call = .{
|
.async_token = async_token,
|
||||||
.params = params.list,
|
|
||||||
.async_token = async_token,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.rtoken = params.rparen,
|
.rtoken = params.rparen,
|
||||||
};
|
};
|
||||||
|
std.mem.copy(*Node, node.params(), params.list);
|
||||||
return &node.base;
|
return &node.base;
|
||||||
}
|
}
|
||||||
if (try p.parsePrimaryTypeExpr()) |expr| {
|
if (try p.parsePrimaryTypeExpr()) |expr| {
|
||||||
@ -1482,17 +1483,15 @@ const Parser = struct {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (try p.parseFnCallArguments()) |params| {
|
if (try p.parseFnCallArguments()) |params| {
|
||||||
const call = try p.arena.allocator.create(Node.SuffixOp);
|
defer p.gpa.free(params.list);
|
||||||
|
const call = try Node.Call.alloc(&p.arena.allocator, params.list.len);
|
||||||
call.* = .{
|
call.* = .{
|
||||||
.lhs = res,
|
.lhs = res,
|
||||||
.op = .{
|
.params_len = params.list.len,
|
||||||
.Call = .{
|
.async_token = null,
|
||||||
.params = params.list,
|
|
||||||
.async_token = null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.rtoken = params.rparen,
|
.rtoken = params.rparen,
|
||||||
};
|
};
|
||||||
|
std.mem.copy(*Node, call.params(), params.list);
|
||||||
res = &call.base;
|
res = &call.base;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1615,14 +1614,16 @@ const Parser = struct {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const decls = try p.parseErrorTagList();
|
const decls = try p.parseErrorTagList();
|
||||||
|
defer p.gpa.free(decls);
|
||||||
const rbrace = try p.expectToken(.RBrace);
|
const rbrace = try p.expectToken(.RBrace);
|
||||||
|
|
||||||
const node = try p.arena.allocator.create(Node.ErrorSetDecl);
|
const node = try Node.ErrorSetDecl.alloc(&p.arena.allocator, decls.len);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.error_token = error_token,
|
.error_token = error_token,
|
||||||
.decls = decls,
|
.decls_len = decls.len,
|
||||||
.rbrace_token = rbrace,
|
.rbrace_token = rbrace,
|
||||||
};
|
};
|
||||||
|
std.mem.copy(*Node, node.decls(), decls);
|
||||||
return &node.base;
|
return &node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1769,19 +1770,25 @@ const Parser = struct {
|
|||||||
_ = try p.expectToken(.RParen);
|
_ = try p.expectToken(.RParen);
|
||||||
_ = try p.expectToken(.LBrace);
|
_ = try p.expectToken(.LBrace);
|
||||||
const cases = try p.parseSwitchProngList();
|
const cases = try p.parseSwitchProngList();
|
||||||
|
defer p.gpa.free(cases);
|
||||||
const rbrace = try p.expectToken(.RBrace);
|
const rbrace = try p.expectToken(.RBrace);
|
||||||
|
|
||||||
const node = try p.arena.allocator.create(Node.Switch);
|
const node = try Node.Switch.alloc(&p.arena.allocator, cases.len);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.switch_token = switch_token,
|
.switch_token = switch_token,
|
||||||
.expr = expr_node,
|
.expr = expr_node,
|
||||||
.cases = cases,
|
.cases_len = cases.len,
|
||||||
.rbrace = rbrace,
|
.rbrace = rbrace,
|
||||||
};
|
};
|
||||||
|
std.mem.copy(*Node, node.cases(), cases);
|
||||||
return &node.base;
|
return &node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
|
/// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
|
||||||
|
/// AsmOutput <- COLON AsmOutputList AsmInput?
|
||||||
|
/// AsmInput <- COLON AsmInputList AsmClobbers?
|
||||||
|
/// AsmClobbers <- COLON StringList
|
||||||
|
/// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
|
||||||
fn parseAsmExpr(p: *Parser) !?*Node {
|
fn parseAsmExpr(p: *Parser) !?*Node {
|
||||||
const asm_token = p.eatToken(.Keyword_asm) orelse return null;
|
const asm_token = p.eatToken(.Keyword_asm) orelse return null;
|
||||||
const volatile_token = p.eatToken(.Keyword_volatile);
|
const volatile_token = p.eatToken(.Keyword_volatile);
|
||||||
@ -1790,19 +1797,39 @@ const Parser = struct {
|
|||||||
.ExpectedExpr = .{ .token = p.tok_i },
|
.ExpectedExpr = .{ .token = p.tok_i },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var arena_outputs: []Node.Asm.Output = &[0]Node.Asm.Output{};
|
||||||
|
var arena_inputs: []Node.Asm.Input = &[0]Node.Asm.Input{};
|
||||||
|
var arena_clobbers: []*Node = &[0]*Node{};
|
||||||
|
|
||||||
|
if (p.eatToken(.Colon) != null) {
|
||||||
|
const outputs = try p.parseAsmOutputList();
|
||||||
|
defer p.gpa.free(outputs);
|
||||||
|
arena_outputs = try p.arena.allocator.dupe(Node.Asm.Output, outputs);
|
||||||
|
|
||||||
|
if (p.eatToken(.Colon) != null) {
|
||||||
|
const inputs = try p.parseAsmInputList();
|
||||||
|
defer p.gpa.free(inputs);
|
||||||
|
arena_inputs = try p.arena.allocator.dupe(Node.Asm.Input, inputs);
|
||||||
|
|
||||||
|
if (p.eatToken(.Colon) != null) {
|
||||||
|
const clobbers = try ListParseFn(*Node, parseStringLiteral)(p);
|
||||||
|
defer p.gpa.free(clobbers);
|
||||||
|
arena_clobbers = try p.arena.allocator.dupe(*Node, clobbers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const node = try p.arena.allocator.create(Node.Asm);
|
const node = try p.arena.allocator.create(Node.Asm);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.asm_token = asm_token,
|
.asm_token = asm_token,
|
||||||
.volatile_token = volatile_token,
|
.volatile_token = volatile_token,
|
||||||
.template = template,
|
.template = template,
|
||||||
.outputs = Node.Asm.OutputList{},
|
.outputs = arena_outputs,
|
||||||
.inputs = Node.Asm.InputList{},
|
.inputs = arena_inputs,
|
||||||
.clobbers = Node.Asm.ClobberList{},
|
.clobbers = arena_clobbers,
|
||||||
.rparen = undefined,
|
.rparen = try p.expectToken(.RParen),
|
||||||
};
|
};
|
||||||
|
|
||||||
try p.parseAsmOutput(node);
|
|
||||||
node.rparen = try p.expectToken(.RParen);
|
|
||||||
return &node.base;
|
return &node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1828,15 +1855,8 @@ const Parser = struct {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AsmOutput <- COLON AsmOutputList AsmInput?
|
|
||||||
fn parseAsmOutput(p: *Parser, asm_node: *Node.Asm) !void {
|
|
||||||
if (p.eatToken(.Colon) == null) return;
|
|
||||||
asm_node.outputs = try p.parseAsmOutputList();
|
|
||||||
try p.parseAsmInput(asm_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
|
/// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
|
||||||
fn parseAsmOutputItem(p: *Parser) !?*Node.AsmOutput {
|
fn parseAsmOutputItem(p: *Parser) !?Node.Asm.Output {
|
||||||
const lbracket = p.eatToken(.LBracket) orelse return null;
|
const lbracket = p.eatToken(.LBracket) orelse return null;
|
||||||
const name = try p.expectNode(parseIdentifier, .{
|
const name = try p.expectNode(parseIdentifier, .{
|
||||||
.ExpectedIdentifier = .{ .token = p.tok_i },
|
.ExpectedIdentifier = .{ .token = p.tok_i },
|
||||||
@ -1848,7 +1868,7 @@ const Parser = struct {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_ = try p.expectToken(.LParen);
|
_ = try p.expectToken(.LParen);
|
||||||
const kind: Node.AsmOutput.Kind = blk: {
|
const kind: Node.Asm.Output.Kind = blk: {
|
||||||
if (p.eatToken(.Arrow) != null) {
|
if (p.eatToken(.Arrow) != null) {
|
||||||
const return_ident = try p.expectNode(parseTypeExpr, .{
|
const return_ident = try p.expectNode(parseTypeExpr, .{
|
||||||
.ExpectedTypeExpr = .{ .token = p.tok_i },
|
.ExpectedTypeExpr = .{ .token = p.tok_i },
|
||||||
@ -1862,26 +1882,17 @@ const Parser = struct {
|
|||||||
};
|
};
|
||||||
const rparen = try p.expectToken(.RParen);
|
const rparen = try p.expectToken(.RParen);
|
||||||
|
|
||||||
const node = try p.arena.allocator.create(Node.AsmOutput);
|
return Node.Asm.Output{
|
||||||
node.* = .{
|
|
||||||
.lbracket = lbracket,
|
.lbracket = lbracket,
|
||||||
.symbolic_name = name,
|
.symbolic_name = name,
|
||||||
.constraint = constraint,
|
.constraint = constraint,
|
||||||
.kind = kind,
|
.kind = kind,
|
||||||
.rparen = rparen,
|
.rparen = rparen,
|
||||||
};
|
};
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AsmInput <- COLON AsmInputList AsmClobbers?
|
|
||||||
fn parseAsmInput(p: *Parser, asm_node: *Node.Asm) !void {
|
|
||||||
if (p.eatToken(.Colon) == null) return;
|
|
||||||
asm_node.inputs = try p.parseAsmInputList();
|
|
||||||
try p.parseAsmClobbers(asm_node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
|
/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
|
||||||
fn parseAsmInputItem(p: *Parser) !?*Node.AsmInput {
|
fn parseAsmInputItem(p: *Parser) !?Node.Asm.Input {
|
||||||
const lbracket = p.eatToken(.LBracket) orelse return null;
|
const lbracket = p.eatToken(.LBracket) orelse return null;
|
||||||
const name = try p.expectNode(parseIdentifier, .{
|
const name = try p.expectNode(parseIdentifier, .{
|
||||||
.ExpectedIdentifier = .{ .token = p.tok_i },
|
.ExpectedIdentifier = .{ .token = p.tok_i },
|
||||||
@ -1898,25 +1909,13 @@ const Parser = struct {
|
|||||||
});
|
});
|
||||||
const rparen = try p.expectToken(.RParen);
|
const rparen = try p.expectToken(.RParen);
|
||||||
|
|
||||||
const node = try p.arena.allocator.create(Node.AsmInput);
|
return Node.Asm.Input{
|
||||||
node.* = .{
|
|
||||||
.lbracket = lbracket,
|
.lbracket = lbracket,
|
||||||
.symbolic_name = name,
|
.symbolic_name = name,
|
||||||
.constraint = constraint,
|
.constraint = constraint,
|
||||||
.expr = expr,
|
.expr = expr,
|
||||||
.rparen = rparen,
|
.rparen = rparen,
|
||||||
};
|
};
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AsmClobbers <- COLON StringList
|
|
||||||
/// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
|
|
||||||
fn parseAsmClobbers(p: *Parser, asm_node: *Node.Asm) !void {
|
|
||||||
if (p.eatToken(.Colon) == null) return;
|
|
||||||
asm_node.clobbers = try ListParseFn(
|
|
||||||
Node.Asm.ClobberList,
|
|
||||||
parseStringLiteral,
|
|
||||||
)(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// BreakLabel <- COLON IDENTIFIER
|
/// BreakLabel <- COLON IDENTIFIER
|
||||||
@ -1999,7 +1998,7 @@ const Parser = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
|
/// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
|
||||||
fn parseParamDecl(p: *Parser, list: *std.ArrayList(Node.FnProto.ParamDecl)) !bool {
|
fn parseParamDecl(p: *Parser) !?Node.FnProto.ParamDecl {
|
||||||
const doc_comments = try p.parseDocComment();
|
const doc_comments = try p.parseDocComment();
|
||||||
const noalias_token = p.eatToken(.Keyword_noalias);
|
const noalias_token = p.eatToken(.Keyword_noalias);
|
||||||
const comptime_token = if (noalias_token == null) p.eatToken(.Keyword_comptime) else null;
|
const comptime_token = if (noalias_token == null) p.eatToken(.Keyword_comptime) else null;
|
||||||
@ -2014,21 +2013,23 @@ const Parser = struct {
|
|||||||
if (noalias_token == null and
|
if (noalias_token == null and
|
||||||
comptime_token == null and
|
comptime_token == null and
|
||||||
name_token == null and
|
name_token == null and
|
||||||
doc_comments == null) return false;
|
doc_comments == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
try p.errors.append(p.gpa, .{
|
try p.errors.append(p.gpa, .{
|
||||||
.ExpectedParamType = .{ .token = p.tok_i },
|
.ExpectedParamType = .{ .token = p.tok_i },
|
||||||
});
|
});
|
||||||
return error.ParseError;
|
return error.ParseError;
|
||||||
};
|
};
|
||||||
|
|
||||||
(try list.addOne()).* = .{
|
return Node.FnProto.ParamDecl{
|
||||||
.doc_comments = doc_comments,
|
.doc_comments = doc_comments,
|
||||||
.comptime_token = comptime_token,
|
.comptime_token = comptime_token,
|
||||||
.noalias_token = noalias_token,
|
.noalias_token = noalias_token,
|
||||||
.name_token = name_token,
|
.name_token = name_token,
|
||||||
.param_type = param_type,
|
.param_type = param_type,
|
||||||
};
|
};
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ParamType
|
/// ParamType
|
||||||
@ -2714,13 +2715,14 @@ const Parser = struct {
|
|||||||
/// ExprList <- (Expr COMMA)* Expr?
|
/// ExprList <- (Expr COMMA)* Expr?
|
||||||
fn parseFnCallArguments(p: *Parser) !?AnnotatedParamList {
|
fn parseFnCallArguments(p: *Parser) !?AnnotatedParamList {
|
||||||
if (p.eatToken(.LParen) == null) return null;
|
if (p.eatToken(.LParen) == null) return null;
|
||||||
const list = try ListParseFn(std.SinglyLinkedList(*Node), parseExpr)(p);
|
const list = try ListParseFn(*Node, parseExpr)(p);
|
||||||
|
errdefer p.gpa.free(list);
|
||||||
const rparen = try p.expectToken(.RParen);
|
const rparen = try p.expectToken(.RParen);
|
||||||
return AnnotatedParamList{ .list = list, .rparen = rparen };
|
return AnnotatedParamList{ .list = list, .rparen = rparen };
|
||||||
}
|
}
|
||||||
|
|
||||||
const AnnotatedParamList = struct {
|
const AnnotatedParamList = struct {
|
||||||
list: std.SinglyLinkedList(*Node),
|
list: []*Node,
|
||||||
rparen: TokenIndex,
|
rparen: TokenIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2936,62 +2938,40 @@ const Parser = struct {
|
|||||||
|
|
||||||
/// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER?
|
/// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER?
|
||||||
/// Only ErrorSetDecl parses an IdentifierList
|
/// Only ErrorSetDecl parses an IdentifierList
|
||||||
fn parseErrorTagList(p: *Parser) !Node.ErrorSetDecl.DeclList {
|
fn parseErrorTagList(p: *Parser) ![]*Node {
|
||||||
return ListParseFn(Node.ErrorSetDecl.DeclList, parseErrorTag)(p);
|
return ListParseFn(*Node, parseErrorTag)(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
|
/// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
|
||||||
fn parseSwitchProngList(p: *Parser) !Node.Switch.CaseList {
|
fn parseSwitchProngList(p: *Parser) ![]*Node {
|
||||||
return ListParseFn(Node.Switch.CaseList, parseSwitchProng)(p);
|
return ListParseFn(*Node, parseSwitchProng)(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
|
/// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
|
||||||
fn parseAsmOutputList(p: *Parser) Error!Node.Asm.OutputList {
|
fn parseAsmOutputList(p: *Parser) Error![]Node.Asm.Output {
|
||||||
return ListParseFn(Node.Asm.OutputList, parseAsmOutputItem)(p);
|
return ListParseFn(Node.Asm.Output, parseAsmOutputItem)(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
|
/// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
|
||||||
fn parseAsmInputList(p: *Parser) Error!Node.Asm.InputList {
|
fn parseAsmInputList(p: *Parser) Error![]Node.Asm.Input {
|
||||||
return ListParseFn(Node.Asm.InputList, parseAsmInputItem)(p);
|
return ListParseFn(Node.Asm.Input, parseAsmInputItem)(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
|
/// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
|
||||||
fn parseParamDeclList(p: *Parser, var_args_token: *?TokenIndex) ![]Node.FnProto.ParamDecl {
|
fn parseParamDeclList(p: *Parser) ![]Node.FnProto.ParamDecl {
|
||||||
var list = std.ArrayList(Node.FnProto.ParamDecl).init(p.gpa);
|
return ListParseFn(Node.FnProto.ParamDecl, parseParamDecl)(p);
|
||||||
defer list.deinit();
|
|
||||||
|
|
||||||
while (try p.parseParamDecl(&list)) {
|
|
||||||
switch (p.tokens[p.tok_i].id) {
|
|
||||||
.Comma => _ = p.nextToken(),
|
|
||||||
// all possible delimiters
|
|
||||||
.Colon, .RParen, .RBrace, .RBracket => break,
|
|
||||||
else => {
|
|
||||||
// this is likely just a missing comma,
|
|
||||||
// continue parsing this list and give an error
|
|
||||||
try p.errors.append(p.gpa, .{
|
|
||||||
.ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma },
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (list.items.len != 0) {
|
|
||||||
const param_type = list.items[list.items.len - 1].param_type;
|
|
||||||
if (param_type == .var_args) {
|
|
||||||
var_args_token.* = param_type.var_args;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list.toOwnedSlice();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NodeParseFn = fn (p: *Parser) Error!?*Node;
|
const NodeParseFn = fn (p: *Parser) Error!?*Node;
|
||||||
|
|
||||||
fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {
|
fn ListParseFn(comptime E: type, comptime nodeParseFn: var) ParseFn([]E) {
|
||||||
return struct {
|
return struct {
|
||||||
pub fn parse(p: *Parser) !L {
|
pub fn parse(p: *Parser) ![]E {
|
||||||
var list = L{};
|
var list = std.ArrayList(E).init(p.gpa);
|
||||||
var list_it = &list.first;
|
defer list.deinit();
|
||||||
while (try nodeParseFn(p)) |node| {
|
|
||||||
list_it = try p.llpush(L.Node.Data, list_it, node);
|
while (try nodeParseFn(p)) |item| {
|
||||||
|
try list.append(item);
|
||||||
|
|
||||||
switch (p.tokens[p.tok_i].id) {
|
switch (p.tokens[p.tok_i].id) {
|
||||||
.Comma => _ = p.nextToken(),
|
.Comma => _ = p.nextToken(),
|
||||||
@ -3006,7 +2986,7 @@ const Parser = struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list;
|
return list.toOwnedSlice();
|
||||||
}
|
}
|
||||||
}.parse;
|
}.parse;
|
||||||
}
|
}
|
||||||
@ -3053,12 +3033,15 @@ const Parser = struct {
|
|||||||
};
|
};
|
||||||
return &node.base;
|
return &node.base;
|
||||||
};
|
};
|
||||||
const node = try p.arena.allocator.create(Node.BuiltinCall);
|
defer p.gpa.free(params.list);
|
||||||
|
|
||||||
|
const node = try Node.BuiltinCall.alloc(&p.arena.allocator, params.list.len);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.builtin_token = token,
|
.builtin_token = token,
|
||||||
.params = params.list,
|
.params_len = params.list.len,
|
||||||
.rparen_token = params.rparen,
|
.rparen_token = params.rparen,
|
||||||
};
|
};
|
||||||
|
std.mem.copy(*Node, node.params(), params.list);
|
||||||
return &node.base;
|
return &node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -187,7 +187,10 @@ fn renderRoot(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void {
|
fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void {
|
||||||
const first_token = node.firstToken();
|
return renderExtraNewlineToken(tree, stream, start_col, node.firstToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn renderExtraNewlineToken(tree: *ast.Tree, stream: var, start_col: *usize, first_token: ast.TokenIndex,) @TypeOf(stream).Error!void {
|
||||||
var prev_token = first_token;
|
var prev_token = first_token;
|
||||||
if (prev_token == 0) return;
|
if (prev_token == 0) return;
|
||||||
var newline_threshold: usize = 2;
|
var newline_threshold: usize = 2;
|
||||||
@ -902,74 +905,70 @@ fn renderExpression(
|
|||||||
return renderToken(tree, stream, rtoken, indent, start_col, space);
|
return renderToken(tree, stream, rtoken, indent, start_col, space);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.Call => {
|
||||||
|
const call = @fieldParentPtr(ast.Node.Call, "base", base);
|
||||||
|
if (call.async_token) |async_token| {
|
||||||
|
try renderToken(tree, stream, async_token, indent, start_col, Space.Space);
|
||||||
|
}
|
||||||
|
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, call.lhs, Space.None);
|
||||||
|
|
||||||
|
const lparen = tree.nextToken(call.lhs.lastToken());
|
||||||
|
|
||||||
|
if (call.params_len == 0) {
|
||||||
|
try renderToken(tree, stream, lparen, indent, start_col, Space.None);
|
||||||
|
return renderToken(tree, stream, call.rtoken, indent, start_col, space);
|
||||||
|
}
|
||||||
|
|
||||||
|
const src_has_trailing_comma = blk: {
|
||||||
|
const maybe_comma = tree.prevToken(call.rtoken);
|
||||||
|
break :blk tree.tokens[maybe_comma].id == .Comma;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (src_has_trailing_comma) {
|
||||||
|
const new_indent = indent + indent_delta;
|
||||||
|
try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline);
|
||||||
|
|
||||||
|
const params = call.params();
|
||||||
|
for (params) |param_node, i| {
|
||||||
|
const param_node_new_indent = if (param_node.id == .MultilineStringLiteral) blk: {
|
||||||
|
break :blk indent;
|
||||||
|
} else blk: {
|
||||||
|
try stream.writeByteNTimes(' ', new_indent);
|
||||||
|
break :blk new_indent;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (i + 1 < params.len) {
|
||||||
|
try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.None);
|
||||||
|
const comma = tree.nextToken(param_node.lastToken());
|
||||||
|
try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
|
||||||
|
try renderExtraNewline(tree, stream, start_col, params[i + 1]);
|
||||||
|
} else {
|
||||||
|
try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.Comma);
|
||||||
|
try stream.writeByteNTimes(' ', indent);
|
||||||
|
return renderToken(tree, stream, call.rtoken, indent, start_col, space);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
|
||||||
|
|
||||||
|
const params = call.params();
|
||||||
|
for (params) |param_node, i| {
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
|
||||||
|
|
||||||
|
if (i + 1 < params.len) {
|
||||||
|
const comma = tree.nextToken(param_node.lastToken());
|
||||||
|
try renderToken(tree, stream, comma, indent, start_col, Space.Space);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return renderToken(tree, stream, call.rtoken, indent, start_col, space);
|
||||||
|
},
|
||||||
|
|
||||||
.SuffixOp => {
|
.SuffixOp => {
|
||||||
const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
|
const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
|
||||||
|
|
||||||
switch (suffix_op.op) {
|
switch (suffix_op.op) {
|
||||||
.Call => |*call_info| {
|
|
||||||
if (call_info.async_token) |async_token| {
|
|
||||||
try renderToken(tree, stream, async_token, indent, start_col, Space.Space);
|
|
||||||
}
|
|
||||||
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
|
||||||
|
|
||||||
const lparen = tree.nextToken(suffix_op.lhs.lastToken());
|
|
||||||
|
|
||||||
if (call_info.params.first == null) {
|
|
||||||
try renderToken(tree, stream, lparen, indent, start_col, Space.None);
|
|
||||||
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
|
|
||||||
}
|
|
||||||
|
|
||||||
const src_has_trailing_comma = blk: {
|
|
||||||
const maybe_comma = tree.prevToken(suffix_op.rtoken);
|
|
||||||
break :blk tree.tokens[maybe_comma].id == .Comma;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (src_has_trailing_comma) {
|
|
||||||
const new_indent = indent + indent_delta;
|
|
||||||
try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline);
|
|
||||||
|
|
||||||
var it = call_info.params.first;
|
|
||||||
while (true) {
|
|
||||||
const param_node_node = it.?;
|
|
||||||
it = param_node_node.next;
|
|
||||||
const param_node = param_node_node.data;
|
|
||||||
|
|
||||||
const param_node_new_indent = if (param_node.id == .MultilineStringLiteral) blk: {
|
|
||||||
break :blk indent;
|
|
||||||
} else blk: {
|
|
||||||
try stream.writeByteNTimes(' ', new_indent);
|
|
||||||
break :blk new_indent;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (it) |next_node| {
|
|
||||||
try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.None);
|
|
||||||
const comma = tree.nextToken(param_node.lastToken());
|
|
||||||
try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // ,
|
|
||||||
try renderExtraNewline(tree, stream, start_col, next_node.data);
|
|
||||||
} else {
|
|
||||||
try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.Comma);
|
|
||||||
try stream.writeByteNTimes(' ', indent);
|
|
||||||
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
|
|
||||||
|
|
||||||
var it = call_info.params.first;
|
|
||||||
while (it) |param_node_node| : (it = param_node_node.next) {
|
|
||||||
const param_node = param_node_node.data;
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
|
|
||||||
|
|
||||||
if (param_node_node.next != null) {
|
|
||||||
const comma = tree.nextToken(param_node.lastToken());
|
|
||||||
try renderToken(tree, stream, comma, indent, start_col, Space.Space);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
|
|
||||||
},
|
|
||||||
|
|
||||||
.ArrayAccess => |index_expr| {
|
.ArrayAccess => |index_expr| {
|
||||||
const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
|
const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
|
||||||
const rbracket = tree.nextToken(index_expr.lastToken());
|
const rbracket = tree.nextToken(index_expr.lastToken());
|
||||||
@ -1288,14 +1287,14 @@ fn renderExpression(
|
|||||||
|
|
||||||
const lbrace = tree.nextToken(err_set_decl.error_token);
|
const lbrace = tree.nextToken(err_set_decl.error_token);
|
||||||
|
|
||||||
if (err_set_decl.decls.first == null) {
|
if (err_set_decl.decls_len == 0) {
|
||||||
try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None);
|
try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None);
|
||||||
try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
|
try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
|
||||||
return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space);
|
return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err_set_decl.decls.first.?.next == null) blk: {
|
if (err_set_decl.decls_len == 1) blk: {
|
||||||
const node = err_set_decl.decls.first.?.data;
|
const node = err_set_decl.decls()[0];
|
||||||
|
|
||||||
// if there are any doc comments or same line comments
|
// if there are any doc comments or same line comments
|
||||||
// don't try to put it all on one line
|
// don't try to put it all on one line
|
||||||
@ -1322,16 +1321,15 @@ fn renderExpression(
|
|||||||
try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {
|
try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {
|
||||||
const new_indent = indent + indent_delta;
|
const new_indent = indent + indent_delta;
|
||||||
|
|
||||||
var it = err_set_decl.decls.first;
|
const decls = err_set_decl.decls();
|
||||||
while (it) |node_node| : (it = node_node.next) {
|
for (decls) |node, i| {
|
||||||
const node = node_node.data;
|
|
||||||
try stream.writeByteNTimes(' ', new_indent);
|
try stream.writeByteNTimes(' ', new_indent);
|
||||||
|
|
||||||
if (node_node.next) |next_node| {
|
if (i + 1 < decls.len) {
|
||||||
try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None);
|
try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None);
|
||||||
try renderToken(tree, stream, tree.nextToken(node.lastToken()), new_indent, start_col, Space.Newline); // ,
|
try renderToken(tree, stream, tree.nextToken(node.lastToken()), new_indent, start_col, Space.Newline); // ,
|
||||||
|
|
||||||
try renderExtraNewline(tree, stream, start_col, next_node.data);
|
try renderExtraNewline(tree, stream, start_col, decls[i + 1]);
|
||||||
} else {
|
} else {
|
||||||
try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
|
try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
|
||||||
}
|
}
|
||||||
@ -1342,16 +1340,15 @@ fn renderExpression(
|
|||||||
} else {
|
} else {
|
||||||
try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // {
|
try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // {
|
||||||
|
|
||||||
var it = err_set_decl.decls.first;
|
const decls = err_set_decl.decls();
|
||||||
while (it) |node_node| : (it = node_node.next) {
|
for (decls) |node, i| {
|
||||||
const node = node_node.data;
|
if (i + 1 < decls.len) {
|
||||||
if (node_node.next) |next_node| {
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
|
try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None);
|
||||||
|
|
||||||
const comma_token = tree.nextToken(node.lastToken());
|
const comma_token = tree.nextToken(node.lastToken());
|
||||||
assert(tree.tokens[comma_token].id == .Comma);
|
assert(tree.tokens[comma_token].id == .Comma);
|
||||||
try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
|
try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
|
||||||
try renderExtraNewline(tree, stream, start_col, next_node.data);
|
try renderExtraNewline(tree, stream, start_col, decls[i + 1]);
|
||||||
} else {
|
} else {
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);
|
try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space);
|
||||||
}
|
}
|
||||||
@ -1401,12 +1398,8 @@ fn renderExpression(
|
|||||||
try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name
|
try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name
|
||||||
|
|
||||||
const src_params_trailing_comma = blk: {
|
const src_params_trailing_comma = blk: {
|
||||||
if (builtin_call.params.first == null or
|
if (builtin_call.params_len < 2) break :blk false;
|
||||||
builtin_call.params.first.?.next == null)
|
const last_node = builtin_call.params()[builtin_call.params_len - 1];
|
||||||
{
|
|
||||||
break :blk false;
|
|
||||||
}
|
|
||||||
const last_node = builtin_call.params.first.?.findLast().data;
|
|
||||||
const maybe_comma = tree.nextToken(last_node.lastToken());
|
const maybe_comma = tree.nextToken(last_node.lastToken());
|
||||||
break :blk tree.tokens[maybe_comma].id == .Comma;
|
break :blk tree.tokens[maybe_comma].id == .Comma;
|
||||||
};
|
};
|
||||||
@ -1417,12 +1410,11 @@ fn renderExpression(
|
|||||||
try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
|
try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
|
||||||
|
|
||||||
// render all on one line, no trailing comma
|
// render all on one line, no trailing comma
|
||||||
var it = builtin_call.params.first;
|
const params = builtin_call.params();
|
||||||
while (it) |param_node_node| : (it = param_node_node.next) {
|
for (params) |param_node, i| {
|
||||||
const param_node = param_node_node.data;
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
|
try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None);
|
||||||
|
|
||||||
if (param_node_node.next != null) {
|
if (i + 1 < params.len) {
|
||||||
const comma_token = tree.nextToken(param_node.lastToken());
|
const comma_token = tree.nextToken(param_node.lastToken());
|
||||||
try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
|
try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
|
||||||
}
|
}
|
||||||
@ -1432,9 +1424,7 @@ fn renderExpression(
|
|||||||
const new_indent = indent + indent_delta;
|
const new_indent = indent + indent_delta;
|
||||||
try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (
|
try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // (
|
||||||
|
|
||||||
var it = builtin_call.params.first;
|
for (builtin_call.params()) |param_node| {
|
||||||
while (it) |param_node_node| : (it = param_node_node.next) {
|
|
||||||
const param_node = param_node_node.data;
|
|
||||||
try stream.writeByteNTimes(' ', new_indent);
|
try stream.writeByteNTimes(' ', new_indent);
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.Comma);
|
try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.Comma);
|
||||||
}
|
}
|
||||||
@ -1592,7 +1582,7 @@ fn renderExpression(
|
|||||||
const rparen = tree.nextToken(switch_node.expr.lastToken());
|
const rparen = tree.nextToken(switch_node.expr.lastToken());
|
||||||
const lbrace = tree.nextToken(rparen);
|
const lbrace = tree.nextToken(rparen);
|
||||||
|
|
||||||
if (switch_node.cases.first == null) {
|
if (switch_node.cases_len == 0) {
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);
|
try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None);
|
||||||
try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
|
try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
|
||||||
try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {
|
try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // {
|
||||||
@ -1606,14 +1596,13 @@ fn renderExpression(
|
|||||||
try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
|
try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
|
||||||
try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // {
|
try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // {
|
||||||
|
|
||||||
var it = switch_node.cases.first;
|
const cases = switch_node.cases();
|
||||||
while (it) |node_node| : (it = node_node.next) {
|
for (cases) |node, i| {
|
||||||
const node = node_node.data;
|
|
||||||
try stream.writeByteNTimes(' ', new_indent);
|
try stream.writeByteNTimes(' ', new_indent);
|
||||||
try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
|
try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma);
|
||||||
|
|
||||||
if (node_node.next) |next_node| {
|
if (i + 1 < cases.len) {
|
||||||
try renderExtraNewline(tree, stream, start_col, next_node.data);
|
try renderExtraNewline(tree, stream, start_col, cases[i + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1929,7 +1918,7 @@ fn renderExpression(
|
|||||||
try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), indent, start_col, Space.None); // (
|
try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), indent, start_col, Space.None); // (
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asm_node.outputs.first == null and asm_node.inputs.first == null and asm_node.clobbers.first == null) {
|
if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.None);
|
try renderExpression(allocator, stream, tree, indent, start_col, asm_node.template, Space.None);
|
||||||
return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
|
return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
|
||||||
}
|
}
|
||||||
@ -1949,7 +1938,7 @@ fn renderExpression(
|
|||||||
const colon1 = tree.nextToken(asm_node.template.lastToken());
|
const colon1 = tree.nextToken(asm_node.template.lastToken());
|
||||||
const indent_extra = indent_once + 2;
|
const indent_extra = indent_once + 2;
|
||||||
|
|
||||||
const colon2 = if (asm_node.outputs.first == null) blk: {
|
const colon2 = if (asm_node.outputs.len == 0) blk: {
|
||||||
try renderToken(tree, stream, colon1, indent, start_col, Space.Newline); // :
|
try renderToken(tree, stream, colon1, indent, start_col, Space.Newline); // :
|
||||||
try stream.writeByteNTimes(' ', indent_once);
|
try stream.writeByteNTimes(' ', indent_once);
|
||||||
|
|
||||||
@ -1957,39 +1946,34 @@ fn renderExpression(
|
|||||||
} else blk: {
|
} else blk: {
|
||||||
try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // :
|
try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // :
|
||||||
|
|
||||||
var it = asm_node.outputs.first;
|
for (asm_node.outputs) |*asm_output, i| {
|
||||||
while (true) {
|
if (i + 1 < asm_node.outputs.len) {
|
||||||
const asm_output_node = it.?;
|
const next_asm_output = asm_node.outputs[i + 1];
|
||||||
it = asm_output_node.next;
|
try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.None);
|
||||||
const asm_output = asm_output_node.data;
|
|
||||||
const node = &asm_output.base;
|
|
||||||
|
|
||||||
if (asm_output_node.next) |next_asm_output| {
|
const comma = tree.prevToken(next_asm_output.firstToken());
|
||||||
try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.None);
|
|
||||||
const next_node = &next_asm_output.data.base;
|
|
||||||
|
|
||||||
const comma = tree.prevToken(next_asm_output.data.firstToken());
|
|
||||||
try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
|
try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
|
||||||
try renderExtraNewline(tree, stream, start_col, next_node);
|
try renderExtraNewlineToken(tree, stream, start_col, next_asm_output.firstToken());
|
||||||
|
|
||||||
try stream.writeByteNTimes(' ', indent_extra);
|
try stream.writeByteNTimes(' ', indent_extra);
|
||||||
} else if (asm_node.inputs.first == null and asm_node.clobbers.first == null) {
|
} else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
|
||||||
try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
|
try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
|
||||||
try stream.writeByteNTimes(' ', indent);
|
try stream.writeByteNTimes(' ', indent);
|
||||||
return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
|
return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
|
||||||
} else {
|
} else {
|
||||||
try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
|
try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline);
|
||||||
try stream.writeByteNTimes(' ', indent_once);
|
try stream.writeByteNTimes(' ', indent_once);
|
||||||
const comma_or_colon = tree.nextToken(node.lastToken());
|
const comma_or_colon = tree.nextToken(asm_output.lastToken());
|
||||||
break :blk switch (tree.tokens[comma_or_colon].id) {
|
break :blk switch (tree.tokens[comma_or_colon].id) {
|
||||||
.Comma => tree.nextToken(comma_or_colon),
|
.Comma => tree.nextToken(comma_or_colon),
|
||||||
else => comma_or_colon,
|
else => comma_or_colon,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unreachable;
|
||||||
};
|
};
|
||||||
|
|
||||||
const colon3 = if (asm_node.inputs.first == null) blk: {
|
const colon3 = if (asm_node.inputs.len == 0) blk: {
|
||||||
try renderToken(tree, stream, colon2, indent, start_col, Space.Newline); // :
|
try renderToken(tree, stream, colon2, indent, start_col, Space.Newline); // :
|
||||||
try stream.writeByteNTimes(' ', indent_once);
|
try stream.writeByteNTimes(' ', indent_once);
|
||||||
|
|
||||||
@ -1997,46 +1981,37 @@ fn renderExpression(
|
|||||||
} else blk: {
|
} else blk: {
|
||||||
try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // :
|
try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // :
|
||||||
|
|
||||||
var it = asm_node.inputs.first;
|
for (asm_node.inputs) |*asm_input, i| {
|
||||||
while (true) {
|
if (i + 1 < asm_node.inputs.len) {
|
||||||
const asm_input_node = it.?;
|
const next_asm_input = &asm_node.inputs[i + 1];
|
||||||
it = asm_input_node.next;
|
try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.None);
|
||||||
const node = &asm_input_node.data.base;
|
|
||||||
|
|
||||||
if (it) |next_asm_input| {
|
const comma = tree.prevToken(next_asm_input.firstToken());
|
||||||
try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.None);
|
|
||||||
const next_node = &next_asm_input.data.base;
|
|
||||||
|
|
||||||
const comma = tree.prevToken(next_asm_input.data.firstToken());
|
|
||||||
try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
|
try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // ,
|
||||||
try renderExtraNewline(tree, stream, start_col, next_node);
|
try renderExtraNewlineToken(tree, stream, start_col, next_asm_input.firstToken());
|
||||||
|
|
||||||
try stream.writeByteNTimes(' ', indent_extra);
|
try stream.writeByteNTimes(' ', indent_extra);
|
||||||
} else if (asm_node.clobbers.first == null) {
|
} else if (asm_node.clobbers.len == 0) {
|
||||||
try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
|
try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
|
||||||
try stream.writeByteNTimes(' ', indent);
|
try stream.writeByteNTimes(' ', indent);
|
||||||
return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // )
|
return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // )
|
||||||
} else {
|
} else {
|
||||||
try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline);
|
try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline);
|
||||||
try stream.writeByteNTimes(' ', indent_once);
|
try stream.writeByteNTimes(' ', indent_once);
|
||||||
const comma_or_colon = tree.nextToken(node.lastToken());
|
const comma_or_colon = tree.nextToken(asm_input.lastToken());
|
||||||
break :blk switch (tree.tokens[comma_or_colon].id) {
|
break :blk switch (tree.tokens[comma_or_colon].id) {
|
||||||
.Comma => tree.nextToken(comma_or_colon),
|
.Comma => tree.nextToken(comma_or_colon),
|
||||||
else => comma_or_colon,
|
else => comma_or_colon,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unreachable;
|
||||||
};
|
};
|
||||||
|
|
||||||
try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // :
|
try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // :
|
||||||
|
|
||||||
var it = asm_node.clobbers.first;
|
for (asm_node.clobbers) |clobber_node, i| {
|
||||||
while (true) {
|
if (i + 1 >= asm_node.clobbers.len) {
|
||||||
const clobber_node_node = it.?;
|
|
||||||
it = clobber_node_node.next;
|
|
||||||
const clobber_node = clobber_node_node.data;
|
|
||||||
|
|
||||||
if (it == null) {
|
|
||||||
try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline);
|
try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline);
|
||||||
try stream.writeByteNTimes(' ', indent);
|
try stream.writeByteNTimes(' ', indent);
|
||||||
return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
|
return renderToken(tree, stream, asm_node.rparen, indent, start_col, space);
|
||||||
@ -2048,40 +2023,6 @@ fn renderExpression(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.AsmInput => {
|
|
||||||
const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
|
|
||||||
|
|
||||||
try stream.writeAll("[");
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);
|
|
||||||
try stream.writeAll("] ");
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);
|
|
||||||
try stream.writeAll(" (");
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);
|
|
||||||
return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )
|
|
||||||
},
|
|
||||||
|
|
||||||
.AsmOutput => {
|
|
||||||
const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
|
|
||||||
|
|
||||||
try stream.writeAll("[");
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);
|
|
||||||
try stream.writeAll("] ");
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);
|
|
||||||
try stream.writeAll(" (");
|
|
||||||
|
|
||||||
switch (asm_output.kind) {
|
|
||||||
ast.Node.AsmOutput.Kind.Variable => |variable_name| {
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);
|
|
||||||
},
|
|
||||||
ast.Node.AsmOutput.Kind.Return => |return_type| {
|
|
||||||
try stream.writeAll("-> ");
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // )
|
|
||||||
},
|
|
||||||
|
|
||||||
.EnumLiteral => {
|
.EnumLiteral => {
|
||||||
const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);
|
const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base);
|
||||||
|
|
||||||
@ -2098,6 +2039,52 @@ fn renderExpression(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn renderAsmOutput(
|
||||||
|
allocator: *mem.Allocator,
|
||||||
|
stream: var,
|
||||||
|
tree: *ast.Tree,
|
||||||
|
indent: usize,
|
||||||
|
start_col: *usize,
|
||||||
|
asm_output: *const ast.Node.Asm.Output,
|
||||||
|
space: Space,
|
||||||
|
) (@TypeOf(stream).Error || Error)!void {
|
||||||
|
try stream.writeAll("[");
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);
|
||||||
|
try stream.writeAll("] ");
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);
|
||||||
|
try stream.writeAll(" (");
|
||||||
|
|
||||||
|
switch (asm_output.kind) {
|
||||||
|
ast.Node.Asm.Output.Kind.Variable => |variable_name| {
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);
|
||||||
|
},
|
||||||
|
ast.Node.Asm.Output.Kind.Return => |return_type| {
|
||||||
|
try stream.writeAll("-> ");
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // )
|
||||||
|
}
|
||||||
|
|
||||||
|
fn renderAsmInput(
|
||||||
|
allocator: *mem.Allocator,
|
||||||
|
stream: var,
|
||||||
|
tree: *ast.Tree,
|
||||||
|
indent: usize,
|
||||||
|
start_col: *usize,
|
||||||
|
asm_input: *const ast.Node.Asm.Input,
|
||||||
|
space: Space,
|
||||||
|
) (@TypeOf(stream).Error || Error)!void {
|
||||||
|
try stream.writeAll("[");
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);
|
||||||
|
try stream.writeAll("] ");
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);
|
||||||
|
try stream.writeAll(" (");
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);
|
||||||
|
return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )
|
||||||
|
}
|
||||||
|
|
||||||
fn renderVarDecl(
|
fn renderVarDecl(
|
||||||
allocator: *mem.Allocator,
|
allocator: *mem.Allocator,
|
||||||
stream: var,
|
stream: var,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user