| author | |
| committer | |
| log | d0e996405bff4352c78c570b4944b369d642d058 |
| tree | d2b43b7fe6889a77a1c15e2e43bf4be1f8dc0e53 |
| parent | 7ada59f873738931b4d162372dff0a33442112b6 |
| signature | Commit is signed but in an unrecognized format. |
4 files changed, 63 insertions(+), 20 deletions(-)
lib/std/zig/ast.zig+2| ... | @@ -880,6 +880,8 @@ pub const Node = struct { | ... | @@ -880,6 +880,8 @@ pub const Node = struct { |
| 880 | align_expr: ?*Node, // populated if align(A) is present | 880 | align_expr: ?*Node, // populated if align(A) is present |
| 881 | section_expr: ?*Node, // populated if linksection(A) is present | 881 | section_expr: ?*Node, // populated if linksection(A) is present |
| 882 | callconv_expr: ?*Node, // populated if callconv(A) is present | 882 | callconv_expr: ?*Node, // populated if callconv(A) is present |
| 883 | is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is | ||
| 884 | is_async: bool = false, // TODO: remove once async fn rewriting is | ||
| 883 | 885 | ||
| 884 | pub const ParamList = SegmentedList(*Node, 2); | 886 | pub const ParamList = SegmentedList(*Node, 2); |
| 885 | 887 |
lib/std/zig/parse.zig+31-1| ... | @@ -337,7 +337,25 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -337,7 +337,25 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 337 | 337 | ||
| 338 | /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) | 338 | /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) |
| 339 | fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 339 | fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 340 | const fn_token = eatToken(it, .Keyword_fn) orelse return null; | 340 | // TODO: Remove once extern/async fn rewriting is |
| 341 | var is_async = false; | ||
| 342 | var is_extern = false; | ||
| 343 | const cc_token: ?usize = blk: { | ||
| 344 | if (eatToken(it, .Keyword_extern)) |token| { | ||
| 345 | is_extern = true; | ||
| 346 | break :blk token; | ||
| 347 | } | ||
| 348 | if (eatToken(it, .Keyword_async)) |token| { | ||
| 349 | is_async = true; | ||
| 350 | break :blk token; | ||
| 351 | } | ||
| 352 | break :blk null; | ||
| 353 | }; | ||
| 354 | const fn_token = eatToken(it, .Keyword_fn) orelse { | ||
| 355 | if (cc_token) |token| | ||
| 356 | putBackToken(it, token); | ||
| 357 | return null; | ||
| 358 | }; | ||
| 341 | const name_token = eatToken(it, .Identifier); | 359 | const name_token = eatToken(it, .Identifier); |
| 342 | const lparen = try expectToken(it, tree, .LParen); | 360 | const lparen = try expectToken(it, tree, .LParen); |
| 343 | const params = try parseParamDeclList(arena, it, tree); | 361 | const params = try parseParamDeclList(arena, it, tree); |
| ... | @@ -381,6 +399,8 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -381,6 +399,8 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 381 | .align_expr = align_expr, | 399 | .align_expr = align_expr, |
| 382 | .section_expr = section_expr, | 400 | .section_expr = section_expr, |
| 383 | .callconv_expr = callconv_expr, | 401 | .callconv_expr = callconv_expr, |
| 402 | .is_extern_prototype = is_extern, | ||
| 403 | .is_async = is_async, | ||
| 384 | }; | 404 | }; |
| 385 | 405 | ||
| 386 | return &fn_proto_node.base; | 406 | return &fn_proto_node.base; |
| ... | @@ -1175,6 +1195,16 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1175,6 +1195,16 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1175 | const maybe_async = eatToken(it, .Keyword_async); | 1195 | const maybe_async = eatToken(it, .Keyword_async); |
| 1176 | if (maybe_async) |async_token| { | 1196 | if (maybe_async) |async_token| { |
| 1177 | const token_fn = eatToken(it, .Keyword_fn); | 1197 | const token_fn = eatToken(it, .Keyword_fn); |
| 1198 | if (token_fn != null) { | ||
| 1199 | // TODO: remove this hack when async fn rewriting is | ||
| 1200 | // HACK: If we see the keyword `fn`, then we assume that | ||
| 1201 | // we are parsing an async fn proto, and not a call. | ||
| 1202 | // We therefore put back all tokens consumed by the async | ||
| 1203 | // prefix... | ||
| 1204 | putBackToken(it, token_fn.?); | ||
| 1205 | putBackToken(it, async_token); | ||
| 1206 | return parsePrimaryTypeExpr(arena, it, tree); | ||
| 1207 | } | ||
| 1178 | var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, .{ | 1208 | var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, .{ |
| 1179 | .ExpectedPrimaryTypeExpr = .{ .token = it.index }, | 1209 | .ExpectedPrimaryTypeExpr = .{ .token = it.index }, |
| 1180 | }); | 1210 | }); |
lib/std/zig/parser_test.zig+24-18| ... | @@ -236,10 +236,10 @@ test "zig fmt: anon list literal syntax" { | ... | @@ -236,10 +236,10 @@ test "zig fmt: anon list literal syntax" { |
| 236 | test "zig fmt: async function" { | 236 | test "zig fmt: async function" { |
| 237 | try testCanonical( | 237 | try testCanonical( |
| 238 | \\pub const Server = struct { | 238 | \\pub const Server = struct { |
| 239 | \\ handleRequestFn: async fn (*Server, *const std.net.Address, File) void, | 239 | \\ handleRequestFn: fn (*Server, *const std.net.Address, File) callconv(.Async) void, |
| 240 | \\}; | 240 | \\}; |
| 241 | \\test "hi" { | 241 | \\test "hi" { |
| 242 | \\ var ptr = @ptrCast(async fn (i32) void, other); | 242 | \\ var ptr = @ptrCast(fn (i32) callconv(.Async) void, other); |
| 243 | \\} | 243 | \\} |
| 244 | \\ | 244 | \\ |
| 245 | ); | 245 | ); |
| ... | @@ -435,15 +435,6 @@ test "zig fmt: aligned struct field" { | ... | @@ -435,15 +435,6 @@ test "zig fmt: aligned struct field" { |
| 435 | ); | 435 | ); |
| 436 | } | 436 | } |
| 437 | 437 | ||
| 438 | test "zig fmt: preserve space between async fn definitions" { | ||
| 439 | try testCanonical( | ||
| 440 | \\async fn a() void {} | ||
| 441 | \\ | ||
| 442 | \\async fn b() void {} | ||
| 443 | \\ | ||
| 444 | ); | ||
| 445 | } | ||
| 446 | |||
| 447 | test "zig fmt: comment to disable/enable zig fmt first" { | 438 | test "zig fmt: comment to disable/enable zig fmt first" { |
| 448 | try testCanonical( | 439 | try testCanonical( |
| 449 | \\// Test trailing comma syntax | 440 | \\// Test trailing comma syntax |
| ... | @@ -1499,7 +1490,7 @@ test "zig fmt: line comments in struct initializer" { | ... | @@ -1499,7 +1490,7 @@ test "zig fmt: line comments in struct initializer" { |
| 1499 | 1490 | ||
| 1500 | test "zig fmt: first line comment in struct initializer" { | 1491 | test "zig fmt: first line comment in struct initializer" { |
| 1501 | try testCanonical( | 1492 | try testCanonical( |
| 1502 | \\pub async fn acquire(self: *Self) HeldLock { | 1493 | \\pub fn acquire(self: *Self) HeldLock { |
| 1503 | \\ return HeldLock{ | 1494 | \\ return HeldLock{ |
| 1504 | \\ // guaranteed allocation elision | 1495 | \\ // guaranteed allocation elision |
| 1505 | \\ .held = self.lock.acquire(), | 1496 | \\ .held = self.lock.acquire(), |
| ... | @@ -2461,8 +2452,7 @@ test "zig fmt: fn type" { | ... | @@ -2461,8 +2452,7 @@ test "zig fmt: fn type" { |
| 2461 | \\} | 2452 | \\} |
| 2462 | \\ | 2453 | \\ |
| 2463 | \\const a: fn (u8) u8 = undefined; | 2454 | \\const a: fn (u8) u8 = undefined; |
| 2464 | \\const b: extern fn (u8) u8 = undefined; | 2455 | \\const b: fn (u8) callconv(.Naked) u8 = undefined; |
| 2465 | \\const c: fn (u8) callconv(.Naked) u8 = undefined; | ||
| 2466 | \\const ap: fn (u8) u8 = a; | 2456 | \\const ap: fn (u8) u8 = a; |
| 2467 | \\ | 2457 | \\ |
| 2468 | ); | 2458 | ); |
| ... | @@ -2484,7 +2474,7 @@ test "zig fmt: inline asm" { | ... | @@ -2484,7 +2474,7 @@ test "zig fmt: inline asm" { |
| 2484 | 2474 | ||
| 2485 | test "zig fmt: async functions" { | 2475 | test "zig fmt: async functions" { |
| 2486 | try testCanonical( | 2476 | try testCanonical( |
| 2487 | \\async fn simpleAsyncFn() void { | 2477 | \\fn simpleAsyncFn() void { |
| 2488 | \\ const a = async a.b(); | 2478 | \\ const a = async a.b(); |
| 2489 | \\ x += 1; | 2479 | \\ x += 1; |
| 2490 | \\ suspend; | 2480 | \\ suspend; |
| ... | @@ -2920,6 +2910,25 @@ test "zig fmt: noasync to nosuspend" { | ... | @@ -2920,6 +2910,25 @@ test "zig fmt: noasync to nosuspend" { |
| 2920 | \\pub fn main() void { | 2910 | \\pub fn main() void { |
| 2921 | \\ nosuspend call(); | 2911 | \\ nosuspend call(); |
| 2922 | \\} | 2912 | \\} |
| 2913 | ); | ||
| 2914 | } | ||
| 2915 | |||
| 2916 | test "zig fmt: convert async fn into callconv(.Async)" { | ||
| 2917 | try testTransform( | ||
| 2918 | \\async fn foo() void {} | ||
| 2919 | , | ||
| 2920 | \\fn foo() callconv(.Async) void {} | ||
| 2921 | \\ | ||
| 2922 | ); | ||
| 2923 | } | ||
| 2924 | |||
| 2925 | test "zig fmt: convert extern fn proto into callconv(.C)" { | ||
| 2926 | try testTransform( | ||
| 2927 | \\extern fn foo0() void {} | ||
| 2928 | \\const foo1 = extern fn () void; | ||
| 2929 | , | ||
| 2930 | \\extern fn foo0() void {} | ||
| 2931 | \\const foo1 = fn () callconv(.C) void; | ||
| 2923 | \\ | 2932 | \\ |
| 2924 | ); | 2933 | ); |
| 2925 | } | 2934 | } |
| ... | @@ -2970,7 +2979,6 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b | ... | @@ -2970,7 +2979,6 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b |
| 2970 | anything_changed.* = try std.zig.render(allocator, buffer.outStream(), tree); | 2979 | anything_changed.* = try std.zig.render(allocator, buffer.outStream(), tree); |
| 2971 | return buffer.toOwnedSlice(); | 2980 | return buffer.toOwnedSlice(); |
| 2972 | } | 2981 | } |
| 2973 | |||
| 2974 | fn testTransform(source: []const u8, expected_source: []const u8) !void { | 2982 | fn testTransform(source: []const u8, expected_source: []const u8) !void { |
| 2975 | const needed_alloc_count = x: { | 2983 | const needed_alloc_count = x: { |
| 2976 | // Try it once with unlimited memory, make sure it works | 2984 | // Try it once with unlimited memory, make sure it works |
| ... | @@ -3018,11 +3026,9 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void { | ... | @@ -3018,11 +3026,9 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void { |
| 3018 | } | 3026 | } |
| 3019 | } | 3027 | } |
| 3020 | } | 3028 | } |
| 3021 | |||
| 3022 | fn testCanonical(source: []const u8) !void { | 3029 | fn testCanonical(source: []const u8) !void { |
| 3023 | return testTransform(source, source); | 3030 | return testTransform(source, source); |
| 3024 | } | 3031 | } |
| 3025 | |||
| 3026 | fn testError(source: []const u8) !void { | 3032 | fn testError(source: []const u8) !void { |
| 3027 | const tree = try std.zig.parse(std.testing.allocator, source); | 3033 | const tree = try std.zig.parse(std.testing.allocator, source); |
| 3028 | defer tree.deinit(); | 3034 | defer tree.deinit(); |
lib/std/zig/render.zig+6-1| ... | @@ -1414,7 +1414,8 @@ fn renderExpression( | ... | @@ -1414,7 +1414,8 @@ fn renderExpression( |
| 1414 | } | 1414 | } |
| 1415 | 1415 | ||
| 1416 | if (fn_proto.extern_export_inline_token) |extern_export_inline_token| { | 1416 | if (fn_proto.extern_export_inline_token) |extern_export_inline_token| { |
| 1417 | try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export | 1417 | if (!fn_proto.is_extern_prototype) |
| 1418 | try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export/inline | ||
| 1418 | } | 1419 | } |
| 1419 | 1420 | ||
| 1420 | if (fn_proto.lib_name) |lib_name| { | 1421 | if (fn_proto.lib_name) |lib_name| { |
| ... | @@ -1510,6 +1511,10 @@ fn renderExpression( | ... | @@ -1510,6 +1511,10 @@ fn renderExpression( |
| 1510 | try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // ( | 1511 | try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // ( |
| 1511 | try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None); | 1512 | try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None); |
| 1512 | try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // ) | 1513 | try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // ) |
| 1514 | } else if (fn_proto.is_extern_prototype) { | ||
| 1515 | try stream.writeAll("callconv(.C) "); | ||
| 1516 | } else if (fn_proto.is_async) { | ||
| 1517 | try stream.writeAll("callconv(.Async) "); | ||
| 1513 | } | 1518 | } |
| 1514 | 1519 | ||
| 1515 | switch (fn_proto.return_type) { | 1520 | switch (fn_proto.return_type) { |