mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
stage2 parser: split out PrefixOp into separate AST Nodes
This is part of a larger effort to improve the memory layout of AST nodes of the self-hosted parser to reduce wasted memory. Reduction of wasted memory also translates to improved performance because of fewer memory allocations, and fewer cache misses. Compared to master, when running `zig fmt` on the std lib: * cache-misses: 801,829 => 768,624 * instructions: 3,234,877,167 => 3,232,075,022 * peak memory: 81480 KB => 75964 KB
This commit is contained in:
parent
204f61d7f5
commit
14cef9dd3d
@ -410,7 +410,20 @@ pub const Node = struct {
|
|||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
InfixOp,
|
InfixOp,
|
||||||
PrefixOp,
|
AddressOf,
|
||||||
|
Await,
|
||||||
|
BitNot,
|
||||||
|
BoolNot,
|
||||||
|
OptionalType,
|
||||||
|
Negation,
|
||||||
|
NegationWrap,
|
||||||
|
Resume,
|
||||||
|
Try,
|
||||||
|
ArrayType,
|
||||||
|
/// ArrayType but has a sentinel node.
|
||||||
|
ArrayTypeSentinel,
|
||||||
|
PtrType,
|
||||||
|
SliceType,
|
||||||
/// Not all suffix operations are under this tag. To save memory, some
|
/// Not all suffix operations are under this tag. To save memory, some
|
||||||
/// suffix operations have dedicated Node tags.
|
/// suffix operations have dedicated Node tags.
|
||||||
SuffixOp,
|
SuffixOp,
|
||||||
@ -1797,85 +1810,116 @@ pub const Node = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const PrefixOp = struct {
|
pub const AddressOf = SimplePrefixOp(.AddressOf);
|
||||||
base: Node = Node{ .id = .PrefixOp },
|
pub const Await = SimplePrefixOp(.Await);
|
||||||
|
pub const BitNot = SimplePrefixOp(.BitNot);
|
||||||
|
pub const BoolNot = SimplePrefixOp(.BoolNot);
|
||||||
|
pub const OptionalType = SimplePrefixOp(.OptionalType);
|
||||||
|
pub const Negation = SimplePrefixOp(.Negation);
|
||||||
|
pub const NegationWrap = SimplePrefixOp(.NegationWrap);
|
||||||
|
pub const Resume = SimplePrefixOp(.Resume);
|
||||||
|
pub const Try = SimplePrefixOp(.Try);
|
||||||
|
|
||||||
|
pub fn SimplePrefixOp(comptime tag: Id) type {
|
||||||
|
return struct {
|
||||||
|
base: Node = Node{ .id = tag },
|
||||||
|
op_token: TokenIndex,
|
||||||
|
rhs: *Node,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn iterate(self: *const Self, index: usize) ?*Node {
|
||||||
|
if (index == 0) return self.rhs;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn firstToken(self: *const Self) TokenIndex {
|
||||||
|
return self.op_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lastToken(self: *const Self) TokenIndex {
|
||||||
|
return self.rhs.lastToken();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ArrayType = struct {
|
||||||
|
base: Node = Node{ .id = .ArrayType },
|
||||||
op_token: TokenIndex,
|
op_token: TokenIndex,
|
||||||
op: Op,
|
|
||||||
rhs: *Node,
|
rhs: *Node,
|
||||||
|
len_expr: *Node,
|
||||||
|
|
||||||
pub const Op = union(enum) {
|
pub fn iterate(self: *const ArrayType, index: usize) ?*Node {
|
||||||
AddressOf,
|
|
||||||
ArrayType: ArrayInfo,
|
|
||||||
Await,
|
|
||||||
BitNot,
|
|
||||||
BoolNot,
|
|
||||||
OptionalType,
|
|
||||||
Negation,
|
|
||||||
NegationWrap,
|
|
||||||
Resume,
|
|
||||||
PtrType: PtrInfo,
|
|
||||||
SliceType: PtrInfo,
|
|
||||||
Try,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ArrayInfo = struct {
|
|
||||||
len_expr: *Node,
|
|
||||||
sentinel: ?*Node,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const PtrInfo = struct {
|
|
||||||
allowzero_token: ?TokenIndex = null,
|
|
||||||
align_info: ?Align = null,
|
|
||||||
const_token: ?TokenIndex = null,
|
|
||||||
volatile_token: ?TokenIndex = null,
|
|
||||||
sentinel: ?*Node = null,
|
|
||||||
|
|
||||||
pub const Align = struct {
|
|
||||||
node: *Node,
|
|
||||||
bit_range: ?BitRange,
|
|
||||||
|
|
||||||
pub const BitRange = struct {
|
|
||||||
start: *Node,
|
|
||||||
end: *Node,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn iterate(self: *const PrefixOp, index: usize) ?*Node {
|
|
||||||
var i = index;
|
var i = index;
|
||||||
|
|
||||||
switch (self.op) {
|
if (i < 1) return self.len_expr;
|
||||||
.PtrType, .SliceType => |addr_of_info| {
|
i -= 1;
|
||||||
if (addr_of_info.sentinel) |sentinel| {
|
|
||||||
if (i < 1) return sentinel;
|
|
||||||
i -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addr_of_info.align_info) |align_info| {
|
if (i < 1) return self.rhs;
|
||||||
if (i < 1) return align_info.node;
|
i -= 1;
|
||||||
i -= 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.ArrayType => |array_info| {
|
return null;
|
||||||
if (i < 1) return array_info.len_expr;
|
}
|
||||||
i -= 1;
|
|
||||||
if (array_info.sentinel) |sentinel| {
|
|
||||||
if (i < 1) return sentinel;
|
|
||||||
i -= 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.AddressOf,
|
pub fn firstToken(self: *const ArrayType) TokenIndex {
|
||||||
.Await,
|
return self.op_token;
|
||||||
.BitNot,
|
}
|
||||||
.BoolNot,
|
|
||||||
.OptionalType,
|
pub fn lastToken(self: *const ArrayType) TokenIndex {
|
||||||
.Negation,
|
return self.rhs.lastToken();
|
||||||
.NegationWrap,
|
}
|
||||||
.Try,
|
};
|
||||||
.Resume,
|
|
||||||
=> {},
|
pub const ArrayTypeSentinel = struct {
|
||||||
|
base: Node = Node{ .id = .ArrayTypeSentinel },
|
||||||
|
op_token: TokenIndex,
|
||||||
|
rhs: *Node,
|
||||||
|
len_expr: *Node,
|
||||||
|
sentinel: *Node,
|
||||||
|
|
||||||
|
pub fn iterate(self: *const ArrayTypeSentinel, index: usize) ?*Node {
|
||||||
|
var i = index;
|
||||||
|
|
||||||
|
if (i < 1) return self.len_expr;
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
if (i < 1) return self.sentinel;
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
if (i < 1) return self.rhs;
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn firstToken(self: *const ArrayTypeSentinel) TokenIndex {
|
||||||
|
return self.op_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lastToken(self: *const ArrayTypeSentinel) TokenIndex {
|
||||||
|
return self.rhs.lastToken();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const PtrType = struct {
|
||||||
|
base: Node = Node{ .id = .PtrType },
|
||||||
|
op_token: TokenIndex,
|
||||||
|
rhs: *Node,
|
||||||
|
/// TODO Add a u8 flags field to Node where it would otherwise be padding, and each bit represents
|
||||||
|
/// one of these possibly-null things. Then we have them directly follow the PtrType in memory.
|
||||||
|
ptr_info: PtrInfo = .{},
|
||||||
|
|
||||||
|
pub fn iterate(self: *const PtrType, index: usize) ?*Node {
|
||||||
|
var i = index;
|
||||||
|
|
||||||
|
if (self.ptr_info.sentinel) |sentinel| {
|
||||||
|
if (i < 1) return sentinel;
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.ptr_info.align_info) |align_info| {
|
||||||
|
if (i < 1) return align_info.node;
|
||||||
|
i -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < 1) return self.rhs;
|
if (i < 1) return self.rhs;
|
||||||
@ -1884,11 +1928,47 @@ pub const Node = struct {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn firstToken(self: *const PrefixOp) TokenIndex {
|
pub fn firstToken(self: *const PtrType) TokenIndex {
|
||||||
return self.op_token;
|
return self.op_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lastToken(self: *const PrefixOp) TokenIndex {
|
pub fn lastToken(self: *const PtrType) TokenIndex {
|
||||||
|
return self.rhs.lastToken();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const SliceType = struct {
|
||||||
|
base: Node = Node{ .id = .SliceType },
|
||||||
|
op_token: TokenIndex,
|
||||||
|
rhs: *Node,
|
||||||
|
/// TODO Add a u8 flags field to Node where it would otherwise be padding, and each bit represents
|
||||||
|
/// one of these possibly-null things. Then we have them directly follow the SliceType in memory.
|
||||||
|
ptr_info: PtrInfo = .{},
|
||||||
|
|
||||||
|
pub fn iterate(self: *const SliceType, index: usize) ?*Node {
|
||||||
|
var i = index;
|
||||||
|
|
||||||
|
if (self.ptr_info.sentinel) |sentinel| {
|
||||||
|
if (i < 1) return sentinel;
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.ptr_info.align_info) |align_info| {
|
||||||
|
if (i < 1) return align_info.node;
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < 1) return self.rhs;
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn firstToken(self: *const SliceType) TokenIndex {
|
||||||
|
return self.op_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lastToken(self: *const SliceType) TokenIndex {
|
||||||
return self.rhs.lastToken();
|
return self.rhs.lastToken();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -2797,6 +2877,24 @@ pub const Node = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const PtrInfo = struct {
|
||||||
|
allowzero_token: ?TokenIndex = null,
|
||||||
|
align_info: ?Align = null,
|
||||||
|
const_token: ?TokenIndex = null,
|
||||||
|
volatile_token: ?TokenIndex = null,
|
||||||
|
sentinel: ?*Node = null,
|
||||||
|
|
||||||
|
pub const Align = struct {
|
||||||
|
node: *Node,
|
||||||
|
bit_range: ?BitRange = null,
|
||||||
|
|
||||||
|
pub const BitRange = struct {
|
||||||
|
start: *Node,
|
||||||
|
end: *Node,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
test "iterate" {
|
test "iterate" {
|
||||||
var root = Node.Root{
|
var root = Node.Root{
|
||||||
.base = Node{ .id = Node.Id.Root },
|
.base = Node{ .id = Node.Id.Root },
|
||||||
|
|||||||
@ -1120,10 +1120,9 @@ const Parser = struct {
|
|||||||
const expr_node = try p.expectNode(parseExpr, .{
|
const expr_node = try p.expectNode(parseExpr, .{
|
||||||
.ExpectedExpr = .{ .token = p.tok_i },
|
.ExpectedExpr = .{ .token = p.tok_i },
|
||||||
});
|
});
|
||||||
const node = try p.arena.allocator.create(Node.PrefixOp);
|
const node = try p.arena.allocator.create(Node.Resume);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.op_token = token,
|
.op_token = token,
|
||||||
.op = .Resume,
|
|
||||||
.rhs = expr_node,
|
.rhs = expr_node,
|
||||||
};
|
};
|
||||||
return &node.base;
|
return &node.base;
|
||||||
@ -2413,24 +2412,25 @@ const Parser = struct {
|
|||||||
/// / KEYWORD_await
|
/// / KEYWORD_await
|
||||||
fn parsePrefixOp(p: *Parser) !?*Node {
|
fn parsePrefixOp(p: *Parser) !?*Node {
|
||||||
const token = p.nextToken();
|
const token = p.nextToken();
|
||||||
const op: Node.PrefixOp.Op = switch (p.token_ids[token]) {
|
switch (p.token_ids[token]) {
|
||||||
.Bang => .BoolNot,
|
.Bang => return p.allocSimplePrefixOp(.BoolNot, token),
|
||||||
.Minus => .Negation,
|
.Minus => return p.allocSimplePrefixOp(.Negation, token),
|
||||||
.Tilde => .BitNot,
|
.Tilde => return p.allocSimplePrefixOp(.BitNot, token),
|
||||||
.MinusPercent => .NegationWrap,
|
.MinusPercent => return p.allocSimplePrefixOp(.NegationWrap, token),
|
||||||
.Ampersand => .AddressOf,
|
.Ampersand => return p.allocSimplePrefixOp(.AddressOf, token),
|
||||||
.Keyword_try => .Try,
|
.Keyword_try => return p.allocSimplePrefixOp(.Try, token),
|
||||||
.Keyword_await => .Await,
|
.Keyword_await => return p.allocSimplePrefixOp(.Await, token),
|
||||||
else => {
|
else => {
|
||||||
p.putBackToken(token);
|
p.putBackToken(token);
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const node = try p.arena.allocator.create(Node.PrefixOp);
|
fn allocSimplePrefixOp(p: *Parser, comptime tag: Node.Id, token: TokenIndex) !?*Node {
|
||||||
|
const node = try p.arena.allocator.create(Node.SimplePrefixOp(tag));
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.op_token = token,
|
.op_token = token,
|
||||||
.op = op,
|
|
||||||
.rhs = undefined, // set by caller
|
.rhs = undefined, // set by caller
|
||||||
};
|
};
|
||||||
return &node.base;
|
return &node.base;
|
||||||
@ -2450,19 +2450,14 @@ const Parser = struct {
|
|||||||
/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
||||||
fn parsePrefixTypeOp(p: *Parser) !?*Node {
|
fn parsePrefixTypeOp(p: *Parser) !?*Node {
|
||||||
if (p.eatToken(.QuestionMark)) |token| {
|
if (p.eatToken(.QuestionMark)) |token| {
|
||||||
const node = try p.arena.allocator.create(Node.PrefixOp);
|
const node = try p.arena.allocator.create(Node.OptionalType);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.op_token = token,
|
.op_token = token,
|
||||||
.op = .OptionalType,
|
|
||||||
.rhs = undefined, // set by caller
|
.rhs = undefined, // set by caller
|
||||||
};
|
};
|
||||||
return &node.base;
|
return &node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or
|
|
||||||
// .return_type more difficult for the caller (see parsePrefixOpExpr helper).
|
|
||||||
// Consider making the AnyFrameType a member of PrefixOp and add a
|
|
||||||
// PrefixOp.AnyFrameType variant?
|
|
||||||
if (p.eatToken(.Keyword_anyframe)) |token| {
|
if (p.eatToken(.Keyword_anyframe)) |token| {
|
||||||
const arrow = p.eatToken(.Arrow) orelse {
|
const arrow = p.eatToken(.Arrow) orelse {
|
||||||
p.putBackToken(token);
|
p.putBackToken(token);
|
||||||
@ -2482,11 +2477,15 @@ const Parser = struct {
|
|||||||
if (try p.parsePtrTypeStart()) |node| {
|
if (try p.parsePtrTypeStart()) |node| {
|
||||||
// If the token encountered was **, there will be two nodes instead of one.
|
// If the token encountered was **, there will be two nodes instead of one.
|
||||||
// The attributes should be applied to the rightmost operator.
|
// The attributes should be applied to the rightmost operator.
|
||||||
const prefix_op = node.cast(Node.PrefixOp).?;
|
var ptr_info = if (node.cast(Node.PtrType)) |ptr_type|
|
||||||
var ptr_info = if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk)
|
if (p.token_ids[ptr_type.op_token] == .AsteriskAsterisk)
|
||||||
&prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType
|
&ptr_type.rhs.cast(Node.PtrType).?.ptr_info
|
||||||
|
else
|
||||||
|
&ptr_type.ptr_info
|
||||||
|
else if (node.cast(Node.SliceType)) |slice_type|
|
||||||
|
&slice_type.ptr_info
|
||||||
else
|
else
|
||||||
&prefix_op.op.PtrType;
|
unreachable;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (p.eatToken(.Keyword_align)) |align_token| {
|
if (p.eatToken(.Keyword_align)) |align_token| {
|
||||||
@ -2505,7 +2504,7 @@ const Parser = struct {
|
|||||||
.ExpectedIntegerLiteral = .{ .token = p.tok_i },
|
.ExpectedIntegerLiteral = .{ .token = p.tok_i },
|
||||||
});
|
});
|
||||||
|
|
||||||
break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{
|
break :bit_range_value ast.PtrInfo.Align.BitRange{
|
||||||
.start = range_start,
|
.start = range_start,
|
||||||
.end = range_end,
|
.end = range_end,
|
||||||
};
|
};
|
||||||
@ -2519,7 +2518,7 @@ const Parser = struct {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{
|
ptr_info.align_info = ast.PtrInfo.Align{
|
||||||
.node = expr_node,
|
.node = expr_node,
|
||||||
.bit_range = bit_range,
|
.bit_range = bit_range,
|
||||||
};
|
};
|
||||||
@ -2563,58 +2562,54 @@ const Parser = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (try p.parseArrayTypeStart()) |node| {
|
if (try p.parseArrayTypeStart()) |node| {
|
||||||
switch (node.cast(Node.PrefixOp).?.op) {
|
if (node.cast(Node.SliceType)) |slice_type| {
|
||||||
.ArrayType => {},
|
// Collect pointer qualifiers in any order, but disallow duplicates
|
||||||
.SliceType => |*slice_type| {
|
while (true) {
|
||||||
// Collect pointer qualifiers in any order, but disallow duplicates
|
if (try p.parseByteAlign()) |align_expr| {
|
||||||
while (true) {
|
if (slice_type.ptr_info.align_info != null) {
|
||||||
if (try p.parseByteAlign()) |align_expr| {
|
try p.errors.append(p.gpa, .{
|
||||||
if (slice_type.align_info != null) {
|
.ExtraAlignQualifier = .{ .token = p.tok_i - 1 },
|
||||||
try p.errors.append(p.gpa, .{
|
});
|
||||||
.ExtraAlignQualifier = .{ .token = p.tok_i - 1 },
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
slice_type.align_info = Node.PrefixOp.PtrInfo.Align{
|
|
||||||
.node = align_expr,
|
|
||||||
.bit_range = null,
|
|
||||||
};
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (p.eatToken(.Keyword_const)) |const_token| {
|
slice_type.ptr_info.align_info = ast.PtrInfo.Align{
|
||||||
if (slice_type.const_token != null) {
|
.node = align_expr,
|
||||||
try p.errors.append(p.gpa, .{
|
.bit_range = null,
|
||||||
.ExtraConstQualifier = .{ .token = p.tok_i - 1 },
|
};
|
||||||
});
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
slice_type.const_token = const_token;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (p.eatToken(.Keyword_volatile)) |volatile_token| {
|
|
||||||
if (slice_type.volatile_token != null) {
|
|
||||||
try p.errors.append(p.gpa, .{
|
|
||||||
.ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
slice_type.volatile_token = volatile_token;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
|
|
||||||
if (slice_type.allowzero_token != null) {
|
|
||||||
try p.errors.append(p.gpa, .{
|
|
||||||
.ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
slice_type.allowzero_token = allowzero_token;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
},
|
if (p.eatToken(.Keyword_const)) |const_token| {
|
||||||
else => unreachable,
|
if (slice_type.ptr_info.const_token != null) {
|
||||||
|
try p.errors.append(p.gpa, .{
|
||||||
|
.ExtraConstQualifier = .{ .token = p.tok_i - 1 },
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
slice_type.ptr_info.const_token = const_token;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (p.eatToken(.Keyword_volatile)) |volatile_token| {
|
||||||
|
if (slice_type.ptr_info.volatile_token != null) {
|
||||||
|
try p.errors.append(p.gpa, .{
|
||||||
|
.ExtraVolatileQualifier = .{ .token = p.tok_i - 1 },
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
slice_type.ptr_info.volatile_token = volatile_token;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (p.eatToken(.Keyword_allowzero)) |allowzero_token| {
|
||||||
|
if (slice_type.ptr_info.allowzero_token != null) {
|
||||||
|
try p.errors.append(p.gpa, .{
|
||||||
|
.ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 },
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
slice_type.ptr_info.allowzero_token = allowzero_token;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -2728,29 +2723,32 @@ const Parser = struct {
|
|||||||
null;
|
null;
|
||||||
const rbracket = try p.expectToken(.RBracket);
|
const rbracket = try p.expectToken(.RBracket);
|
||||||
|
|
||||||
const op: Node.PrefixOp.Op = if (expr) |len_expr|
|
if (expr) |len_expr| {
|
||||||
.{
|
if (sentinel) |s| {
|
||||||
.ArrayType = .{
|
const node = try p.arena.allocator.create(Node.ArrayTypeSentinel);
|
||||||
|
node.* = .{
|
||||||
|
.op_token = lbracket,
|
||||||
|
.rhs = undefined, // set by caller
|
||||||
.len_expr = len_expr,
|
.len_expr = len_expr,
|
||||||
.sentinel = sentinel,
|
.sentinel = s,
|
||||||
},
|
};
|
||||||
|
return &node.base;
|
||||||
|
} else {
|
||||||
|
const node = try p.arena.allocator.create(Node.ArrayType);
|
||||||
|
node.* = .{
|
||||||
|
.op_token = lbracket,
|
||||||
|
.rhs = undefined, // set by caller
|
||||||
|
.len_expr = len_expr,
|
||||||
|
};
|
||||||
|
return &node.base;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
.{
|
|
||||||
.SliceType = Node.PrefixOp.PtrInfo{
|
|
||||||
.allowzero_token = null,
|
|
||||||
.align_info = null,
|
|
||||||
.const_token = null,
|
|
||||||
.volatile_token = null,
|
|
||||||
.sentinel = sentinel,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const node = try p.arena.allocator.create(Node.PrefixOp);
|
const node = try p.arena.allocator.create(Node.SliceType);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.op_token = lbracket,
|
.op_token = lbracket,
|
||||||
.op = op,
|
|
||||||
.rhs = undefined, // set by caller
|
.rhs = undefined, // set by caller
|
||||||
|
.ptr_info = .{ .sentinel = sentinel },
|
||||||
};
|
};
|
||||||
return &node.base;
|
return &node.base;
|
||||||
}
|
}
|
||||||
@ -2768,28 +2766,26 @@ const Parser = struct {
|
|||||||
})
|
})
|
||||||
else
|
else
|
||||||
null;
|
null;
|
||||||
const node = try p.arena.allocator.create(Node.PrefixOp);
|
const node = try p.arena.allocator.create(Node.PtrType);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.op_token = asterisk,
|
.op_token = asterisk,
|
||||||
.op = .{ .PtrType = .{ .sentinel = sentinel } },
|
|
||||||
.rhs = undefined, // set by caller
|
.rhs = undefined, // set by caller
|
||||||
|
.ptr_info = .{ .sentinel = sentinel },
|
||||||
};
|
};
|
||||||
return &node.base;
|
return &node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.eatToken(.AsteriskAsterisk)) |double_asterisk| {
|
if (p.eatToken(.AsteriskAsterisk)) |double_asterisk| {
|
||||||
const node = try p.arena.allocator.create(Node.PrefixOp);
|
const node = try p.arena.allocator.create(Node.PtrType);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.op_token = double_asterisk,
|
.op_token = double_asterisk,
|
||||||
.op = .{ .PtrType = .{} },
|
|
||||||
.rhs = undefined, // set by caller
|
.rhs = undefined, // set by caller
|
||||||
};
|
};
|
||||||
|
|
||||||
// Special case for **, which is its own token
|
// Special case for **, which is its own token
|
||||||
const child = try p.arena.allocator.create(Node.PrefixOp);
|
const child = try p.arena.allocator.create(Node.PtrType);
|
||||||
child.* = .{
|
child.* = .{
|
||||||
.op_token = double_asterisk,
|
.op_token = double_asterisk,
|
||||||
.op = .{ .PtrType = .{} },
|
|
||||||
.rhs = undefined, // set by caller
|
.rhs = undefined, // set by caller
|
||||||
};
|
};
|
||||||
node.rhs = &child.base;
|
node.rhs = &child.base;
|
||||||
@ -2808,10 +2804,9 @@ const Parser = struct {
|
|||||||
p.putBackToken(ident);
|
p.putBackToken(ident);
|
||||||
} else {
|
} else {
|
||||||
_ = try p.expectToken(.RBracket);
|
_ = try p.expectToken(.RBracket);
|
||||||
const node = try p.arena.allocator.create(Node.PrefixOp);
|
const node = try p.arena.allocator.create(Node.PtrType);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.op_token = lbracket,
|
.op_token = lbracket,
|
||||||
.op = .{ .PtrType = .{} },
|
|
||||||
.rhs = undefined, // set by caller
|
.rhs = undefined, // set by caller
|
||||||
};
|
};
|
||||||
return &node.base;
|
return &node.base;
|
||||||
@ -2824,11 +2819,11 @@ const Parser = struct {
|
|||||||
else
|
else
|
||||||
null;
|
null;
|
||||||
_ = try p.expectToken(.RBracket);
|
_ = try p.expectToken(.RBracket);
|
||||||
const node = try p.arena.allocator.create(Node.PrefixOp);
|
const node = try p.arena.allocator.create(Node.PtrType);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.op_token = lbracket,
|
.op_token = lbracket,
|
||||||
.op = .{ .PtrType = .{ .sentinel = sentinel } },
|
|
||||||
.rhs = undefined, // set by caller
|
.rhs = undefined, // set by caller
|
||||||
|
.ptr_info = .{ .sentinel = sentinel },
|
||||||
};
|
};
|
||||||
return &node.base;
|
return &node.base;
|
||||||
}
|
}
|
||||||
@ -3146,10 +3141,9 @@ const Parser = struct {
|
|||||||
|
|
||||||
fn parseTry(p: *Parser) !?*Node {
|
fn parseTry(p: *Parser) !?*Node {
|
||||||
const token = p.eatToken(.Keyword_try) orelse return null;
|
const token = p.eatToken(.Keyword_try) orelse return null;
|
||||||
const node = try p.arena.allocator.create(Node.PrefixOp);
|
const node = try p.arena.allocator.create(Node.Try);
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.op_token = token,
|
.op_token = token,
|
||||||
.op = .Try,
|
|
||||||
.rhs = undefined, // set by caller
|
.rhs = undefined, // set by caller
|
||||||
};
|
};
|
||||||
return &node.base;
|
return &node.base;
|
||||||
@ -3228,15 +3222,87 @@ const Parser = struct {
|
|||||||
var rightmost_op = first_op;
|
var rightmost_op = first_op;
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (rightmost_op.id) {
|
switch (rightmost_op.id) {
|
||||||
.PrefixOp => {
|
.AddressOf => {
|
||||||
var prefix_op = rightmost_op.cast(Node.PrefixOp).?;
|
if (try opParseFn(p)) |rhs| {
|
||||||
|
rightmost_op.cast(Node.AddressOf).?.rhs = rhs;
|
||||||
|
rightmost_op = rhs;
|
||||||
|
} else break;
|
||||||
|
},
|
||||||
|
.Await => {
|
||||||
|
if (try opParseFn(p)) |rhs| {
|
||||||
|
rightmost_op.cast(Node.Await).?.rhs = rhs;
|
||||||
|
rightmost_op = rhs;
|
||||||
|
} else break;
|
||||||
|
},
|
||||||
|
.BitNot => {
|
||||||
|
if (try opParseFn(p)) |rhs| {
|
||||||
|
rightmost_op.cast(Node.BitNot).?.rhs = rhs;
|
||||||
|
rightmost_op = rhs;
|
||||||
|
} else break;
|
||||||
|
},
|
||||||
|
.BoolNot => {
|
||||||
|
if (try opParseFn(p)) |rhs| {
|
||||||
|
rightmost_op.cast(Node.BoolNot).?.rhs = rhs;
|
||||||
|
rightmost_op = rhs;
|
||||||
|
} else break;
|
||||||
|
},
|
||||||
|
.OptionalType => {
|
||||||
|
if (try opParseFn(p)) |rhs| {
|
||||||
|
rightmost_op.cast(Node.OptionalType).?.rhs = rhs;
|
||||||
|
rightmost_op = rhs;
|
||||||
|
} else break;
|
||||||
|
},
|
||||||
|
.Negation => {
|
||||||
|
if (try opParseFn(p)) |rhs| {
|
||||||
|
rightmost_op.cast(Node.Negation).?.rhs = rhs;
|
||||||
|
rightmost_op = rhs;
|
||||||
|
} else break;
|
||||||
|
},
|
||||||
|
.NegationWrap => {
|
||||||
|
if (try opParseFn(p)) |rhs| {
|
||||||
|
rightmost_op.cast(Node.NegationWrap).?.rhs = rhs;
|
||||||
|
rightmost_op = rhs;
|
||||||
|
} else break;
|
||||||
|
},
|
||||||
|
.Resume => {
|
||||||
|
if (try opParseFn(p)) |rhs| {
|
||||||
|
rightmost_op.cast(Node.Resume).?.rhs = rhs;
|
||||||
|
rightmost_op = rhs;
|
||||||
|
} else break;
|
||||||
|
},
|
||||||
|
.Try => {
|
||||||
|
if (try opParseFn(p)) |rhs| {
|
||||||
|
rightmost_op.cast(Node.Try).?.rhs = rhs;
|
||||||
|
rightmost_op = rhs;
|
||||||
|
} else break;
|
||||||
|
},
|
||||||
|
.ArrayType => {
|
||||||
|
if (try opParseFn(p)) |rhs| {
|
||||||
|
rightmost_op.cast(Node.ArrayType).?.rhs = rhs;
|
||||||
|
rightmost_op = rhs;
|
||||||
|
} else break;
|
||||||
|
},
|
||||||
|
.ArrayTypeSentinel => {
|
||||||
|
if (try opParseFn(p)) |rhs| {
|
||||||
|
rightmost_op.cast(Node.ArrayTypeSentinel).?.rhs = rhs;
|
||||||
|
rightmost_op = rhs;
|
||||||
|
} else break;
|
||||||
|
},
|
||||||
|
.SliceType => {
|
||||||
|
if (try opParseFn(p)) |rhs| {
|
||||||
|
rightmost_op.cast(Node.SliceType).?.rhs = rhs;
|
||||||
|
rightmost_op = rhs;
|
||||||
|
} else break;
|
||||||
|
},
|
||||||
|
.PtrType => {
|
||||||
|
var ptr_type = rightmost_op.cast(Node.PtrType).?;
|
||||||
// If the token encountered was **, there will be two nodes
|
// If the token encountered was **, there will be two nodes
|
||||||
if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk) {
|
if (p.token_ids[ptr_type.op_token] == .AsteriskAsterisk) {
|
||||||
rightmost_op = prefix_op.rhs;
|
rightmost_op = ptr_type.rhs;
|
||||||
prefix_op = rightmost_op.cast(Node.PrefixOp).?;
|
ptr_type = rightmost_op.cast(Node.PtrType).?;
|
||||||
}
|
}
|
||||||
if (try opParseFn(p)) |rhs| {
|
if (try opParseFn(p)) |rhs| {
|
||||||
prefix_op.rhs = rhs;
|
ptr_type.rhs = rhs;
|
||||||
rightmost_op = rhs;
|
rightmost_op = rhs;
|
||||||
} else break;
|
} else break;
|
||||||
},
|
},
|
||||||
@ -3253,8 +3319,80 @@ const Parser = struct {
|
|||||||
|
|
||||||
// If any prefix op existed, a child node on the RHS is required
|
// If any prefix op existed, a child node on the RHS is required
|
||||||
switch (rightmost_op.id) {
|
switch (rightmost_op.id) {
|
||||||
.PrefixOp => {
|
.AddressOf => {
|
||||||
const prefix_op = rightmost_op.cast(Node.PrefixOp).?;
|
const prefix_op = rightmost_op.cast(Node.AddressOf).?;
|
||||||
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.Await => {
|
||||||
|
const prefix_op = rightmost_op.cast(Node.Await).?;
|
||||||
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.BitNot => {
|
||||||
|
const prefix_op = rightmost_op.cast(Node.BitNot).?;
|
||||||
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.BoolNot => {
|
||||||
|
const prefix_op = rightmost_op.cast(Node.BoolNot).?;
|
||||||
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.OptionalType => {
|
||||||
|
const prefix_op = rightmost_op.cast(Node.OptionalType).?;
|
||||||
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.Negation => {
|
||||||
|
const prefix_op = rightmost_op.cast(Node.Negation).?;
|
||||||
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.NegationWrap => {
|
||||||
|
const prefix_op = rightmost_op.cast(Node.NegationWrap).?;
|
||||||
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.Resume => {
|
||||||
|
const prefix_op = rightmost_op.cast(Node.Resume).?;
|
||||||
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.Try => {
|
||||||
|
const prefix_op = rightmost_op.cast(Node.Try).?;
|
||||||
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.ArrayType => {
|
||||||
|
const prefix_op = rightmost_op.cast(Node.ArrayType).?;
|
||||||
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.ArrayTypeSentinel => {
|
||||||
|
const prefix_op = rightmost_op.cast(Node.ArrayTypeSentinel).?;
|
||||||
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.PtrType => {
|
||||||
|
const prefix_op = rightmost_op.cast(Node.PtrType).?;
|
||||||
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.SliceType => {
|
||||||
|
const prefix_op = rightmost_op.cast(Node.SliceType).?;
|
||||||
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
prefix_op.rhs = try p.expectNode(childParseFn, .{
|
||||||
.InvalidToken = .{ .token = p.tok_i },
|
.InvalidToken = .{ .token = p.tok_i },
|
||||||
});
|
});
|
||||||
|
|||||||
@ -468,166 +468,192 @@ fn renderExpression(
|
|||||||
return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);
|
return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);
|
||||||
},
|
},
|
||||||
|
|
||||||
.PrefixOp => {
|
.BitNot => {
|
||||||
const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
|
const bit_not = @fieldParentPtr(ast.Node.BitNot, "base", base);
|
||||||
|
try renderToken(tree, stream, bit_not.op_token, indent, start_col, Space.None);
|
||||||
|
return renderExpression(allocator, stream, tree, indent, start_col, bit_not.rhs, space);
|
||||||
|
},
|
||||||
|
.BoolNot => {
|
||||||
|
const bool_not = @fieldParentPtr(ast.Node.BoolNot, "base", base);
|
||||||
|
try renderToken(tree, stream, bool_not.op_token, indent, start_col, Space.None);
|
||||||
|
return renderExpression(allocator, stream, tree, indent, start_col, bool_not.rhs, space);
|
||||||
|
},
|
||||||
|
.Negation => {
|
||||||
|
const negation = @fieldParentPtr(ast.Node.Negation, "base", base);
|
||||||
|
try renderToken(tree, stream, negation.op_token, indent, start_col, Space.None);
|
||||||
|
return renderExpression(allocator, stream, tree, indent, start_col, negation.rhs, space);
|
||||||
|
},
|
||||||
|
.NegationWrap => {
|
||||||
|
const negation_wrap = @fieldParentPtr(ast.Node.NegationWrap, "base", base);
|
||||||
|
try renderToken(tree, stream, negation_wrap.op_token, indent, start_col, Space.None);
|
||||||
|
return renderExpression(allocator, stream, tree, indent, start_col, negation_wrap.rhs, space);
|
||||||
|
},
|
||||||
|
.OptionalType => {
|
||||||
|
const opt_type = @fieldParentPtr(ast.Node.OptionalType, "base", base);
|
||||||
|
try renderToken(tree, stream, opt_type.op_token, indent, start_col, Space.None);
|
||||||
|
return renderExpression(allocator, stream, tree, indent, start_col, opt_type.rhs, space);
|
||||||
|
},
|
||||||
|
.AddressOf => {
|
||||||
|
const addr_of = @fieldParentPtr(ast.Node.AddressOf, "base", base);
|
||||||
|
try renderToken(tree, stream, addr_of.op_token, indent, start_col, Space.None);
|
||||||
|
return renderExpression(allocator, stream, tree, indent, start_col, addr_of.rhs, space);
|
||||||
|
},
|
||||||
|
.Try => {
|
||||||
|
const try_node = @fieldParentPtr(ast.Node.Try, "base", base);
|
||||||
|
try renderToken(tree, stream, try_node.op_token, indent, start_col, Space.Space);
|
||||||
|
return renderExpression(allocator, stream, tree, indent, start_col, try_node.rhs, space);
|
||||||
|
},
|
||||||
|
.Resume => {
|
||||||
|
const resume_node = @fieldParentPtr(ast.Node.Resume, "base", base);
|
||||||
|
try renderToken(tree, stream, resume_node.op_token, indent, start_col, Space.Space);
|
||||||
|
return renderExpression(allocator, stream, tree, indent, start_col, resume_node.rhs, space);
|
||||||
|
},
|
||||||
|
.Await => {
|
||||||
|
const await_node = @fieldParentPtr(ast.Node.Await, "base", base);
|
||||||
|
try renderToken(tree, stream, await_node.op_token, indent, start_col, Space.Space);
|
||||||
|
return renderExpression(allocator, stream, tree, indent, start_col, await_node.rhs, space);
|
||||||
|
},
|
||||||
|
|
||||||
switch (prefix_op_node.op) {
|
.ArrayType => {
|
||||||
.PtrType => |ptr_info| {
|
const array_type = @fieldParentPtr(ast.Node.ArrayType, "base", base);
|
||||||
const op_tok_id = tree.token_ids[prefix_op_node.op_token];
|
return renderArrayType(
|
||||||
switch (op_tok_id) {
|
allocator,
|
||||||
.Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),
|
stream,
|
||||||
.LBracket => if (tree.token_ids[prefix_op_node.op_token + 2] == .Identifier)
|
tree,
|
||||||
try stream.writeAll("[*c")
|
indent,
|
||||||
else
|
start_col,
|
||||||
try stream.writeAll("[*"),
|
array_type.op_token,
|
||||||
else => unreachable,
|
array_type.rhs,
|
||||||
}
|
array_type.len_expr,
|
||||||
if (ptr_info.sentinel) |sentinel| {
|
null,
|
||||||
const colon_token = tree.prevToken(sentinel.firstToken());
|
space,
|
||||||
try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
|
);
|
||||||
const sentinel_space = switch (op_tok_id) {
|
},
|
||||||
.LBracket => Space.None,
|
.ArrayTypeSentinel => {
|
||||||
else => Space.Space,
|
const array_type = @fieldParentPtr(ast.Node.ArrayTypeSentinel, "base", base);
|
||||||
};
|
return renderArrayType(
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, sentinel, sentinel_space);
|
allocator,
|
||||||
}
|
stream,
|
||||||
switch (op_tok_id) {
|
tree,
|
||||||
.Asterisk, .AsteriskAsterisk => {},
|
indent,
|
||||||
.LBracket => try stream.writeByte(']'),
|
start_col,
|
||||||
else => unreachable,
|
array_type.op_token,
|
||||||
}
|
array_type.rhs,
|
||||||
if (ptr_info.allowzero_token) |allowzero_token| {
|
array_type.len_expr,
|
||||||
try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
|
array_type.sentinel,
|
||||||
}
|
space,
|
||||||
if (ptr_info.align_info) |align_info| {
|
);
|
||||||
const lparen_token = tree.prevToken(align_info.node.firstToken());
|
},
|
||||||
const align_token = tree.prevToken(lparen_token);
|
|
||||||
|
|
||||||
try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
|
.PtrType => {
|
||||||
try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
|
const ptr_type = @fieldParentPtr(ast.Node.PtrType, "base", base);
|
||||||
|
const op_tok_id = tree.token_ids[ptr_type.op_token];
|
||||||
|
switch (op_tok_id) {
|
||||||
|
.Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),
|
||||||
|
.LBracket => if (tree.token_ids[ptr_type.op_token + 2] == .Identifier)
|
||||||
|
try stream.writeAll("[*c")
|
||||||
|
else
|
||||||
|
try stream.writeAll("[*"),
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
if (ptr_type.ptr_info.sentinel) |sentinel| {
|
||||||
|
const colon_token = tree.prevToken(sentinel.firstToken());
|
||||||
|
try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
|
||||||
|
const sentinel_space = switch (op_tok_id) {
|
||||||
|
.LBracket => Space.None,
|
||||||
|
else => Space.Space,
|
||||||
|
};
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, sentinel, sentinel_space);
|
||||||
|
}
|
||||||
|
switch (op_tok_id) {
|
||||||
|
.Asterisk, .AsteriskAsterisk => {},
|
||||||
|
.LBracket => try stream.writeByte(']'),
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
if (ptr_type.ptr_info.allowzero_token) |allowzero_token| {
|
||||||
|
try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
|
||||||
|
}
|
||||||
|
if (ptr_type.ptr_info.align_info) |align_info| {
|
||||||
|
const lparen_token = tree.prevToken(align_info.node.firstToken());
|
||||||
|
const align_token = tree.prevToken(lparen_token);
|
||||||
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
|
try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
|
||||||
|
try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
|
||||||
|
|
||||||
if (align_info.bit_range) |bit_range| {
|
try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
|
||||||
const colon1 = tree.prevToken(bit_range.start.firstToken());
|
|
||||||
const colon2 = tree.prevToken(bit_range.end.firstToken());
|
|
||||||
|
|
||||||
try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
|
if (align_info.bit_range) |bit_range| {
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
|
const colon1 = tree.prevToken(bit_range.start.firstToken());
|
||||||
try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
|
const colon2 = tree.prevToken(bit_range.end.firstToken());
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
|
|
||||||
|
|
||||||
const rparen_token = tree.nextToken(bit_range.end.lastToken());
|
try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
|
||||||
try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
|
try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
|
||||||
} else {
|
try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
|
||||||
const rparen_token = tree.nextToken(align_info.node.lastToken());
|
try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
|
||||||
try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ptr_info.const_token) |const_token| {
|
|
||||||
try renderToken(tree, stream, const_token, indent, start_col, Space.Space); // const
|
|
||||||
}
|
|
||||||
if (ptr_info.volatile_token) |volatile_token| {
|
|
||||||
try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space); // volatile
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.SliceType => |ptr_info| {
|
const rparen_token = tree.nextToken(bit_range.end.lastToken());
|
||||||
try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); // [
|
try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
|
||||||
if (ptr_info.sentinel) |sentinel| {
|
} else {
|
||||||
const colon_token = tree.prevToken(sentinel.firstToken());
|
const rparen_token = tree.nextToken(align_info.node.lastToken());
|
||||||
try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
|
try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
|
}
|
||||||
try renderToken(tree, stream, tree.nextToken(sentinel.lastToken()), indent, start_col, Space.None); // ]
|
}
|
||||||
} else {
|
if (ptr_type.ptr_info.const_token) |const_token| {
|
||||||
try renderToken(tree, stream, tree.nextToken(prefix_op_node.op_token), indent, start_col, Space.None); // ]
|
try renderToken(tree, stream, const_token, indent, start_col, Space.Space); // const
|
||||||
}
|
}
|
||||||
|
if (ptr_type.ptr_info.volatile_token) |volatile_token| {
|
||||||
|
try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space); // volatile
|
||||||
|
}
|
||||||
|
return renderExpression(allocator, stream, tree, indent, start_col, ptr_type.rhs, space);
|
||||||
|
},
|
||||||
|
|
||||||
if (ptr_info.allowzero_token) |allowzero_token| {
|
.SliceType => {
|
||||||
try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
|
const slice_type = @fieldParentPtr(ast.Node.SliceType, "base", base);
|
||||||
}
|
try renderToken(tree, stream, slice_type.op_token, indent, start_col, Space.None); // [
|
||||||
if (ptr_info.align_info) |align_info| {
|
if (slice_type.ptr_info.sentinel) |sentinel| {
|
||||||
const lparen_token = tree.prevToken(align_info.node.firstToken());
|
const colon_token = tree.prevToken(sentinel.firstToken());
|
||||||
const align_token = tree.prevToken(lparen_token);
|
try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
|
||||||
try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
|
try renderToken(tree, stream, tree.nextToken(sentinel.lastToken()), indent, start_col, Space.None); // ]
|
||||||
try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
|
} else {
|
||||||
|
try renderToken(tree, stream, tree.nextToken(slice_type.op_token), indent, start_col, Space.None); // ]
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
|
|
||||||
|
|
||||||
if (align_info.bit_range) |bit_range| {
|
|
||||||
const colon1 = tree.prevToken(bit_range.start.firstToken());
|
|
||||||
const colon2 = tree.prevToken(bit_range.end.firstToken());
|
|
||||||
|
|
||||||
try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
|
|
||||||
try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
|
|
||||||
|
|
||||||
const rparen_token = tree.nextToken(bit_range.end.lastToken());
|
|
||||||
try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
|
|
||||||
} else {
|
|
||||||
const rparen_token = tree.nextToken(align_info.node.lastToken());
|
|
||||||
try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ptr_info.const_token) |const_token| {
|
|
||||||
try renderToken(tree, stream, const_token, indent, start_col, Space.Space);
|
|
||||||
}
|
|
||||||
if (ptr_info.volatile_token) |volatile_token| {
|
|
||||||
try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.ArrayType => |array_info| {
|
|
||||||
const lbracket = prefix_op_node.op_token;
|
|
||||||
const rbracket = tree.nextToken(if (array_info.sentinel) |sentinel|
|
|
||||||
sentinel.lastToken()
|
|
||||||
else
|
|
||||||
array_info.len_expr.lastToken());
|
|
||||||
|
|
||||||
try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
|
|
||||||
|
|
||||||
const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
|
|
||||||
const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
|
|
||||||
const new_indent = if (ends_with_comment) indent + indent_delta else indent;
|
|
||||||
const new_space = if (ends_with_comment) Space.Newline else Space.None;
|
|
||||||
try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space);
|
|
||||||
if (starts_with_comment) {
|
|
||||||
try stream.writeByte('\n');
|
|
||||||
}
|
|
||||||
if (ends_with_comment or starts_with_comment) {
|
|
||||||
try stream.writeByteNTimes(' ', indent);
|
|
||||||
}
|
|
||||||
if (array_info.sentinel) |sentinel| {
|
|
||||||
const colon_token = tree.prevToken(sentinel.firstToken());
|
|
||||||
try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
|
|
||||||
try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
|
|
||||||
}
|
|
||||||
try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ]
|
|
||||||
},
|
|
||||||
.BitNot,
|
|
||||||
.BoolNot,
|
|
||||||
.Negation,
|
|
||||||
.NegationWrap,
|
|
||||||
.OptionalType,
|
|
||||||
.AddressOf,
|
|
||||||
=> {
|
|
||||||
try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None);
|
|
||||||
},
|
|
||||||
|
|
||||||
.Try,
|
|
||||||
.Resume,
|
|
||||||
=> {
|
|
||||||
try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space);
|
|
||||||
},
|
|
||||||
|
|
||||||
.Await => |await_info| {
|
|
||||||
try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderExpression(allocator, stream, tree, indent, start_col, prefix_op_node.rhs, space);
|
if (slice_type.ptr_info.allowzero_token) |allowzero_token| {
|
||||||
|
try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
|
||||||
|
}
|
||||||
|
if (slice_type.ptr_info.align_info) |align_info| {
|
||||||
|
const lparen_token = tree.prevToken(align_info.node.firstToken());
|
||||||
|
const align_token = tree.prevToken(lparen_token);
|
||||||
|
|
||||||
|
try renderToken(tree, stream, align_token, indent, start_col, Space.None); // align
|
||||||
|
try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
|
||||||
|
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, align_info.node, Space.None);
|
||||||
|
|
||||||
|
if (align_info.bit_range) |bit_range| {
|
||||||
|
const colon1 = tree.prevToken(bit_range.start.firstToken());
|
||||||
|
const colon2 = tree.prevToken(bit_range.end.firstToken());
|
||||||
|
|
||||||
|
try renderToken(tree, stream, colon1, indent, start_col, Space.None); // :
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, bit_range.start, Space.None);
|
||||||
|
try renderToken(tree, stream, colon2, indent, start_col, Space.None); // :
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, bit_range.end, Space.None);
|
||||||
|
|
||||||
|
const rparen_token = tree.nextToken(bit_range.end.lastToken());
|
||||||
|
try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
|
||||||
|
} else {
|
||||||
|
const rparen_token = tree.nextToken(align_info.node.lastToken());
|
||||||
|
try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (slice_type.ptr_info.const_token) |const_token| {
|
||||||
|
try renderToken(tree, stream, const_token, indent, start_col, Space.Space);
|
||||||
|
}
|
||||||
|
if (slice_type.ptr_info.volatile_token) |volatile_token| {
|
||||||
|
try renderToken(tree, stream, volatile_token, indent, start_col, Space.Space);
|
||||||
|
}
|
||||||
|
return renderExpression(allocator, stream, tree, indent, start_col, slice_type.rhs, space);
|
||||||
},
|
},
|
||||||
|
|
||||||
.ArrayInitializer, .ArrayInitializerDot => {
|
.ArrayInitializer, .ArrayInitializerDot => {
|
||||||
@ -2057,6 +2083,46 @@ fn renderExpression(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn renderArrayType(
|
||||||
|
allocator: *mem.Allocator,
|
||||||
|
stream: anytype,
|
||||||
|
tree: *ast.Tree,
|
||||||
|
indent: usize,
|
||||||
|
start_col: *usize,
|
||||||
|
lbracket: ast.TokenIndex,
|
||||||
|
rhs: *ast.Node,
|
||||||
|
len_expr: *ast.Node,
|
||||||
|
opt_sentinel: ?*ast.Node,
|
||||||
|
space: Space,
|
||||||
|
) (@TypeOf(stream).Error || Error)!void {
|
||||||
|
const rbracket = tree.nextToken(if (opt_sentinel) |sentinel|
|
||||||
|
sentinel.lastToken()
|
||||||
|
else
|
||||||
|
len_expr.lastToken());
|
||||||
|
|
||||||
|
try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
|
||||||
|
|
||||||
|
const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
|
||||||
|
const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
|
||||||
|
const new_indent = if (ends_with_comment) indent + indent_delta else indent;
|
||||||
|
const new_space = if (ends_with_comment) Space.Newline else Space.None;
|
||||||
|
try renderExpression(allocator, stream, tree, new_indent, start_col, len_expr, new_space);
|
||||||
|
if (starts_with_comment) {
|
||||||
|
try stream.writeByte('\n');
|
||||||
|
}
|
||||||
|
if (ends_with_comment or starts_with_comment) {
|
||||||
|
try stream.writeByteNTimes(' ', indent);
|
||||||
|
}
|
||||||
|
if (opt_sentinel) |sentinel| {
|
||||||
|
const colon_token = tree.prevToken(sentinel.firstToken());
|
||||||
|
try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // :
|
||||||
|
try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
|
||||||
|
}
|
||||||
|
try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ]
|
||||||
|
|
||||||
|
return renderExpression(allocator, stream, tree, indent, start_col, rhs, space);
|
||||||
|
}
|
||||||
|
|
||||||
fn renderAsmOutput(
|
fn renderAsmOutput(
|
||||||
allocator: *mem.Allocator,
|
allocator: *mem.Allocator,
|
||||||
stream: anytype,
|
stream: anytype,
|
||||||
|
|||||||
@ -1308,10 +1308,18 @@ fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir
|
|||||||
.ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)),
|
.ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)),
|
||||||
.If => return self.astGenIf(scope, @fieldParentPtr(ast.Node.If, "base", ast_node)),
|
.If => return self.astGenIf(scope, @fieldParentPtr(ast.Node.If, "base", ast_node)),
|
||||||
.InfixOp => return self.astGenInfixOp(scope, @fieldParentPtr(ast.Node.InfixOp, "base", ast_node)),
|
.InfixOp => return self.astGenInfixOp(scope, @fieldParentPtr(ast.Node.InfixOp, "base", ast_node)),
|
||||||
|
.BoolNot => return self.astGenBoolNot(scope, @fieldParentPtr(ast.Node.BoolNot, "base", ast_node)),
|
||||||
else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}),
|
else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn astGenBoolNot(self: *Module, scope: *Scope, node: *ast.Node.BoolNot) InnerError!*zir.Inst {
|
||||||
|
const operand = try self.astGenExpr(scope, node.rhs);
|
||||||
|
const tree = scope.tree();
|
||||||
|
const src = tree.token_locs[node.op_token].start;
|
||||||
|
return self.addZIRInst(scope, src, zir.Inst.BoolNot, .{ .operand = operand }, .{});
|
||||||
|
}
|
||||||
|
|
||||||
fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) InnerError!*zir.Inst {
|
fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) InnerError!*zir.Inst {
|
||||||
switch (infix_node.op) {
|
switch (infix_node.op) {
|
||||||
.Assign => {
|
.Assign => {
|
||||||
|
|||||||
@ -1561,7 +1561,7 @@ fn transImplicitCastExpr(
|
|||||||
return maybeSuppressResult(rp, scope, result_used, sub_expr_node);
|
return maybeSuppressResult(rp, scope, result_used, sub_expr_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
const prefix_op = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
|
const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
|
||||||
prefix_op.rhs = try transExpr(rp, scope, sub_expr, .used, .r_value);
|
prefix_op.rhs = try transExpr(rp, scope, sub_expr, .used, .r_value);
|
||||||
|
|
||||||
return maybeSuppressResult(rp, scope, result_used, &prefix_op.base);
|
return maybeSuppressResult(rp, scope, result_used, &prefix_op.base);
|
||||||
@ -1673,11 +1673,7 @@ fn isBoolRes(res: *ast.Node) bool {
|
|||||||
|
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
.PrefixOp => switch (@fieldParentPtr(ast.Node.PrefixOp, "base", res).op) {
|
.BoolNot => return true,
|
||||||
.BoolNot => return true,
|
|
||||||
|
|
||||||
else => {},
|
|
||||||
},
|
|
||||||
.BoolLiteral => return true,
|
.BoolLiteral => return true,
|
||||||
.GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),
|
.GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),
|
||||||
else => {},
|
else => {},
|
||||||
@ -2162,21 +2158,16 @@ fn transCreateNodeArrayType(
|
|||||||
source_loc: ZigClangSourceLocation,
|
source_loc: ZigClangSourceLocation,
|
||||||
ty: *const ZigClangType,
|
ty: *const ZigClangType,
|
||||||
len: anytype,
|
len: anytype,
|
||||||
) TransError!*ast.Node {
|
) !*ast.Node {
|
||||||
var node = try transCreateNodePrefixOp(
|
const node = try rp.c.arena.create(ast.Node.ArrayType);
|
||||||
rp.c,
|
const op_token = try appendToken(rp.c, .LBracket, "[");
|
||||||
.{
|
const len_expr = try transCreateNodeInt(rp.c, len);
|
||||||
.ArrayType = .{
|
|
||||||
.len_expr = undefined,
|
|
||||||
.sentinel = null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.LBracket,
|
|
||||||
"[",
|
|
||||||
);
|
|
||||||
node.op.ArrayType.len_expr = try transCreateNodeInt(rp.c, len);
|
|
||||||
_ = try appendToken(rp.c, .RBracket, "]");
|
_ = try appendToken(rp.c, .RBracket, "]");
|
||||||
node.rhs = try transType(rp, ty, source_loc);
|
node.* = .{
|
||||||
|
.op_token = op_token,
|
||||||
|
.rhs = try transType(rp, ty, source_loc),
|
||||||
|
.len_expr = len_expr,
|
||||||
|
};
|
||||||
return &node.base;
|
return &node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2449,7 +2440,7 @@ fn transDoWhileLoop(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
defer cond_scope.deinit();
|
defer cond_scope.deinit();
|
||||||
const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
|
const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");
|
||||||
prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
|
prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
|
||||||
_ = try appendToken(rp.c, .RParen, ")");
|
_ = try appendToken(rp.c, .RParen, ")");
|
||||||
if_node.condition = &prefix_op.base;
|
if_node.condition = &prefix_op.base;
|
||||||
@ -3036,7 +3027,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
|
|||||||
else
|
else
|
||||||
return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
|
return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
|
||||||
.AddrOf => {
|
.AddrOf => {
|
||||||
const op_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
|
const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
|
||||||
op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
|
op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
|
||||||
return &op_node.base;
|
return &op_node.base;
|
||||||
},
|
},
|
||||||
@ -3052,7 +3043,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
|
|||||||
.Plus => return transExpr(rp, scope, op_expr, used, .r_value),
|
.Plus => return transExpr(rp, scope, op_expr, used, .r_value),
|
||||||
.Minus => {
|
.Minus => {
|
||||||
if (!qualTypeHasWrappingOverflow(ZigClangExpr_getType(op_expr))) {
|
if (!qualTypeHasWrappingOverflow(ZigClangExpr_getType(op_expr))) {
|
||||||
const op_node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-");
|
const op_node = try transCreateNodeSimplePrefixOp(rp.c, .Negation, .Minus, "-");
|
||||||
op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
|
op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
|
||||||
return &op_node.base;
|
return &op_node.base;
|
||||||
} else if (cIsUnsignedInteger(ZigClangExpr_getType(op_expr))) {
|
} else if (cIsUnsignedInteger(ZigClangExpr_getType(op_expr))) {
|
||||||
@ -3065,12 +3056,12 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
|
|||||||
return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "C negation with non float non integer", .{});
|
return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "C negation with non float non integer", .{});
|
||||||
},
|
},
|
||||||
.Not => {
|
.Not => {
|
||||||
const op_node = try transCreateNodePrefixOp(rp.c, .BitNot, .Tilde, "~");
|
const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BitNot, .Tilde, "~");
|
||||||
op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
|
op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
|
||||||
return &op_node.base;
|
return &op_node.base;
|
||||||
},
|
},
|
||||||
.LNot => {
|
.LNot => {
|
||||||
const op_node = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
|
const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");
|
||||||
op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
|
op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
|
||||||
return &op_node.base;
|
return &op_node.base;
|
||||||
},
|
},
|
||||||
@ -3116,7 +3107,7 @@ fn transCreatePreCrement(
|
|||||||
|
|
||||||
const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
|
const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
|
||||||
node.eq_token = try appendToken(rp.c, .Equal, "=");
|
node.eq_token = try appendToken(rp.c, .Equal, "=");
|
||||||
const rhs_node = try transCreateNodePrefixOp(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;
|
node.init_node = &rhs_node.base;
|
||||||
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
||||||
@ -3182,7 +3173,7 @@ fn transCreatePostCrement(
|
|||||||
|
|
||||||
const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
|
const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
|
||||||
node.eq_token = try appendToken(rp.c, .Equal, "=");
|
node.eq_token = try appendToken(rp.c, .Equal, "=");
|
||||||
const rhs_node = try transCreateNodePrefixOp(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;
|
node.init_node = &rhs_node.base;
|
||||||
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
||||||
@ -3336,7 +3327,7 @@ fn transCreateCompoundAssign(
|
|||||||
|
|
||||||
const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
|
const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
|
||||||
node.eq_token = try appendToken(rp.c, .Equal, "=");
|
node.eq_token = try appendToken(rp.c, .Equal, "=");
|
||||||
const addr_node = try transCreateNodePrefixOp(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;
|
node.init_node = &addr_node.base;
|
||||||
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
||||||
@ -3984,16 +3975,15 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c
|
|||||||
return &field_access_node.base;
|
return &field_access_node.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transCreateNodePrefixOp(
|
fn transCreateNodeSimplePrefixOp(
|
||||||
c: *Context,
|
c: *Context,
|
||||||
op: ast.Node.PrefixOp.Op,
|
comptime tag: ast.Node.Id,
|
||||||
op_tok_id: std.zig.Token.Id,
|
op_tok_id: std.zig.Token.Id,
|
||||||
bytes: []const u8,
|
bytes: []const u8,
|
||||||
) !*ast.Node.PrefixOp {
|
) !*ast.Node.SimplePrefixOp(tag) {
|
||||||
const node = try c.arena.create(ast.Node.PrefixOp);
|
const node = try c.arena.create(ast.Node.SimplePrefixOp(tag));
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.op_token = try appendToken(c, op_tok_id, bytes),
|
.op_token = try appendToken(c, op_tok_id, bytes),
|
||||||
.op = op,
|
|
||||||
.rhs = undefined, // translate and set afterward
|
.rhs = undefined, // translate and set afterward
|
||||||
};
|
};
|
||||||
return node;
|
return node;
|
||||||
@ -4065,8 +4055,8 @@ fn transCreateNodePtrType(
|
|||||||
is_const: bool,
|
is_const: bool,
|
||||||
is_volatile: bool,
|
is_volatile: bool,
|
||||||
op_tok_id: std.zig.Token.Id,
|
op_tok_id: std.zig.Token.Id,
|
||||||
) !*ast.Node.PrefixOp {
|
) !*ast.Node.PtrType {
|
||||||
const node = try c.arena.create(ast.Node.PrefixOp);
|
const node = try c.arena.create(ast.Node.PtrType);
|
||||||
const op_token = switch (op_tok_id) {
|
const op_token = switch (op_tok_id) {
|
||||||
.LBracket => blk: {
|
.LBracket => blk: {
|
||||||
const lbracket = try appendToken(c, .LBracket, "[");
|
const lbracket = try appendToken(c, .LBracket, "[");
|
||||||
@ -4086,11 +4076,9 @@ fn transCreateNodePtrType(
|
|||||||
};
|
};
|
||||||
node.* = .{
|
node.* = .{
|
||||||
.op_token = op_token,
|
.op_token = op_token,
|
||||||
.op = .{
|
.ptr_info = .{
|
||||||
.PtrType = .{
|
.const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,
|
||||||
.const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,
|
.volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,
|
||||||
.volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.rhs = undefined, // translate and set afterward
|
.rhs = undefined, // translate and set afterward
|
||||||
};
|
};
|
||||||
@ -4569,12 +4557,12 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
|
|||||||
.Pointer => {
|
.Pointer => {
|
||||||
const child_qt = ZigClangType_getPointeeType(ty);
|
const child_qt = ZigClangType_getPointeeType(ty);
|
||||||
if (qualTypeChildIsFnProto(child_qt)) {
|
if (qualTypeChildIsFnProto(child_qt)) {
|
||||||
const optional_node = try transCreateNodePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
|
const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
|
||||||
optional_node.rhs = try transQualType(rp, child_qt, source_loc);
|
optional_node.rhs = try transQualType(rp, child_qt, source_loc);
|
||||||
return &optional_node.base;
|
return &optional_node.base;
|
||||||
}
|
}
|
||||||
if (typeIsOpaque(rp.c, ZigClangQualType_getTypePtr(child_qt), source_loc)) {
|
if (typeIsOpaque(rp.c, ZigClangQualType_getTypePtr(child_qt), source_loc)) {
|
||||||
const optional_node = try transCreateNodePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
|
const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
|
||||||
const pointer_node = try transCreateNodePtrType(
|
const pointer_node = try transCreateNodePtrType(
|
||||||
rp.c,
|
rp.c,
|
||||||
ZigClangQualType_isConstQualified(child_qt),
|
ZigClangQualType_isConstQualified(child_qt),
|
||||||
@ -4599,21 +4587,8 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
|
|||||||
|
|
||||||
const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);
|
const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);
|
||||||
const size = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize));
|
const size = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize));
|
||||||
var node = try transCreateNodePrefixOp(
|
const elem_ty = ZigClangQualType_getTypePtr(ZigClangConstantArrayType_getElementType(const_arr_ty));
|
||||||
rp.c,
|
return try transCreateNodeArrayType(rp, source_loc, elem_ty, size);
|
||||||
.{
|
|
||||||
.ArrayType = .{
|
|
||||||
.len_expr = undefined,
|
|
||||||
.sentinel = null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.LBracket,
|
|
||||||
"[",
|
|
||||||
);
|
|
||||||
node.op.ArrayType.len_expr = try transCreateNodeInt(rp.c, size);
|
|
||||||
_ = try appendToken(rp.c, .RBracket, "]");
|
|
||||||
node.rhs = try transQualType(rp, ZigClangConstantArrayType_getElementType(const_arr_ty), source_loc);
|
|
||||||
return &node.base;
|
|
||||||
},
|
},
|
||||||
.IncompleteArray => {
|
.IncompleteArray => {
|
||||||
const incomplete_array_ty = @ptrCast(*const ZigClangIncompleteArrayType, ty);
|
const incomplete_array_ty = @ptrCast(*const ZigClangIncompleteArrayType, ty);
|
||||||
@ -5824,7 +5799,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
|||||||
if (prev_id == .Keyword_void) {
|
if (prev_id == .Keyword_void) {
|
||||||
const ptr = try transCreateNodePtrType(c, false, false, .Asterisk);
|
const ptr = try transCreateNodePtrType(c, false, false, .Asterisk);
|
||||||
ptr.rhs = node;
|
ptr.rhs = node;
|
||||||
const optional_node = try transCreateNodePrefixOp(c, .OptionalType, .QuestionMark, "?");
|
const optional_node = try transCreateNodeSimplePrefixOp(c, .OptionalType, .QuestionMark, "?");
|
||||||
optional_node.rhs = &ptr.base;
|
optional_node.rhs = &ptr.base;
|
||||||
return &optional_node.base;
|
return &optional_node.base;
|
||||||
} else {
|
} else {
|
||||||
@ -5993,18 +5968,18 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
|||||||
|
|
||||||
switch (op_tok.id) {
|
switch (op_tok.id) {
|
||||||
.Bang => {
|
.Bang => {
|
||||||
const node = try transCreateNodePrefixOp(c, .BoolNot, .Bang, "!");
|
const node = try transCreateNodeSimplePrefixOp(c, .BoolNot, .Bang, "!");
|
||||||
node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
|
node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
|
||||||
return &node.base;
|
return &node.base;
|
||||||
},
|
},
|
||||||
.Minus => {
|
.Minus => {
|
||||||
const node = try transCreateNodePrefixOp(c, .Negation, .Minus, "-");
|
const node = try transCreateNodeSimplePrefixOp(c, .Negation, .Minus, "-");
|
||||||
node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
|
node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
|
||||||
return &node.base;
|
return &node.base;
|
||||||
},
|
},
|
||||||
.Plus => return try parseCPrefixOpExpr(c, it, source, source_loc, scope),
|
.Plus => return try parseCPrefixOpExpr(c, it, source, source_loc, scope),
|
||||||
.Tilde => {
|
.Tilde => {
|
||||||
const node = try transCreateNodePrefixOp(c, .BitNot, .Tilde, "~");
|
const node = try transCreateNodeSimplePrefixOp(c, .BitNot, .Tilde, "~");
|
||||||
node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
|
node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
|
||||||
return &node.base;
|
return &node.base;
|
||||||
},
|
},
|
||||||
@ -6013,7 +5988,7 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
|||||||
return try transCreateNodePtrDeref(c, node);
|
return try transCreateNodePtrDeref(c, node);
|
||||||
},
|
},
|
||||||
.Ampersand => {
|
.Ampersand => {
|
||||||
const node = try transCreateNodePrefixOp(c, .AddressOf, .Ampersand, "&");
|
const node = try transCreateNodeSimplePrefixOp(c, .AddressOf, .Ampersand, "&");
|
||||||
node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
|
node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
|
||||||
return &node.base;
|
return &node.base;
|
||||||
},
|
},
|
||||||
@ -6034,29 +6009,49 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
|
fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
|
||||||
if (node.id == .ContainerDecl) {
|
switch (node.id) {
|
||||||
return node;
|
.ContainerDecl,
|
||||||
} else if (node.id == .PrefixOp) {
|
.AddressOf,
|
||||||
return node;
|
.Await,
|
||||||
} else if (node.cast(ast.Node.Identifier)) |ident| {
|
.BitNot,
|
||||||
if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
|
.BoolNot,
|
||||||
if (value.cast(ast.Node.VarDecl)) |var_decl|
|
.OptionalType,
|
||||||
return getContainer(c, var_decl.init_node.?);
|
.Negation,
|
||||||
}
|
.NegationWrap,
|
||||||
} else if (node.cast(ast.Node.InfixOp)) |infix| {
|
.Resume,
|
||||||
if (infix.op != .Period)
|
.Try,
|
||||||
return null;
|
.ArrayType,
|
||||||
if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
|
.ArrayTypeSentinel,
|
||||||
if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
|
.PtrType,
|
||||||
for (container.fieldsAndDecls()) |field_ref| {
|
.SliceType,
|
||||||
const field = field_ref.cast(ast.Node.ContainerField).?;
|
=> return node,
|
||||||
const ident = infix.rhs.cast(ast.Node.Identifier).?;
|
|
||||||
if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
|
.Identifier => {
|
||||||
return getContainer(c, field.type_expr.?);
|
const ident = node.cast(ast.Node.Identifier).?;
|
||||||
|
if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
|
||||||
|
if (value.cast(ast.Node.VarDecl)) |var_decl|
|
||||||
|
return getContainer(c, var_decl.init_node.?);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
.InfixOp => {
|
||||||
|
const infix = node.cast(ast.Node.InfixOp).?;
|
||||||
|
if (infix.op != .Period)
|
||||||
|
return null;
|
||||||
|
if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
|
||||||
|
if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
|
||||||
|
for (container.fieldsAndDecls()) |field_ref| {
|
||||||
|
const field = field_ref.cast(ast.Node.ContainerField).?;
|
||||||
|
const ident = infix.rhs.cast(ast.Node.Identifier).?;
|
||||||
|
if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
|
||||||
|
return getContainer(c, field.type_expr.?);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
else => {},
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -6091,11 +6086,9 @@ 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.init_node.? else return null;
|
||||||
if (getContainerTypeOf(c, init)) |ty_node| {
|
if (getContainerTypeOf(c, init)) |ty_node| {
|
||||||
if (ty_node.cast(ast.Node.PrefixOp)) |prefix| {
|
if (ty_node.cast(ast.Node.OptionalType)) |prefix| {
|
||||||
if (prefix.op == .OptionalType) {
|
if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
|
||||||
if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
|
return fn_proto;
|
||||||
return fn_proto;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user