mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
stage2: AST: (breaking) flatten out suffix operations
This commit is contained in:
parent
1ac28eed83
commit
7a1a924788
@ -471,9 +471,14 @@ pub const Node = struct {
|
||||
ArrayTypeSentinel,
|
||||
PtrType,
|
||||
SliceType,
|
||||
/// Not all suffix operations are under this tag. To save memory, some
|
||||
/// suffix operations have dedicated Node tags.
|
||||
SuffixOp,
|
||||
/// `a[b..c]`
|
||||
Slice,
|
||||
/// `a.*`
|
||||
Deref,
|
||||
/// `a.?`
|
||||
UnwrapOptional,
|
||||
/// `a[b]`
|
||||
ArrayAccess,
|
||||
/// `T{a, b}`
|
||||
ArrayInitializer,
|
||||
/// ArrayInitializer but with `.` instead of a left-hand-side operand.
|
||||
@ -601,7 +606,9 @@ pub const Node = struct {
|
||||
|
||||
.PtrType => PtrType,
|
||||
.SliceType => SliceType,
|
||||
.SuffixOp => SuffixOp,
|
||||
.Slice => Slice,
|
||||
.Deref, .UnwrapOptional => SimpleSuffixOp,
|
||||
.ArrayAccess => ArrayAccess,
|
||||
|
||||
.ArrayInitializer => ArrayInitializer,
|
||||
.ArrayInitializerDot => ArrayInitializerDot,
|
||||
@ -2398,8 +2405,8 @@ pub const Node = struct {
|
||||
/// Parameter nodes directly follow Call in memory.
|
||||
pub const Call = struct {
|
||||
base: Node = Node{ .tag = .Call },
|
||||
lhs: *Node,
|
||||
rtoken: TokenIndex,
|
||||
lhs: *Node,
|
||||
params_len: NodeIndex,
|
||||
async_token: ?TokenIndex,
|
||||
|
||||
@ -2450,62 +2457,90 @@ pub const Node = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const SuffixOp = struct {
|
||||
base: Node = Node{ .tag = .SuffixOp },
|
||||
op: Op,
|
||||
lhs: *Node,
|
||||
pub const ArrayAccess = struct {
|
||||
base: Node = Node{ .tag = .ArrayAccess },
|
||||
rtoken: TokenIndex,
|
||||
lhs: *Node,
|
||||
index_expr: *Node,
|
||||
|
||||
pub const Op = union(enum) {
|
||||
ArrayAccess: *Node,
|
||||
Slice: Slice,
|
||||
Deref,
|
||||
UnwrapOptional,
|
||||
|
||||
pub const Slice = struct {
|
||||
start: *Node,
|
||||
end: ?*Node,
|
||||
sentinel: ?*Node,
|
||||
};
|
||||
};
|
||||
|
||||
pub fn iterate(self: *const SuffixOp, index: usize) ?*Node {
|
||||
pub fn iterate(self: *const ArrayAccess, index: usize) ?*Node {
|
||||
var i = index;
|
||||
|
||||
if (i == 0) return self.lhs;
|
||||
if (i < 1) return self.lhs;
|
||||
i -= 1;
|
||||
|
||||
switch (self.op) {
|
||||
.ArrayAccess => |index_expr| {
|
||||
if (i < 1) return index_expr;
|
||||
i -= 1;
|
||||
},
|
||||
.Slice => |range| {
|
||||
if (i < 1) return range.start;
|
||||
i -= 1;
|
||||
if (i < 1) return self.index_expr;
|
||||
i -= 1;
|
||||
|
||||
if (range.end) |end| {
|
||||
if (i < 1) return end;
|
||||
i -= 1;
|
||||
}
|
||||
if (range.sentinel) |sentinel| {
|
||||
if (i < 1) return sentinel;
|
||||
i -= 1;
|
||||
}
|
||||
},
|
||||
.UnwrapOptional,
|
||||
.Deref,
|
||||
=> {},
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn firstToken(self: *const ArrayAccess) TokenIndex {
|
||||
return self.lhs.firstToken();
|
||||
}
|
||||
|
||||
pub fn lastToken(self: *const ArrayAccess) TokenIndex {
|
||||
return self.rtoken;
|
||||
}
|
||||
};
|
||||
|
||||
pub const SimpleSuffixOp = struct {
|
||||
base: Node,
|
||||
rtoken: TokenIndex,
|
||||
lhs: *Node,
|
||||
|
||||
pub fn iterate(self: *const SimpleSuffixOp, index: usize) ?*Node {
|
||||
var i = index;
|
||||
|
||||
if (i < 1) return self.lhs;
|
||||
i -= 1;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn firstToken(self: *const SimpleSuffixOp) TokenIndex {
|
||||
return self.lhs.firstToken();
|
||||
}
|
||||
|
||||
pub fn lastToken(self: *const SimpleSuffixOp) TokenIndex {
|
||||
return self.rtoken;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Slice = struct {
|
||||
base: Node = Node{ .tag = .Slice },
|
||||
rtoken: TokenIndex,
|
||||
lhs: *Node,
|
||||
start: *Node,
|
||||
end: ?*Node,
|
||||
sentinel: ?*Node,
|
||||
|
||||
pub fn iterate(self: *const Slice, index: usize) ?*Node {
|
||||
var i = index;
|
||||
|
||||
if (i < 1) return self.lhs;
|
||||
i -= 1;
|
||||
|
||||
if (i < 1) return self.start;
|
||||
i -= 1;
|
||||
|
||||
if (self.end) |end| {
|
||||
if (i < 1) return end;
|
||||
i -= 1;
|
||||
}
|
||||
if (self.sentinel) |sentinel| {
|
||||
if (i < 1) return sentinel;
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn firstToken(self: *const SuffixOp) TokenIndex {
|
||||
pub fn firstToken(self: *const Slice) TokenIndex {
|
||||
return self.lhs.firstToken();
|
||||
}
|
||||
|
||||
pub fn lastToken(self: *const SuffixOp) TokenIndex {
|
||||
pub fn lastToken(self: *const Slice) TokenIndex {
|
||||
return self.rtoken;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1439,58 +1439,7 @@ const Parser = struct {
|
||||
.ExpectedPrimaryTypeExpr = .{ .token = p.tok_i },
|
||||
});
|
||||
|
||||
// TODO pass `res` into `parseSuffixOp` rather than patching it up afterwards.
|
||||
while (try p.parseSuffixOp()) |node| {
|
||||
switch (node.tag) {
|
||||
.SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,
|
||||
.Catch => node.castTag(.Catch).?.lhs = res,
|
||||
|
||||
.Add,
|
||||
.AddWrap,
|
||||
.ArrayCat,
|
||||
.ArrayMult,
|
||||
.Assign,
|
||||
.AssignBitAnd,
|
||||
.AssignBitOr,
|
||||
.AssignBitShiftLeft,
|
||||
.AssignBitShiftRight,
|
||||
.AssignBitXor,
|
||||
.AssignDiv,
|
||||
.AssignSub,
|
||||
.AssignSubWrap,
|
||||
.AssignMod,
|
||||
.AssignAdd,
|
||||
.AssignAddWrap,
|
||||
.AssignMul,
|
||||
.AssignMulWrap,
|
||||
.BangEqual,
|
||||
.BitAnd,
|
||||
.BitOr,
|
||||
.BitShiftLeft,
|
||||
.BitShiftRight,
|
||||
.BitXor,
|
||||
.BoolAnd,
|
||||
.BoolOr,
|
||||
.Div,
|
||||
.EqualEqual,
|
||||
.ErrorUnion,
|
||||
.GreaterOrEqual,
|
||||
.GreaterThan,
|
||||
.LessOrEqual,
|
||||
.LessThan,
|
||||
.MergeErrorSets,
|
||||
.Mod,
|
||||
.Mul,
|
||||
.MulWrap,
|
||||
.Period,
|
||||
.Range,
|
||||
.Sub,
|
||||
.SubWrap,
|
||||
.OrElse,
|
||||
=> node.cast(Node.SimpleInfixOp).?.lhs = res,
|
||||
|
||||
else => unreachable,
|
||||
}
|
||||
while (try p.parseSuffixOp(res)) |node| {
|
||||
res = node;
|
||||
}
|
||||
|
||||
@ -1516,57 +1465,7 @@ const Parser = struct {
|
||||
var res = expr;
|
||||
|
||||
while (true) {
|
||||
// TODO pass `res` into `parseSuffixOp` rather than patching it up afterwards.
|
||||
if (try p.parseSuffixOp()) |node| {
|
||||
switch (node.tag) {
|
||||
.SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,
|
||||
.Catch => node.castTag(.Catch).?.lhs = res,
|
||||
|
||||
.Add,
|
||||
.AddWrap,
|
||||
.ArrayCat,
|
||||
.ArrayMult,
|
||||
.Assign,
|
||||
.AssignBitAnd,
|
||||
.AssignBitOr,
|
||||
.AssignBitShiftLeft,
|
||||
.AssignBitShiftRight,
|
||||
.AssignBitXor,
|
||||
.AssignDiv,
|
||||
.AssignSub,
|
||||
.AssignSubWrap,
|
||||
.AssignMod,
|
||||
.AssignAdd,
|
||||
.AssignAddWrap,
|
||||
.AssignMul,
|
||||
.AssignMulWrap,
|
||||
.BangEqual,
|
||||
.BitAnd,
|
||||
.BitOr,
|
||||
.BitShiftLeft,
|
||||
.BitShiftRight,
|
||||
.BitXor,
|
||||
.BoolAnd,
|
||||
.BoolOr,
|
||||
.Div,
|
||||
.EqualEqual,
|
||||
.ErrorUnion,
|
||||
.GreaterOrEqual,
|
||||
.GreaterThan,
|
||||
.LessOrEqual,
|
||||
.LessThan,
|
||||
.MergeErrorSets,
|
||||
.Mod,
|
||||
.Mul,
|
||||
.MulWrap,
|
||||
.Period,
|
||||
.Range,
|
||||
.Sub,
|
||||
.SubWrap,
|
||||
.OrElse,
|
||||
=> node.cast(Node.SimpleInfixOp).?.lhs = res,
|
||||
else => unreachable,
|
||||
}
|
||||
if (try p.parseSuffixOp(res)) |node| {
|
||||
res = node;
|
||||
continue;
|
||||
}
|
||||
@ -2733,78 +2632,77 @@ const Parser = struct {
|
||||
/// / DOT IDENTIFIER
|
||||
/// / DOTASTERISK
|
||||
/// / DOTQUESTIONMARK
|
||||
fn parseSuffixOp(p: *Parser) !?*Node {
|
||||
const OpAndToken = struct {
|
||||
op: Node.SuffixOp.Op,
|
||||
token: TokenIndex,
|
||||
};
|
||||
const op_and_token: OpAndToken = blk: {
|
||||
if (p.eatToken(.LBracket)) |_| {
|
||||
const index_expr = try p.expectNode(parseExpr, .{
|
||||
.ExpectedExpr = .{ .token = p.tok_i },
|
||||
});
|
||||
fn parseSuffixOp(p: *Parser, lhs: *Node) !?*Node {
|
||||
if (p.eatToken(.LBracket)) |_| {
|
||||
const index_expr = try p.expectNode(parseExpr, .{
|
||||
.ExpectedExpr = .{ .token = p.tok_i },
|
||||
});
|
||||
|
||||
if (p.eatToken(.Ellipsis2) != null) {
|
||||
const end_expr = try p.parseExpr();
|
||||
const sentinel: ?*Node = if (p.eatToken(.Colon) != null)
|
||||
try p.parseExpr()
|
||||
else
|
||||
null;
|
||||
break :blk .{
|
||||
.op = .{
|
||||
.Slice = .{
|
||||
.start = index_expr,
|
||||
.end = end_expr,
|
||||
.sentinel = sentinel,
|
||||
},
|
||||
},
|
||||
.token = try p.expectToken(.RBracket),
|
||||
};
|
||||
}
|
||||
|
||||
break :blk .{
|
||||
.op = .{ .ArrayAccess = index_expr },
|
||||
.token = try p.expectToken(.RBracket),
|
||||
if (p.eatToken(.Ellipsis2) != null) {
|
||||
const end_expr = try p.parseExpr();
|
||||
const sentinel: ?*Node = if (p.eatToken(.Colon) != null)
|
||||
try p.parseExpr()
|
||||
else
|
||||
null;
|
||||
const rtoken = try p.expectToken(.RBracket);
|
||||
const node = try p.arena.allocator.create(Node.Slice);
|
||||
node.* = .{
|
||||
.lhs = lhs,
|
||||
.rtoken = rtoken,
|
||||
.start = index_expr,
|
||||
.end = end_expr,
|
||||
.sentinel = sentinel,
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
if (p.eatToken(.PeriodAsterisk)) |period_asterisk| {
|
||||
break :blk .{ .op = .Deref, .token = period_asterisk };
|
||||
}
|
||||
const rtoken = try p.expectToken(.RBracket);
|
||||
const node = try p.arena.allocator.create(Node.ArrayAccess);
|
||||
node.* = .{
|
||||
.lhs = lhs,
|
||||
.rtoken = rtoken,
|
||||
.index_expr = index_expr,
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
if (p.eatToken(.Period)) |period| {
|
||||
if (try p.parseIdentifier()) |identifier| {
|
||||
// TODO: It's a bit weird to return a SimpleInfixOp from the SuffixOp parser.
|
||||
// Should there be an Node.SuffixOp.FieldAccess variant? Or should
|
||||
// this grammar rule be altered?
|
||||
const node = try p.arena.allocator.create(Node.SimpleInfixOp);
|
||||
node.* = .{
|
||||
.base = Node{ .tag = .Period },
|
||||
.op_token = period,
|
||||
.lhs = undefined, // set by caller
|
||||
.rhs = identifier,
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (p.eatToken(.QuestionMark)) |question_mark| {
|
||||
break :blk .{ .op = .UnwrapOptional, .token = question_mark };
|
||||
}
|
||||
try p.errors.append(p.gpa, .{
|
||||
.ExpectedSuffixOp = .{ .token = p.tok_i },
|
||||
});
|
||||
return null;
|
||||
}
|
||||
if (p.eatToken(.PeriodAsterisk)) |period_asterisk| {
|
||||
const node = try p.arena.allocator.create(Node.SimpleSuffixOp);
|
||||
node.* = .{
|
||||
.base = .{ .tag = .Deref },
|
||||
.lhs = lhs,
|
||||
.rtoken = period_asterisk,
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
if (p.eatToken(.Period)) |period| {
|
||||
if (try p.parseIdentifier()) |identifier| {
|
||||
const node = try p.arena.allocator.create(Node.SimpleInfixOp);
|
||||
node.* = .{
|
||||
.base = Node{ .tag = .Period },
|
||||
.op_token = period,
|
||||
.lhs = lhs,
|
||||
.rhs = identifier,
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (p.eatToken(.QuestionMark)) |question_mark| {
|
||||
const node = try p.arena.allocator.create(Node.SimpleSuffixOp);
|
||||
node.* = .{
|
||||
.base = .{ .tag = .UnwrapOptional },
|
||||
.lhs = lhs,
|
||||
.rtoken = question_mark,
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
try p.errors.append(p.gpa, .{
|
||||
.ExpectedSuffixOp = .{ .token = p.tok_i },
|
||||
});
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
const node = try p.arena.allocator.create(Node.SuffixOp);
|
||||
node.* = .{
|
||||
.lhs = undefined, // set by caller
|
||||
.op = op_and_token.op,
|
||||
.rtoken = op_and_token.token,
|
||||
};
|
||||
return &node.base;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// FnCallArguments <- LPAREN ExprList RPAREN
|
||||
|
||||
@ -1044,68 +1044,67 @@ fn renderExpression(
|
||||
return renderToken(tree, stream, call.rtoken, indent, start_col, space);
|
||||
},
|
||||
|
||||
.SuffixOp => {
|
||||
const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
|
||||
.ArrayAccess => {
|
||||
const suffix_op = base.castTag(.ArrayAccess).?;
|
||||
|
||||
switch (suffix_op.op) {
|
||||
.ArrayAccess => |index_expr| {
|
||||
const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
|
||||
const rbracket = tree.nextToken(index_expr.lastToken());
|
||||
const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
|
||||
const rbracket = tree.nextToken(suffix_op.index_expr.lastToken());
|
||||
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
||||
try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
||||
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, index_expr, new_space);
|
||||
if (starts_with_comment) {
|
||||
try stream.writeByte('\n');
|
||||
}
|
||||
if (ends_with_comment or starts_with_comment) {
|
||||
try stream.writeByteNTimes(' ', indent);
|
||||
}
|
||||
return renderToken(tree, stream, rbracket, indent, start_col, space); // ]
|
||||
},
|
||||
|
||||
.Deref => {
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
||||
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .*
|
||||
},
|
||||
|
||||
.UnwrapOptional => {
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
||||
try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .
|
||||
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?
|
||||
},
|
||||
|
||||
.Slice => |range| {
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
||||
|
||||
const lbracket = tree.prevToken(range.start.firstToken());
|
||||
const dotdot = tree.nextToken(range.start.lastToken());
|
||||
|
||||
const after_start_space_bool = nodeCausesSliceOpSpace(range.start) or
|
||||
(if (range.end) |end| nodeCausesSliceOpSpace(end) else false);
|
||||
const after_start_space = if (after_start_space_bool) Space.Space else Space.None;
|
||||
const after_op_space = if (range.end != null) after_start_space else Space.None;
|
||||
|
||||
try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, range.start, after_start_space);
|
||||
try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..
|
||||
if (range.end) |end| {
|
||||
const after_end_space = if (range.sentinel != null) Space.Space else Space.None;
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, end, after_end_space);
|
||||
}
|
||||
if (range.sentinel) |sentinel| {
|
||||
const colon = tree.prevToken(sentinel.firstToken());
|
||||
try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
|
||||
}
|
||||
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]
|
||||
},
|
||||
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, suffix_op.index_expr, new_space);
|
||||
if (starts_with_comment) {
|
||||
try stream.writeByte('\n');
|
||||
}
|
||||
if (ends_with_comment or starts_with_comment) {
|
||||
try stream.writeByteNTimes(' ', indent);
|
||||
}
|
||||
return renderToken(tree, stream, rbracket, indent, start_col, space); // ]
|
||||
},
|
||||
.Slice => {
|
||||
const suffix_op = base.castTag(.Slice).?;
|
||||
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
||||
|
||||
const lbracket = tree.prevToken(suffix_op.start.firstToken());
|
||||
const dotdot = tree.nextToken(suffix_op.start.lastToken());
|
||||
|
||||
const after_start_space_bool = nodeCausesSliceOpSpace(suffix_op.start) or
|
||||
(if (suffix_op.end) |end| nodeCausesSliceOpSpace(end) else false);
|
||||
const after_start_space = if (after_start_space_bool) Space.Space else Space.None;
|
||||
const after_op_space = if (suffix_op.end != null) after_start_space else Space.None;
|
||||
|
||||
try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.start, after_start_space);
|
||||
try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..
|
||||
if (suffix_op.end) |end| {
|
||||
const after_end_space = if (suffix_op.sentinel != null) Space.Space else Space.None;
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, end, after_end_space);
|
||||
}
|
||||
if (suffix_op.sentinel) |sentinel| {
|
||||
const colon = tree.prevToken(sentinel.firstToken());
|
||||
try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
|
||||
}
|
||||
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]
|
||||
},
|
||||
.Deref => {
|
||||
const suffix_op = base.castTag(.Deref).?;
|
||||
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
||||
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .*
|
||||
},
|
||||
.UnwrapOptional => {
|
||||
const suffix_op = base.castTag(.UnwrapOptional).?;
|
||||
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
||||
try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .
|
||||
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?
|
||||
},
|
||||
|
||||
.ControlFlowExpression => {
|
||||
|
||||
@ -34,7 +34,7 @@ pub fn expr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst {
|
||||
.LessThan => return cmp(mod, scope, node.castTag(.LessThan).?, .lt),
|
||||
.LessOrEqual => return cmp(mod, scope, node.castTag(.LessOrEqual).?, .lte),
|
||||
.Period => return field(mod, scope, node.castTag(.Period).?),
|
||||
.SuffixOp => return suffixOp(mod, scope, node.castTag(.SuffixOp).?),
|
||||
.Deref => return deref(mod, scope, node.castTag(.Deref).?),
|
||||
.BoolNot => return boolNot(mod, scope, node.castTag(.BoolNot).?),
|
||||
else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),
|
||||
}
|
||||
@ -73,32 +73,41 @@ fn varDecl(mod: *Module, scope: *Scope, node: *ast.Node.VarDecl) InnerError!Scop
|
||||
if (node.getTrailer("align_node")) |align_node| {
|
||||
return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{});
|
||||
}
|
||||
if (node.getTrailer("type_node")) |type_node| {
|
||||
return mod.failNode(scope, type_node, "TODO implement typed locals", .{});
|
||||
}
|
||||
const tree = scope.tree();
|
||||
switch (tree.token_ids[node.mut_token]) {
|
||||
.Keyword_const => {},
|
||||
.Keyword_const => {
|
||||
if (node.getTrailer("type_node")) |type_node| {
|
||||
return mod.failNode(scope, type_node, "TODO implement typed const locals", .{});
|
||||
}
|
||||
// Depending on the type of AST the initialization expression is, we may need an lvalue
|
||||
// or an rvalue as a result location. If it is an rvalue, we can use the instruction as
|
||||
// the variable, no memory location needed.
|
||||
const init_node = node.getTrailer("init_node").?;
|
||||
if (nodeMayNeedMemoryLocation(init_node)) {
|
||||
return mod.failNode(scope, init_node, "TODO implement result locations", .{});
|
||||
}
|
||||
const init_inst = try expr(mod, scope, init_node);
|
||||
const ident_name = try identifierTokenString(mod, scope, node.name_token);
|
||||
return Scope.LocalVar{
|
||||
.parent = scope,
|
||||
.gen_zir = scope.getGenZIR(),
|
||||
.name = ident_name,
|
||||
.inst = init_inst,
|
||||
};
|
||||
},
|
||||
.Keyword_var => {
|
||||
return mod.failTok(scope, node.mut_token, "TODO implement mutable locals", .{});
|
||||
return mod.failNode(scope, &node.base, "TODO implement local vars", .{});
|
||||
//const src = tree.token_locs[node.name_token].start;
|
||||
//const alloc = mod.addZIRInst(scope, src, zir.Inst.Alloc, .{}, .{});
|
||||
//if (node.getTrailer("type_node")) |type_node| {
|
||||
// const type_inst = try expr(mod, scope, type_node);
|
||||
// return mod.failNode(scope, type_node, "TODO implement typed var locals", .{});
|
||||
//} else {
|
||||
// return mod.failTok(scope, node.mut_token, "TODO implement mutable type-inferred locals", .{});
|
||||
//}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
// Depending on the type of AST the initialization expression is, we may need an lvalue
|
||||
// or an rvalue as a result location. If it is an rvalue, we can use the instruction as
|
||||
// the variable, no memory location needed.
|
||||
const init_node = node.getTrailer("init_node").?;
|
||||
if (nodeMayNeedMemoryLocation(init_node)) {
|
||||
return mod.failNode(scope, init_node, "TODO implement result locations", .{});
|
||||
}
|
||||
const init_inst = try expr(mod, scope, init_node);
|
||||
const ident_name = try identifierTokenString(mod, scope, node.name_token);
|
||||
return Scope.LocalVar{
|
||||
.parent = scope,
|
||||
.gen_zir = scope.getGenZIR(),
|
||||
.name = ident_name,
|
||||
.inst = init_inst,
|
||||
};
|
||||
}
|
||||
|
||||
fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
|
||||
@ -163,18 +172,13 @@ fn field(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp) InnerError!
|
||||
return mod.addZIRInst(scope, src, zir.Inst.Deref, .{ .ptr = pointer }, .{});
|
||||
}
|
||||
|
||||
fn suffixOp(mod: *Module, scope: *Scope, node: *ast.Node.SuffixOp) InnerError!*zir.Inst {
|
||||
switch (node.op) {
|
||||
.Deref => {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.rtoken].start;
|
||||
fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.rtoken].start;
|
||||
|
||||
const lhs = try expr(mod, scope, node.lhs);
|
||||
const lhs = try expr(mod, scope, node.lhs);
|
||||
|
||||
return mod.addZIRInst(scope, src, zir.Inst.Deref, .{ .ptr = lhs }, .{});
|
||||
},
|
||||
else => return mod.failNode(scope, &node.base, "TODO implement astGenExpr for suffixOp {}", .{node.op}),
|
||||
}
|
||||
return mod.addZIRInst(scope, src, zir.Inst.Deref, .{ .ptr = lhs }, .{});
|
||||
}
|
||||
|
||||
fn add(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
|
||||
@ -672,6 +676,9 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
|
||||
.Period,
|
||||
.Sub,
|
||||
.SubWrap,
|
||||
.Slice,
|
||||
.Deref,
|
||||
.ArrayAccess,
|
||||
=> return false,
|
||||
|
||||
// Forward the question to a sub-expression.
|
||||
@ -682,6 +689,7 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
|
||||
.OrElse => node = node.castTag(.OrElse).?.rhs,
|
||||
.Comptime => node = node.castTag(.Comptime).?.expr,
|
||||
.Nosuspend => node = node.castTag(.Nosuspend).?.expr,
|
||||
.UnwrapOptional => node = node.castTag(.UnwrapOptional).?.lhs,
|
||||
|
||||
// True because these are exactly the expressions we need memory locations for.
|
||||
.ArrayInitializer,
|
||||
@ -697,7 +705,6 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
|
||||
.Switch,
|
||||
.Call,
|
||||
.BuiltinCall, // TODO some of these can return false
|
||||
.SuffixOp, // TODO this should be split up
|
||||
=> return true,
|
||||
|
||||
// Depending on AST properties, they may need memory locations.
|
||||
|
||||
@ -2962,9 +2962,9 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS
|
||||
cast_node.params()[1] = try transExpr(rp, scope, subscr_expr, .used, .r_value);
|
||||
cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
node.rtoken = try appendToken(rp.c, .RBrace, "]");
|
||||
node.op.ArrayAccess = &cast_node.base;
|
||||
node.index_expr = &cast_node.base;
|
||||
} else {
|
||||
node.op.ArrayAccess = try transExpr(rp, scope, subscr_expr, .used, .r_value);
|
||||
node.index_expr = try transExpr(rp, scope, subscr_expr, .used, .r_value);
|
||||
node.rtoken = try appendToken(rp.c, .RBrace, "]");
|
||||
}
|
||||
return maybeSuppressResult(rp, scope, result_used, &node.base);
|
||||
@ -4405,9 +4405,9 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
|
||||
fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node {
|
||||
_ = try appendToken(c, .Period, ".");
|
||||
const qm = try appendToken(c, .QuestionMark, "?");
|
||||
const node = try c.arena.create(ast.Node.SuffixOp);
|
||||
const node = try c.arena.create(ast.Node.SimpleSuffixOp);
|
||||
node.* = .{
|
||||
.op = .UnwrapOptional,
|
||||
.base = .{ .tag = .UnwrapOptional },
|
||||
.lhs = wrapped,
|
||||
.rtoken = qm,
|
||||
};
|
||||
@ -4567,23 +4567,21 @@ fn transCreateNodeShiftOp(
|
||||
}
|
||||
|
||||
fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node {
|
||||
const node = try c.arena.create(ast.Node.SuffixOp);
|
||||
const node = try c.arena.create(ast.Node.SimpleSuffixOp);
|
||||
node.* = .{
|
||||
.base = .{ .tag = .Deref },
|
||||
.lhs = lhs,
|
||||
.op = .Deref,
|
||||
.rtoken = try appendToken(c, .PeriodAsterisk, ".*"),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.SuffixOp {
|
||||
fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.ArrayAccess {
|
||||
_ = try appendToken(c, .LBrace, "[");
|
||||
const node = try c.arena.create(ast.Node.SuffixOp);
|
||||
const node = try c.arena.create(ast.Node.ArrayAccess);
|
||||
node.* = .{
|
||||
.lhs = lhs,
|
||||
.op = .{
|
||||
.ArrayAccess = undefined,
|
||||
},
|
||||
.index_expr = undefined,
|
||||
.rtoken = undefined,
|
||||
};
|
||||
return node;
|
||||
@ -6010,7 +6008,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
||||
},
|
||||
.LBracket => {
|
||||
const arr_node = try transCreateNodeArrayAccess(c, node);
|
||||
arr_node.op.ArrayAccess = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
|
||||
arr_node.index_expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
|
||||
arr_node.rtoken = try appendToken(c, .RBracket, "]");
|
||||
node = &arr_node.base;
|
||||
if (it.next().?.id != .RBracket) {
|
||||
@ -6099,7 +6097,6 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
||||
};
|
||||
mem.copy(*ast.Node, tuple_node.list(), init_vals.items);
|
||||
|
||||
|
||||
//(@import("std").mem.zeroInit(T, .{x}))
|
||||
const import_fn_call = try c.createBuiltinCall("@import", 1);
|
||||
const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user