Commit 6f8d732599
Changed files (6)
lib/std/zig/ast.zig
@@ -431,6 +431,7 @@ pub const Node = struct {
ContainerDecl,
Asm,
Comptime,
+ Noasync,
Block,
// Misc
@@ -1078,6 +1079,30 @@ pub const Node = struct {
}
};
+ pub const Noasync = struct {
+ base: Node = Node{ .id = .Noasync },
+ doc_comments: ?*DocComment,
+ noasync_token: TokenIndex,
+ expr: *Node,
+
+ pub fn iterate(self: *Noasync, index: usize) ?*Node {
+ var i = index;
+
+ if (i < 1) return self.expr;
+ i -= 1;
+
+ return null;
+ }
+
+ pub fn firstToken(self: *const Noasync) TokenIndex {
+ return self.noasync_token;
+ }
+
+ pub fn lastToken(self: *const Noasync) TokenIndex {
+ return self.expr.lastToken();
+ }
+ };
+
pub const Payload = struct {
base: Node = Node{ .id = .Payload },
lpipe: TokenIndex,
@@ -1560,9 +1585,7 @@ pub const Node = struct {
pub const Op = union(enum) {
AddressOf,
ArrayType: ArrayInfo,
- Await: struct {
- noasync_token: ?TokenIndex = null,
- },
+ Await,
BitNot,
BoolNot,
Cancel,
lib/std/zig/parse.zig
@@ -856,6 +856,7 @@ fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
/// / IfExpr
/// / KEYWORD_break BreakLabel? Expr?
/// / KEYWORD_comptime Expr
+/// / KEYWORD_noasync Expr
/// / KEYWORD_continue BreakLabel?
/// / KEYWORD_resume Expr
/// / KEYWORD_return Expr?
@@ -870,7 +871,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const label = try parseBreakLabel(arena, it, tree);
const expr_node = try parseExpr(arena, it, tree);
const node = try arena.create(Node.ControlFlowExpression);
- node.* = Node.ControlFlowExpression{
+ node.* = .{
.ltoken = token,
.kind = Node.ControlFlowExpression.Kind{ .Break = label },
.rhs = expr_node,
@@ -883,7 +884,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
.ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
});
const node = try arena.create(Node.Comptime);
- node.* = Node.Comptime{
+ node.* = .{
.doc_comments = null,
.comptime_token = token,
.expr = expr_node,
@@ -891,10 +892,23 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
return &node.base;
}
+ if (eatToken(it, .Keyword_noasync)) |token| {
+ const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
+ .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
+ });
+ const node = try arena.create(Node.Noasync);
+ node.* = .{
+ .doc_comments = null,
+ .noasync_token = token,
+ .expr = expr_node,
+ };
+ return &node.base;
+ }
+
if (eatToken(it, .Keyword_continue)) |token| {
const label = try parseBreakLabel(arena, it, tree);
const node = try arena.create(Node.ControlFlowExpression);
- node.* = Node.ControlFlowExpression{
+ node.* = .{
.ltoken = token,
.kind = Node.ControlFlowExpression.Kind{ .Continue = label },
.rhs = null,
@@ -907,7 +921,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
.ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
});
const node = try arena.create(Node.PrefixOp);
- node.* = Node.PrefixOp{
+ node.* = .{
.op_token = token,
.op = Node.PrefixOp.Op.Resume,
.rhs = expr_node,
@@ -918,7 +932,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
if (eatToken(it, .Keyword_return)) |token| {
const expr_node = try parseExpr(arena, it, tree);
const node = try arena.create(Node.ControlFlowExpression);
- node.* = Node.ControlFlowExpression{
+ node.* = .{
.ltoken = token,
.kind = Node.ControlFlowExpression.Kind.Return,
.rhs = expr_node,
@@ -1126,19 +1140,18 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
/// SuffixExpr
/// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
-/// / KEYWORD_noasync PrimaryTypeExpr SuffixOp* FnCallArguments
/// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
- const maybe_async = eatAnnotatedToken(it, .Keyword_async) orelse eatAnnotatedToken(it, .Keyword_noasync);
+ const maybe_async = eatToken(it, .Keyword_async);
if (maybe_async) |async_token| {
const token_fn = eatToken(it, .Keyword_fn);
- if (async_token.ptr.id == .Keyword_async and token_fn != null) {
+ if (token_fn != null) {
// HACK: If we see the keyword `fn`, then we assume that
// we are parsing an async fn proto, and not a call.
// We therefore put back all tokens consumed by the async
// prefix...
putBackToken(it, token_fn.?);
- putBackToken(it, async_token.index);
+ putBackToken(it, async_token);
return parsePrimaryTypeExpr(arena, it, tree);
}
// TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr
@@ -1167,7 +1180,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
.op = Node.SuffixOp.Op{
.Call = Node.SuffixOp.Op.Call{
.params = params.list,
- .async_token = async_token.index,
+ .async_token = async_token,
},
},
.rtoken = params.rparen,
@@ -1224,6 +1237,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
/// / IfTypeExpr
/// / INTEGER
/// / KEYWORD_comptime TypeExpr
+/// / KEYWORD_noasync TypeExpr
/// / KEYWORD_error DOT IDENTIFIER
/// / KEYWORD_false
/// / KEYWORD_null
@@ -1255,13 +1269,23 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
if (eatToken(it, .Keyword_comptime)) |token| {
const expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
const node = try arena.create(Node.Comptime);
- node.* = Node.Comptime{
+ node.* = .{
.doc_comments = null,
.comptime_token = token,
.expr = expr,
};
return &node.base;
}
+ if (eatToken(it, .Keyword_noasync)) |token| {
+ const expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
+ const node = try arena.create(Node.Noasync);
+ node.* = .{
+ .doc_comments = null,
+ .noasync_token = token,
+ .expr = expr,
+ };
+ return &node.base;
+ }
if (eatToken(it, .Keyword_error)) |token| {
const period = try expectToken(it, tree, .Period);
const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{
@@ -1269,7 +1293,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
});
const global_error_set = try createLiteral(arena, Node.ErrorType, token);
const node = try arena.create(Node.InfixOp);
- node.* = Node.InfixOp{
+ node.* = .{
.op_token = period,
.lhs = global_error_set,
.op = Node.InfixOp.Op.Period,
@@ -1281,7 +1305,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);
if (eatToken(it, .Keyword_anyframe)) |token| {
const node = try arena.create(Node.AnyFrameType);
- node.* = Node.AnyFrameType{
+ node.* = .{
.anyframe_token = token,
.result = null,
};
@@ -2180,18 +2204,6 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
.Ampersand => ops{ .AddressOf = {} },
.Keyword_try => ops{ .Try = {} },
.Keyword_await => ops{ .Await = .{} },
- .Keyword_noasync => if (eatToken(it, .Keyword_await)) |await_tok| {
- const node = try arena.create(Node.PrefixOp);
- node.* = Node.PrefixOp{
- .op_token = await_tok,
- .op = .{ .Await = .{ .noasync_token = token.index } },
- .rhs = undefined, // set by caller
- };
- return &node.base;
- } else {
- putBackToken(it, token.index);
- return null;
- },
else => {
putBackToken(it, token.index);
return null;
lib/std/zig/render.zig
@@ -390,6 +390,12 @@ fn renderExpression(
try renderToken(tree, stream, comptime_node.comptime_token, indent, start_col, Space.Space);
return renderExpression(allocator, stream, tree, indent, start_col, comptime_node.expr, space);
},
+ .Noasync => {
+ const noasync_node = @fieldParentPtr(ast.Node.Noasync, "base", base);
+
+ try renderToken(tree, stream, noasync_node.noasync_token, indent, start_col, Space.Space);
+ return renderExpression(allocator, stream, tree, indent, start_col, noasync_node.expr, space);
+ },
.Suspend => {
const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
@@ -590,9 +596,6 @@ fn renderExpression(
},
.Await => |await_info| {
- if (await_info.noasync_token) |tok| {
- try renderToken(tree, stream, tok, indent, start_col, Space.Space);
- }
try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space);
},
}
src/all_types.hpp
@@ -651,6 +651,7 @@ enum NodeType {
NodeTypeSwitchProng,
NodeTypeSwitchRange,
NodeTypeCompTime,
+ NodeTypeNoAsync,
NodeTypeBreak,
NodeTypeContinue,
NodeTypeAsmExpr,
@@ -991,6 +992,10 @@ struct AstNodeCompTime {
AstNode *expr;
};
+struct AstNodeNoAsync {
+ AstNode *expr;
+};
+
struct AsmOutput {
Buf *asm_symbolic_name;
Buf *constraint;
@@ -1148,7 +1153,6 @@ struct AstNodeErrorType {
};
struct AstNodeAwaitExpr {
- Token *noasync_token;
AstNode *expr;
};
@@ -1199,6 +1203,7 @@ struct AstNode {
AstNodeSwitchProng switch_prong;
AstNodeSwitchRange switch_range;
AstNodeCompTime comptime_expr;
+ AstNodeNoAsync noasync_expr;
AstNodeAsmExpr asm_expr;
AstNodeFieldAccessExpr field_access_expr;
AstNodePtrDerefExpr ptr_deref_expr;
src/ast_render.cpp
@@ -220,6 +220,8 @@ static const char *node_type_str(NodeType node_type) {
return "SwitchRange";
case NodeTypeCompTime:
return "CompTime";
+ case NodeTypeNoAsync:
+ return "NoAsync";
case NodeTypeBreak:
return "Break";
case NodeTypeContinue:
@@ -1091,6 +1093,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
render_node_grouped(ar, node->data.comptime_expr.expr);
break;
}
+ case NodeTypeNoAsync:
+ {
+ fprintf(ar->f, "noasync ");
+ render_node_grouped(ar, node->data.noasync_expr.expr);
+ break;
+ }
case NodeTypeForExpr:
{
if (node->data.for_expr.name != nullptr) {
src/parser.cpp
@@ -1237,6 +1237,7 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) {
// / IfExpr
// / KEYWORD_break BreakLabel? Expr?
// / KEYWORD_comptime Expr
+// / KEYWORD_noasync Expr
// / KEYWORD_continue BreakLabel?
// / KEYWORD_resume Expr
// / KEYWORD_return Expr?
@@ -1271,6 +1272,14 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) {
return res;
}
+ Token *noasync = eat_token_if(pc, TokenIdKeywordNoAsync);
+ if (noasync != nullptr) {
+ AstNode *expr = ast_expect(pc, ast_parse_expr);
+ AstNode *res = ast_create_node(pc, NodeTypeNoAsync, noasync);
+ res->data.noasync_expr.expr = expr;
+ return res;
+ }
+
Token *continue_token = eat_token_if(pc, TokenIdKeywordContinue);
if (continue_token != nullptr) {
Token *label = ast_parse_break_label(pc);
@@ -1459,13 +1468,11 @@ static AstNode *ast_parse_error_union_expr(ParseContext *pc) {
// SuffixExpr
// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
-// / KEYWORD_noasync PrimaryTypeExpr SuffixOp* FnCallArguments
// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
- Token *async_token = eat_token(pc);
- bool is_async = async_token->id == TokenIdKeywordAsync;
- if (is_async || async_token->id == TokenIdKeywordNoAsync) {
- if (is_async && eat_token_if(pc, TokenIdKeywordFn) != nullptr) {
+ Token *async_token = eat_token_if(pc, TokenIdKeywordAsync);
+ if (async_token) {
+ if (eat_token_if(pc, TokenIdKeywordFn) != nullptr) {
// HACK: If we see the keyword `fn`, then we assume that
// we are parsing an async fn proto, and not a call.
// We therefore put back all tokens consumed by the async
@@ -1515,13 +1522,12 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
assert(args->type == NodeTypeFnCallExpr);
AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async_token);
- res->data.fn_call_expr.modifier = is_async ? CallModifierAsync : CallModifierNoAsync;
+ res->data.fn_call_expr.modifier = CallModifierAsync;
res->data.fn_call_expr.seen = false;
res->data.fn_call_expr.fn_ref_expr = child;
res->data.fn_call_expr.params = args->data.fn_call_expr.params;
return res;
}
- put_back_token(pc);
AstNode *res = ast_parse_primary_type_expr(pc);
if (res == nullptr)
@@ -1582,6 +1588,7 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
// / IfTypeExpr
// / INTEGER
// / KEYWORD_comptime TypeExpr
+// / KEYWORD_noasync TypeExpr
// / KEYWORD_error DOT IDENTIFIER
// / KEYWORD_false
// / KEYWORD_null
@@ -1683,6 +1690,14 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {
return res;
}
+ Token *noasync = eat_token_if(pc, TokenIdKeywordNoAsync);
+ if (noasync != nullptr) {
+ AstNode *expr = ast_expect(pc, ast_parse_type_expr);
+ AstNode *res = ast_create_node(pc, NodeTypeNoAsync, noasync);
+ res->data.noasync_expr.expr = expr;
+ return res;
+ }
+
Token *error = eat_token_if(pc, TokenIdKeywordError);
if (error != nullptr) {
Token *dot = expect_token(pc, TokenIdDot);
@@ -2599,14 +2614,10 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) {
return res;
}
- Token *noasync_token = eat_token_if(pc, TokenIdKeywordNoAsync);
Token *await = eat_token_if(pc, TokenIdKeywordAwait);
if (await != nullptr) {
AstNode *res = ast_create_node(pc, NodeTypeAwaitExpr, await);
- res->data.await_expr.noasync_token = noasync_token;
return res;
- } else if (noasync_token != nullptr) {
- put_back_token(pc);
}
return nullptr;
@@ -3125,6 +3136,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeCompTime:
visit_field(&node->data.comptime_expr.expr, visit, context);
break;
+ case NodeTypeNoAsync:
+ visit_field(&node->data.comptime_expr.expr, visit, context);
+ break;
case NodeTypeBreak:
// none
break;