| author | |
| committer | |
| log | 638d5c3aca7ce1e4fd10060079caa0acb66144c0 |
| tree | 7001b05a51eea62061ad9dfcba8b99d904ea1be5 |
| parent | 52c01840ce36f6ed6528fc62c6f3c1426bdce914 |
| parent | 3fd2cd43678d52ca2f737d991edaddfd8b73c2a4 |
| signature |
Implement new noasync syntax12 files changed, 224 insertions(+), 46 deletions(-)
lib/std/zig/ast.zig+25-3| ... | ... | @@ -431,6 +431,7 @@ pub const Node = struct { |
| 431 | 431 | ContainerDecl, |
| 432 | 432 | Asm, |
| 433 | 433 | Comptime, |
| 434 | Noasync, | |
| 434 | 435 | Block, |
| 435 | 436 | |
| 436 | 437 | // Misc |
| ... | ... | @@ -1078,6 +1079,29 @@ pub const Node = struct { |
| 1078 | 1079 | } |
| 1079 | 1080 | }; |
| 1080 | 1081 | |
| 1082 | pub const Noasync = struct { | |
| 1083 | base: Node = Node{ .id = .Noasync }, | |
| 1084 | noasync_token: TokenIndex, | |
| 1085 | expr: *Node, | |
| 1086 | ||
| 1087 | pub fn iterate(self: *Noasync, index: usize) ?*Node { | |
| 1088 | var i = index; | |
| 1089 | ||
| 1090 | if (i < 1) return self.expr; | |
| 1091 | i -= 1; | |
| 1092 | ||
| 1093 | return null; | |
| 1094 | } | |
| 1095 | ||
| 1096 | pub fn firstToken(self: *const Noasync) TokenIndex { | |
| 1097 | return self.noasync_token; | |
| 1098 | } | |
| 1099 | ||
| 1100 | pub fn lastToken(self: *const Noasync) TokenIndex { | |
| 1101 | return self.expr.lastToken(); | |
| 1102 | } | |
| 1103 | }; | |
| 1104 | ||
| 1081 | 1105 | pub const Payload = struct { |
| 1082 | 1106 | base: Node = Node{ .id = .Payload }, |
| 1083 | 1107 | lpipe: TokenIndex, |
| ... | ... | @@ -1560,9 +1584,7 @@ pub const Node = struct { |
| 1560 | 1584 | pub const Op = union(enum) { |
| 1561 | 1585 | AddressOf, |
| 1562 | 1586 | ArrayType: ArrayInfo, |
| 1563 | Await: struct { | |
| 1564 | noasync_token: ?TokenIndex = null, | |
| 1565 | }, | |
| 1587 | Await, | |
| 1566 | 1588 | BitNot, |
| 1567 | 1589 | BoolNot, |
| 1568 | 1590 | Cancel, |
lib/std/zig/parse.zig+49-25| ... | ... | @@ -462,6 +462,7 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 462 | 462 | /// Statement |
| 463 | 463 | /// <- KEYWORD_comptime? VarDecl |
| 464 | 464 | /// / KEYWORD_comptime BlockExprStatement |
| 465 | /// / KEYWORD_noasync BlockExprStatement | |
| 465 | 466 | /// / KEYWORD_suspend (SEMICOLON / BlockExprStatement) |
| 466 | 467 | /// / KEYWORD_defer BlockExprStatement |
| 467 | 468 | /// / KEYWORD_errdefer BlockExprStatement |
| ... | ... | @@ -493,6 +494,19 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No |
| 493 | 494 | return &node.base; |
| 494 | 495 | } |
| 495 | 496 | |
| 497 | if (eatToken(it, .Keyword_noasync)) |noasync_token| { | |
| 498 | const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{ | |
| 499 | .ExpectedBlockOrAssignment = .{ .token = it.index }, | |
| 500 | }); | |
| 501 | ||
| 502 | const node = try arena.create(Node.Noasync); | |
| 503 | node.* = .{ | |
| 504 | .noasync_token = noasync_token, | |
| 505 | .expr = block_expr, | |
| 506 | }; | |
| 507 | return &node.base; | |
| 508 | } | |
| 509 | ||
| 496 | 510 | if (eatToken(it, .Keyword_suspend)) |suspend_token| { |
| 497 | 511 | const semicolon = eatToken(it, .Semicolon); |
| 498 | 512 | |
| ... | ... | @@ -856,6 +870,7 @@ fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 856 | 870 | /// / IfExpr |
| 857 | 871 | /// / KEYWORD_break BreakLabel? Expr? |
| 858 | 872 | /// / KEYWORD_comptime Expr |
| 873 | /// / KEYWORD_noasync Expr | |
| 859 | 874 | /// / KEYWORD_continue BreakLabel? |
| 860 | 875 | /// / KEYWORD_resume Expr |
| 861 | 876 | /// / KEYWORD_return Expr? |
| ... | ... | @@ -870,7 +885,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 870 | 885 | const label = try parseBreakLabel(arena, it, tree); |
| 871 | 886 | const expr_node = try parseExpr(arena, it, tree); |
| 872 | 887 | const node = try arena.create(Node.ControlFlowExpression); |
| 873 | node.* = Node.ControlFlowExpression{ | |
| 888 | node.* = .{ | |
| 874 | 889 | .ltoken = token, |
| 875 | 890 | .kind = Node.ControlFlowExpression.Kind{ .Break = label }, |
| 876 | 891 | .rhs = expr_node, |
| ... | ... | @@ -883,7 +898,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 883 | 898 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, |
| 884 | 899 | }); |
| 885 | 900 | const node = try arena.create(Node.Comptime); |
| 886 | node.* = Node.Comptime{ | |
| 901 | node.* = .{ | |
| 887 | 902 | .doc_comments = null, |
| 888 | 903 | .comptime_token = token, |
| 889 | 904 | .expr = expr_node, |
| ... | ... | @@ -891,10 +906,22 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 891 | 906 | return &node.base; |
| 892 | 907 | } |
| 893 | 908 | |
| 909 | if (eatToken(it, .Keyword_noasync)) |token| { | |
| 910 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 911 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 912 | }); | |
| 913 | const node = try arena.create(Node.Noasync); | |
| 914 | node.* = .{ | |
| 915 | .noasync_token = token, | |
| 916 | .expr = expr_node, | |
| 917 | }; | |
| 918 | return &node.base; | |
| 919 | } | |
| 920 | ||
| 894 | 921 | if (eatToken(it, .Keyword_continue)) |token| { |
| 895 | 922 | const label = try parseBreakLabel(arena, it, tree); |
| 896 | 923 | const node = try arena.create(Node.ControlFlowExpression); |
| 897 | node.* = Node.ControlFlowExpression{ | |
| 924 | node.* = .{ | |
| 898 | 925 | .ltoken = token, |
| 899 | 926 | .kind = Node.ControlFlowExpression.Kind{ .Continue = label }, |
| 900 | 927 | .rhs = null, |
| ... | ... | @@ -907,7 +934,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 907 | 934 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, |
| 908 | 935 | }); |
| 909 | 936 | const node = try arena.create(Node.PrefixOp); |
| 910 | node.* = Node.PrefixOp{ | |
| 937 | node.* = .{ | |
| 911 | 938 | .op_token = token, |
| 912 | 939 | .op = Node.PrefixOp.Op.Resume, |
| 913 | 940 | .rhs = expr_node, |
| ... | ... | @@ -918,7 +945,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 918 | 945 | if (eatToken(it, .Keyword_return)) |token| { |
| 919 | 946 | const expr_node = try parseExpr(arena, it, tree); |
| 920 | 947 | const node = try arena.create(Node.ControlFlowExpression); |
| 921 | node.* = Node.ControlFlowExpression{ | |
| 948 | node.* = .{ | |
| 922 | 949 | .ltoken = token, |
| 923 | 950 | .kind = Node.ControlFlowExpression.Kind.Return, |
| 924 | 951 | .rhs = expr_node, |
| ... | ... | @@ -1126,19 +1153,18 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 1126 | 1153 | |
| 1127 | 1154 | /// SuffixExpr |
| 1128 | 1155 | /// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments |
| 1129 | /// / KEYWORD_noasync PrimaryTypeExpr SuffixOp* FnCallArguments | |
| 1130 | 1156 | /// / PrimaryTypeExpr (SuffixOp / FnCallArguments)* |
| 1131 | 1157 | fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1132 | const maybe_async = eatAnnotatedToken(it, .Keyword_async) orelse eatAnnotatedToken(it, .Keyword_noasync); | |
| 1158 | const maybe_async = eatToken(it, .Keyword_async); | |
| 1133 | 1159 | if (maybe_async) |async_token| { |
| 1134 | 1160 | const token_fn = eatToken(it, .Keyword_fn); |
| 1135 | if (async_token.ptr.id == .Keyword_async and token_fn != null) { | |
| 1161 | if (token_fn != null) { | |
| 1136 | 1162 | // HACK: If we see the keyword `fn`, then we assume that |
| 1137 | 1163 | // we are parsing an async fn proto, and not a call. |
| 1138 | 1164 | // We therefore put back all tokens consumed by the async |
| 1139 | 1165 | // prefix... |
| 1140 | 1166 | putBackToken(it, token_fn.?); |
| 1141 | putBackToken(it, async_token.index); | |
| 1167 | putBackToken(it, async_token); | |
| 1142 | 1168 | return parsePrimaryTypeExpr(arena, it, tree); |
| 1143 | 1169 | } |
| 1144 | 1170 | // TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr |
| ... | ... | @@ -1167,7 +1193,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1167 | 1193 | .op = Node.SuffixOp.Op{ |
| 1168 | 1194 | .Call = Node.SuffixOp.Op.Call{ |
| 1169 | 1195 | .params = params.list, |
| 1170 | .async_token = async_token.index, | |
| 1196 | .async_token = async_token, | |
| 1171 | 1197 | }, |
| 1172 | 1198 | }, |
| 1173 | 1199 | .rtoken = params.rparen, |
| ... | ... | @@ -1224,6 +1250,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1224 | 1250 | /// / IfTypeExpr |
| 1225 | 1251 | /// / INTEGER |
| 1226 | 1252 | /// / KEYWORD_comptime TypeExpr |
| 1253 | /// / KEYWORD_noasync TypeExpr | |
| 1227 | 1254 | /// / KEYWORD_error DOT IDENTIFIER |
| 1228 | 1255 | /// / KEYWORD_false |
| 1229 | 1256 | /// / KEYWORD_null |
| ... | ... | @@ -1255,13 +1282,22 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N |
| 1255 | 1282 | if (eatToken(it, .Keyword_comptime)) |token| { |
| 1256 | 1283 | const expr = (try parseTypeExpr(arena, it, tree)) orelse return null; |
| 1257 | 1284 | const node = try arena.create(Node.Comptime); |
| 1258 | node.* = Node.Comptime{ | |
| 1285 | node.* = .{ | |
| 1259 | 1286 | .doc_comments = null, |
| 1260 | 1287 | .comptime_token = token, |
| 1261 | 1288 | .expr = expr, |
| 1262 | 1289 | }; |
| 1263 | 1290 | return &node.base; |
| 1264 | 1291 | } |
| 1292 | if (eatToken(it, .Keyword_noasync)) |token| { | |
| 1293 | const expr = (try parseTypeExpr(arena, it, tree)) orelse return null; | |
| 1294 | const node = try arena.create(Node.Noasync); | |
| 1295 | node.* = .{ | |
| 1296 | .noasync_token = token, | |
| 1297 | .expr = expr, | |
| 1298 | }; | |
| 1299 | return &node.base; | |
| 1300 | } | |
| 1265 | 1301 | if (eatToken(it, .Keyword_error)) |token| { |
| 1266 | 1302 | const period = try expectToken(it, tree, .Period); |
| 1267 | 1303 | const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ |
| ... | ... | @@ -1269,7 +1305,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N |
| 1269 | 1305 | }); |
| 1270 | 1306 | const global_error_set = try createLiteral(arena, Node.ErrorType, token); |
| 1271 | 1307 | const node = try arena.create(Node.InfixOp); |
| 1272 | node.* = Node.InfixOp{ | |
| 1308 | node.* = .{ | |
| 1273 | 1309 | .op_token = period, |
| 1274 | 1310 | .lhs = global_error_set, |
| 1275 | 1311 | .op = Node.InfixOp.Op.Period, |
| ... | ... | @@ -1281,7 +1317,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N |
| 1281 | 1317 | if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token); |
| 1282 | 1318 | if (eatToken(it, .Keyword_anyframe)) |token| { |
| 1283 | 1319 | const node = try arena.create(Node.AnyFrameType); |
| 1284 | node.* = Node.AnyFrameType{ | |
| 1320 | node.* = .{ | |
| 1285 | 1321 | .anyframe_token = token, |
| 1286 | 1322 | .result = null, |
| 1287 | 1323 | }; |
| ... | ... | @@ -2180,18 +2216,6 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2180 | 2216 | .Ampersand => ops{ .AddressOf = {} }, |
| 2181 | 2217 | .Keyword_try => ops{ .Try = {} }, |
| 2182 | 2218 | .Keyword_await => ops{ .Await = .{} }, |
| 2183 | .Keyword_noasync => if (eatToken(it, .Keyword_await)) |await_tok| { | |
| 2184 | const node = try arena.create(Node.PrefixOp); | |
| 2185 | node.* = Node.PrefixOp{ | |
| 2186 | .op_token = await_tok, | |
| 2187 | .op = .{ .Await = .{ .noasync_token = token.index } }, | |
| 2188 | .rhs = undefined, // set by caller | |
| 2189 | }; | |
| 2190 | return &node.base; | |
| 2191 | } else { | |
| 2192 | putBackToken(it, token.index); | |
| 2193 | return null; | |
| 2194 | }, | |
| 2195 | 2219 | else => { |
| 2196 | 2220 | putBackToken(it, token.index); |
| 2197 | 2221 | return null; |
lib/std/zig/render.zig+6-3| ... | ... | @@ -390,6 +390,12 @@ fn renderExpression( |
| 390 | 390 | try renderToken(tree, stream, comptime_node.comptime_token, indent, start_col, Space.Space); |
| 391 | 391 | return renderExpression(allocator, stream, tree, indent, start_col, comptime_node.expr, space); |
| 392 | 392 | }, |
| 393 | .Noasync => { | |
| 394 | const noasync_node = @fieldParentPtr(ast.Node.Noasync, "base", base); | |
| 395 | ||
| 396 | try renderToken(tree, stream, noasync_node.noasync_token, indent, start_col, Space.Space); | |
| 397 | return renderExpression(allocator, stream, tree, indent, start_col, noasync_node.expr, space); | |
| 398 | }, | |
| 393 | 399 | |
| 394 | 400 | .Suspend => { |
| 395 | 401 | const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base); |
| ... | ... | @@ -590,9 +596,6 @@ fn renderExpression( |
| 590 | 596 | }, |
| 591 | 597 | |
| 592 | 598 | .Await => |await_info| { |
| 593 | if (await_info.noasync_token) |tok| { | |
| 594 | try renderToken(tree, stream, tok, indent, start_col, Space.Space); | |
| 595 | } | |
| 596 | 599 | try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space); |
| 597 | 600 | }, |
| 598 | 601 | } |
src/all_types.hpp+12-1| ... | ... | @@ -651,6 +651,7 @@ enum NodeType { |
| 651 | 651 | NodeTypeSwitchProng, |
| 652 | 652 | NodeTypeSwitchRange, |
| 653 | 653 | NodeTypeCompTime, |
| 654 | NodeTypeNoAsync, | |
| 654 | 655 | NodeTypeBreak, |
| 655 | 656 | NodeTypeContinue, |
| 656 | 657 | NodeTypeAsmExpr, |
| ... | ... | @@ -991,6 +992,10 @@ struct AstNodeCompTime { |
| 991 | 992 | AstNode *expr; |
| 992 | 993 | }; |
| 993 | 994 | |
| 995 | struct AstNodeNoAsync { | |
| 996 | AstNode *expr; | |
| 997 | }; | |
| 998 | ||
| 994 | 999 | struct AsmOutput { |
| 995 | 1000 | Buf *asm_symbolic_name; |
| 996 | 1001 | Buf *constraint; |
| ... | ... | @@ -1148,7 +1153,6 @@ struct AstNodeErrorType { |
| 1148 | 1153 | }; |
| 1149 | 1154 | |
| 1150 | 1155 | struct AstNodeAwaitExpr { |
| 1151 | Token *noasync_token; | |
| 1152 | 1156 | AstNode *expr; |
| 1153 | 1157 | }; |
| 1154 | 1158 | |
| ... | ... | @@ -1199,6 +1203,7 @@ struct AstNode { |
| 1199 | 1203 | AstNodeSwitchProng switch_prong; |
| 1200 | 1204 | AstNodeSwitchRange switch_range; |
| 1201 | 1205 | AstNodeCompTime comptime_expr; |
| 1206 | AstNodeNoAsync noasync_expr; | |
| 1202 | 1207 | AstNodeAsmExpr asm_expr; |
| 1203 | 1208 | AstNodeFieldAccessExpr field_access_expr; |
| 1204 | 1209 | AstNodePtrDerefExpr ptr_deref_expr; |
| ... | ... | @@ -2325,6 +2330,7 @@ enum ScopeId { |
| 2325 | 2330 | ScopeIdRuntime, |
| 2326 | 2331 | ScopeIdTypeOf, |
| 2327 | 2332 | ScopeIdExpr, |
| 2333 | ScopeIdNoAsync, | |
| 2328 | 2334 | }; |
| 2329 | 2335 | |
| 2330 | 2336 | struct Scope { |
| ... | ... | @@ -2457,6 +2463,11 @@ struct ScopeCompTime { |
| 2457 | 2463 | Scope base; |
| 2458 | 2464 | }; |
| 2459 | 2465 | |
| 2466 | // This scope is created for a noasync expression. | |
| 2467 | // NodeTypeNoAsync | |
| 2468 | struct ScopeNoAsync { | |
| 2469 | Scope base; | |
| 2470 | }; | |
| 2460 | 2471 | |
| 2461 | 2472 | // This scope is created for a function definition. |
| 2462 | 2473 | // NodeTypeFnDef |
src/analyze.cpp+9| ... | ... | @@ -106,6 +106,7 @@ static ScopeExpr *find_expr_scope(Scope *scope) { |
| 106 | 106 | case ScopeIdDecls: |
| 107 | 107 | case ScopeIdFnDef: |
| 108 | 108 | case ScopeIdCompTime: |
| 109 | case ScopeIdNoAsync: | |
| 109 | 110 | case ScopeIdVarDecl: |
| 110 | 111 | case ScopeIdCImport: |
| 111 | 112 | case ScopeIdSuspend: |
| ... | ... | @@ -226,6 +227,12 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) { |
| 226 | 227 | return &scope->base; |
| 227 | 228 | } |
| 228 | 229 | |
| 230 | Scope *create_noasync_scope(CodeGen *g, AstNode *node, Scope *parent) { | |
| 231 | ScopeNoAsync *scope = heap::c_allocator.create<ScopeNoAsync>(); | |
| 232 | init_scope(g, &scope->base, ScopeIdNoAsync, node, parent); | |
| 233 | return &scope->base; | |
| 234 | } | |
| 235 | ||
| 229 | 236 | Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent) { |
| 230 | 237 | ScopeTypeOf *scope = heap::c_allocator.create<ScopeTypeOf>(); |
| 231 | 238 | init_scope(g, &scope->base, ScopeIdTypeOf, node, parent); |
| ... | ... | @@ -3755,6 +3762,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 3755 | 3762 | case NodeTypeCompTime: |
| 3756 | 3763 | preview_comptime_decl(g, node, decls_scope); |
| 3757 | 3764 | break; |
| 3765 | case NodeTypeNoAsync: | |
| 3758 | 3766 | case NodeTypeParamDecl: |
| 3759 | 3767 | case NodeTypeReturnExpr: |
| 3760 | 3768 | case NodeTypeDefer: |
| ... | ... | @@ -6176,6 +6184,7 @@ static void mark_suspension_point(Scope *scope) { |
| 6176 | 6184 | case ScopeIdDecls: |
| 6177 | 6185 | case ScopeIdFnDef: |
| 6178 | 6186 | case ScopeIdCompTime: |
| 6187 | case ScopeIdNoAsync: | |
| 6179 | 6188 | case ScopeIdCImport: |
| 6180 | 6189 | case ScopeIdSuspend: |
| 6181 | 6190 | case ScopeIdTypeOf: |
src/analyze.hpp+1| ... | ... | @@ -125,6 +125,7 @@ ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 125 | 125 | ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 126 | 126 | ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry); |
| 127 | 127 | Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 128 | Scope *create_noasync_scope(CodeGen *g, AstNode *node, Scope *parent); | |
| 128 | 129 | Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstSrc *is_comptime); |
| 129 | 130 | Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 130 | 131 | ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent); |
src/ast_render.cpp+8| ... | ... | @@ -220,6 +220,8 @@ static const char *node_type_str(NodeType node_type) { |
| 220 | 220 | return "SwitchRange"; |
| 221 | 221 | case NodeTypeCompTime: |
| 222 | 222 | return "CompTime"; |
| 223 | case NodeTypeNoAsync: | |
| 224 | return "NoAsync"; | |
| 223 | 225 | case NodeTypeBreak: |
| 224 | 226 | return "Break"; |
| 225 | 227 | case NodeTypeContinue: |
| ... | ... | @@ -1091,6 +1093,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 1091 | 1093 | render_node_grouped(ar, node->data.comptime_expr.expr); |
| 1092 | 1094 | break; |
| 1093 | 1095 | } |
| 1096 | case NodeTypeNoAsync: | |
| 1097 | { | |
| 1098 | fprintf(ar->f, "noasync "); | |
| 1099 | render_node_grouped(ar, node->data.noasync_expr.expr); | |
| 1100 | break; | |
| 1101 | } | |
| 1094 | 1102 | case NodeTypeForExpr: |
| 1095 | 1103 | { |
| 1096 | 1104 | if (node->data.for_expr.name != nullptr) { |
src/codegen.cpp+3-1| ... | ... | @@ -687,6 +687,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { |
| 687 | 687 | case ScopeIdLoop: |
| 688 | 688 | case ScopeIdSuspend: |
| 689 | 689 | case ScopeIdCompTime: |
| 690 | case ScopeIdNoAsync: | |
| 690 | 691 | case ScopeIdRuntime: |
| 691 | 692 | case ScopeIdTypeOf: |
| 692 | 693 | case ScopeIdExpr: |
| ... | ... | @@ -968,7 +969,7 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { |
| 968 | 969 | case PanicMsgIdResumedFnPendingAwait: |
| 969 | 970 | return buf_create_from_str("resumed an async function which can only be awaited"); |
| 970 | 971 | case PanicMsgIdBadNoAsyncCall: |
| 971 | return buf_create_from_str("async function called with noasync suspended"); | |
| 972 | return buf_create_from_str("async function called in noasync scope suspended"); | |
| 972 | 973 | case PanicMsgIdResumeNotSuspendedFn: |
| 973 | 974 | return buf_create_from_str("resumed a non-suspended function"); |
| 974 | 975 | case PanicMsgIdBadSentinel: |
| ... | ... | @@ -3934,6 +3935,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) { |
| 3934 | 3935 | case ScopeIdLoop: |
| 3935 | 3936 | case ScopeIdSuspend: |
| 3936 | 3937 | case ScopeIdCompTime: |
| 3938 | case ScopeIdNoAsync: | |
| 3937 | 3939 | case ScopeIdRuntime: |
| 3938 | 3940 | case ScopeIdTypeOf: |
| 3939 | 3941 | case ScopeIdExpr: |
src/ir.cpp+46-2| ... | ... | @@ -4978,6 +4978,7 @@ static void ir_count_defers(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_ |
| 4978 | 4978 | case ScopeIdLoop: |
| 4979 | 4979 | case ScopeIdSuspend: |
| 4980 | 4980 | case ScopeIdCompTime: |
| 4981 | case ScopeIdNoAsync: | |
| 4981 | 4982 | case ScopeIdRuntime: |
| 4982 | 4983 | case ScopeIdTypeOf: |
| 4983 | 4984 | case ScopeIdExpr: |
| ... | ... | @@ -5033,6 +5034,7 @@ static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope |
| 5033 | 5034 | case ScopeIdLoop: |
| 5034 | 5035 | case ScopeIdSuspend: |
| 5035 | 5036 | case ScopeIdCompTime: |
| 5037 | case ScopeIdNoAsync: | |
| 5036 | 5038 | case ScopeIdRuntime: |
| 5037 | 5039 | case ScopeIdTypeOf: |
| 5038 | 5040 | case ScopeIdExpr: |
| ... | ... | @@ -7307,6 +7309,18 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod |
| 7307 | 7309 | zig_unreachable(); |
| 7308 | 7310 | } |
| 7309 | 7311 | |
| 7312 | static ScopeNoAsync *get_scope_noasync(Scope *scope) { | |
| 7313 | while (scope) { | |
| 7314 | if (scope->id == ScopeIdNoAsync) | |
| 7315 | return (ScopeNoAsync *)scope; | |
| 7316 | if (scope->id == ScopeIdFnDef) | |
| 7317 | return nullptr; | |
| 7318 | ||
| 7319 | scope = scope->parent; | |
| 7320 | } | |
| 7321 | return nullptr; | |
| 7322 | } | |
| 7323 | ||
| 7310 | 7324 | static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, |
| 7311 | 7325 | ResultLoc *result_loc) |
| 7312 | 7326 | { |
| ... | ... | @@ -7315,8 +7329,19 @@ static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node, |
| 7315 | 7329 | if (node->data.fn_call_expr.modifier == CallModifierBuiltin) |
| 7316 | 7330 | return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc); |
| 7317 | 7331 | |
| 7332 | bool is_noasync = get_scope_noasync(scope) != nullptr; | |
| 7333 | CallModifier modifier = node->data.fn_call_expr.modifier; | |
| 7334 | if (is_noasync) { | |
| 7335 | if (modifier == CallModifierAsync) { | |
| 7336 | add_node_error(irb->codegen, node, | |
| 7337 | buf_sprintf("async call in noasync scope")); | |
| 7338 | return irb->codegen->invalid_inst_src; | |
| 7339 | } | |
| 7340 | modifier = CallModifierNoAsync; | |
| 7341 | } | |
| 7342 | ||
| 7318 | 7343 | AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; |
| 7319 | return ir_gen_fn_call_with_args(irb, scope, node, fn_ref_node, node->data.fn_call_expr.modifier, | |
| 7344 | return ir_gen_fn_call_with_args(irb, scope, node, fn_ref_node, modifier, | |
| 7320 | 7345 | nullptr, node->data.fn_call_expr.params.items, node->data.fn_call_expr.params.length, lval, result_loc); |
| 7321 | 7346 | } |
| 7322 | 7347 | |
| ... | ... | @@ -9170,6 +9195,14 @@ static IrInstSrc *ir_gen_comptime(IrBuilderSrc *irb, Scope *parent_scope, AstNod |
| 9170 | 9195 | return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr); |
| 9171 | 9196 | } |
| 9172 | 9197 | |
| 9198 | static IrInstSrc *ir_gen_noasync(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval) { | |
| 9199 | assert(node->type == NodeTypeNoAsync); | |
| 9200 | ||
| 9201 | Scope *child_scope = create_noasync_scope(irb->codegen, node, parent_scope); | |
| 9202 | // purposefully pass null for result_loc and let EndExpr handle it | |
| 9203 | return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr); | |
| 9204 | } | |
| 9205 | ||
| 9173 | 9206 | static IrInstSrc *ir_gen_return_from_block(IrBuilderSrc *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) { |
| 9174 | 9207 | IrInstSrc *is_comptime; |
| 9175 | 9208 | if (ir_should_inline(irb->exec, break_scope)) { |
| ... | ... | @@ -9750,6 +9783,10 @@ static IrInstSrc *ir_gen_fn_proto(IrBuilderSrc *irb, Scope *parent_scope, AstNod |
| 9750 | 9783 | |
| 9751 | 9784 | static IrInstSrc *ir_gen_resume(IrBuilderSrc *irb, Scope *scope, AstNode *node) { |
| 9752 | 9785 | assert(node->type == NodeTypeResume); |
| 9786 | if (get_scope_noasync(scope) != nullptr) { | |
| 9787 | add_node_error(irb->codegen, node, buf_sprintf("resume in noasync scope")); | |
| 9788 | return irb->codegen->invalid_inst_src; | |
| 9789 | } | |
| 9753 | 9790 | |
| 9754 | 9791 | IrInstSrc *target_inst = ir_gen_node_extra(irb, node->data.resume_expr.expr, scope, LValPtr, nullptr); |
| 9755 | 9792 | if (target_inst == irb->codegen->invalid_inst_src) |
| ... | ... | @@ -9763,7 +9800,7 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no |
| 9763 | 9800 | { |
| 9764 | 9801 | assert(node->type == NodeTypeAwaitExpr); |
| 9765 | 9802 | |
| 9766 | bool is_noasync = node->data.await_expr.noasync_token != nullptr; | |
| 9803 | bool is_noasync = get_scope_noasync(scope) != nullptr; | |
| 9767 | 9804 | |
| 9768 | 9805 | AstNode *expr_node = node->data.await_expr.expr; |
| 9769 | 9806 | if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) { |
| ... | ... | @@ -9809,6 +9846,11 @@ static IrInstSrc *ir_gen_suspend(IrBuilderSrc *irb, Scope *parent_scope, AstNode |
| 9809 | 9846 | add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition")); |
| 9810 | 9847 | return irb->codegen->invalid_inst_src; |
| 9811 | 9848 | } |
| 9849 | if (get_scope_noasync(parent_scope) != nullptr) { | |
| 9850 | add_node_error(irb->codegen, node, buf_sprintf("suspend in noasync scope")); | |
| 9851 | return irb->codegen->invalid_inst_src; | |
| 9852 | } | |
| 9853 | ||
| 9812 | 9854 | ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope); |
| 9813 | 9855 | if (existing_suspend_scope) { |
| 9814 | 9856 | if (!existing_suspend_scope->reported_err) { |
| ... | ... | @@ -9938,6 +9980,8 @@ static IrInstSrc *ir_gen_node_raw(IrBuilderSrc *irb, AstNode *node, Scope *scope |
| 9938 | 9980 | return ir_gen_switch_expr(irb, scope, node, lval, result_loc); |
| 9939 | 9981 | case NodeTypeCompTime: |
| 9940 | 9982 | return ir_expr_wrap(irb, scope, ir_gen_comptime(irb, scope, node, lval), result_loc); |
| 9983 | case NodeTypeNoAsync: | |
| 9984 | return ir_expr_wrap(irb, scope, ir_gen_noasync(irb, scope, node, lval), result_loc); | |
| 9941 | 9985 | case NodeTypeErrorType: |
| 9942 | 9986 | return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval, result_loc); |
| 9943 | 9987 | case NodeTypeBreak: |
src/parser.cpp+34-11| ... | ... | @@ -876,6 +876,7 @@ static AstNode *ast_parse_container_field(ParseContext *pc) { |
| 876 | 876 | // Statement |
| 877 | 877 | // <- KEYWORD_comptime? VarDecl |
| 878 | 878 | // / KEYWORD_comptime BlockExprStatement |
| 879 | // / KEYWORD_noasync BlockExprStatement | |
| 879 | 880 | // / KEYWORD_suspend (SEMICOLON / BlockExprStatement) |
| 880 | 881 | // / KEYWORD_defer BlockExprStatement |
| 881 | 882 | // / KEYWORD_errdefer BlockExprStatement |
| ... | ... | @@ -899,6 +900,14 @@ static AstNode *ast_parse_statement(ParseContext *pc) { |
| 899 | 900 | return res; |
| 900 | 901 | } |
| 901 | 902 | |
| 903 | Token *noasync = eat_token_if(pc, TokenIdKeywordNoAsync); | |
| 904 | if (noasync != nullptr) { | |
| 905 | AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); | |
| 906 | AstNode *res = ast_create_node(pc, NodeTypeNoAsync, noasync); | |
| 907 | res->data.noasync_expr.expr = statement; | |
| 908 | return res; | |
| 909 | } | |
| 910 | ||
| 902 | 911 | Token *suspend = eat_token_if(pc, TokenIdKeywordSuspend); |
| 903 | 912 | if (suspend != nullptr) { |
| 904 | 913 | AstNode *statement = nullptr; |
| ... | ... | @@ -1237,6 +1246,7 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) { |
| 1237 | 1246 | // / IfExpr |
| 1238 | 1247 | // / KEYWORD_break BreakLabel? Expr? |
| 1239 | 1248 | // / KEYWORD_comptime Expr |
| 1249 | // / KEYWORD_noasync Expr | |
| 1240 | 1250 | // / KEYWORD_continue BreakLabel? |
| 1241 | 1251 | // / KEYWORD_resume Expr |
| 1242 | 1252 | // / KEYWORD_return Expr? |
| ... | ... | @@ -1271,6 +1281,14 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) { |
| 1271 | 1281 | return res; |
| 1272 | 1282 | } |
| 1273 | 1283 | |
| 1284 | Token *noasync = eat_token_if(pc, TokenIdKeywordNoAsync); | |
| 1285 | if (noasync != nullptr) { | |
| 1286 | AstNode *expr = ast_expect(pc, ast_parse_expr); | |
| 1287 | AstNode *res = ast_create_node(pc, NodeTypeNoAsync, noasync); | |
| 1288 | res->data.noasync_expr.expr = expr; | |
| 1289 | return res; | |
| 1290 | } | |
| 1291 | ||
| 1274 | 1292 | Token *continue_token = eat_token_if(pc, TokenIdKeywordContinue); |
| 1275 | 1293 | if (continue_token != nullptr) { |
| 1276 | 1294 | Token *label = ast_parse_break_label(pc); |
| ... | ... | @@ -1459,13 +1477,11 @@ static AstNode *ast_parse_error_union_expr(ParseContext *pc) { |
| 1459 | 1477 | |
| 1460 | 1478 | // SuffixExpr |
| 1461 | 1479 | // <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments |
| 1462 | // / KEYWORD_noasync PrimaryTypeExpr SuffixOp* FnCallArguments | |
| 1463 | 1480 | // / PrimaryTypeExpr (SuffixOp / FnCallArguments)* |
| 1464 | 1481 | static AstNode *ast_parse_suffix_expr(ParseContext *pc) { |
| 1465 | Token *async_token = eat_token(pc); | |
| 1466 | bool is_async = async_token->id == TokenIdKeywordAsync; | |
| 1467 | if (is_async || async_token->id == TokenIdKeywordNoAsync) { | |
| 1468 | if (is_async && eat_token_if(pc, TokenIdKeywordFn) != nullptr) { | |
| 1482 | Token *async_token = eat_token_if(pc, TokenIdKeywordAsync); | |
| 1483 | if (async_token) { | |
| 1484 | if (eat_token_if(pc, TokenIdKeywordFn) != nullptr) { | |
| 1469 | 1485 | // HACK: If we see the keyword `fn`, then we assume that |
| 1470 | 1486 | // we are parsing an async fn proto, and not a call. |
| 1471 | 1487 | // We therefore put back all tokens consumed by the async |
| ... | ... | @@ -1515,13 +1531,12 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) { |
| 1515 | 1531 | assert(args->type == NodeTypeFnCallExpr); |
| 1516 | 1532 | |
| 1517 | 1533 | AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async_token); |
| 1518 | res->data.fn_call_expr.modifier = is_async ? CallModifierAsync : CallModifierNoAsync; | |
| 1534 | res->data.fn_call_expr.modifier = CallModifierAsync; | |
| 1519 | 1535 | res->data.fn_call_expr.seen = false; |
| 1520 | 1536 | res->data.fn_call_expr.fn_ref_expr = child; |
| 1521 | 1537 | res->data.fn_call_expr.params = args->data.fn_call_expr.params; |
| 1522 | 1538 | return res; |
| 1523 | 1539 | } |
| 1524 | put_back_token(pc); | |
| 1525 | 1540 | |
| 1526 | 1541 | AstNode *res = ast_parse_primary_type_expr(pc); |
| 1527 | 1542 | if (res == nullptr) |
| ... | ... | @@ -1582,6 +1597,7 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) { |
| 1582 | 1597 | // / IfTypeExpr |
| 1583 | 1598 | // / INTEGER |
| 1584 | 1599 | // / KEYWORD_comptime TypeExpr |
| 1600 | // / KEYWORD_noasync TypeExpr | |
| 1585 | 1601 | // / KEYWORD_error DOT IDENTIFIER |
| 1586 | 1602 | // / KEYWORD_false |
| 1587 | 1603 | // / KEYWORD_null |
| ... | ... | @@ -1683,6 +1699,14 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { |
| 1683 | 1699 | return res; |
| 1684 | 1700 | } |
| 1685 | 1701 | |
| 1702 | Token *noasync = eat_token_if(pc, TokenIdKeywordNoAsync); | |
| 1703 | if (noasync != nullptr) { | |
| 1704 | AstNode *expr = ast_expect(pc, ast_parse_type_expr); | |
| 1705 | AstNode *res = ast_create_node(pc, NodeTypeNoAsync, noasync); | |
| 1706 | res->data.noasync_expr.expr = expr; | |
| 1707 | return res; | |
| 1708 | } | |
| 1709 | ||
| 1686 | 1710 | Token *error = eat_token_if(pc, TokenIdKeywordError); |
| 1687 | 1711 | if (error != nullptr) { |
| 1688 | 1712 | Token *dot = expect_token(pc, TokenIdDot); |
| ... | ... | @@ -2599,14 +2623,10 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) { |
| 2599 | 2623 | return res; |
| 2600 | 2624 | } |
| 2601 | 2625 | |
| 2602 | Token *noasync_token = eat_token_if(pc, TokenIdKeywordNoAsync); | |
| 2603 | 2626 | Token *await = eat_token_if(pc, TokenIdKeywordAwait); |
| 2604 | 2627 | if (await != nullptr) { |
| 2605 | 2628 | AstNode *res = ast_create_node(pc, NodeTypeAwaitExpr, await); |
| 2606 | res->data.await_expr.noasync_token = noasync_token; | |
| 2607 | 2629 | return res; |
| 2608 | } else if (noasync_token != nullptr) { | |
| 2609 | put_back_token(pc); | |
| 2610 | 2630 | } |
| 2611 | 2631 | |
| 2612 | 2632 | return nullptr; |
| ... | ... | @@ -3125,6 +3145,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 3125 | 3145 | case NodeTypeCompTime: |
| 3126 | 3146 | visit_field(&node->data.comptime_expr.expr, visit, context); |
| 3127 | 3147 | break; |
| 3148 | case NodeTypeNoAsync: | |
| 3149 | visit_field(&node->data.comptime_expr.expr, visit, context); | |
| 3150 | break; | |
| 3128 | 3151 | case NodeTypeBreak: |
| 3129 | 3152 | // none |
| 3130 | 3153 | break; |
test/compile_errors.zig+15| ... | ... | @@ -2,6 +2,21 @@ const tests = @import("tests.zig"); |
| 2 | 2 | const std = @import("std"); |
| 3 | 3 | |
| 4 | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.addTest("combination of noasync and async", | |
| 6 | \\export fn entry() void { | |
| 7 | \\ noasync { | |
| 8 | \\ const bar = async foo(); | |
| 9 | \\ suspend; | |
| 10 | \\ resume bar; | |
| 11 | \\ } | |
| 12 | \\} | |
| 13 | \\fn foo() void {} | |
| 14 | , &[_][]const u8{ | |
| 15 | "tmp.zig:3:21: error: async call in noasync scope", | |
| 16 | "tmp.zig:4:9: error: suspend in noasync scope", | |
| 17 | "tmp.zig:5:9: error: resume in noasync scope", | |
| 18 | }); | |
| 19 | ||
| 5 | 20 | cases.addTest("@TypeOf with no arguments", |
| 6 | 21 | \\export fn entry() void { |
| 7 | 22 | \\ _ = @TypeOf(); |
test/stage1/behavior/async_fn.zig+16| ... | ... | @@ -1531,3 +1531,19 @@ test "noasync await" { |
| 1531 | 1531 | S.doTheTest(); |
| 1532 | 1532 | expect(S.finished); |
| 1533 | 1533 | } |
| 1534 | ||
| 1535 | test "noasync on function calls" { | |
| 1536 | const S0 = struct { | |
| 1537 | b: i32 = 42, | |
| 1538 | }; | |
| 1539 | const S1 = struct { | |
| 1540 | fn c() S0 { | |
| 1541 | return S0{}; | |
| 1542 | } | |
| 1543 | fn d() !S0 { | |
| 1544 | return S0{}; | |
| 1545 | } | |
| 1546 | }; | |
| 1547 | expectEqual(@as(i32, 42), noasync S1.c().b); | |
| 1548 | expectEqual(@as(i32, 42), (try noasync S1.d()).b); | |
| 1549 | } |