authorgravatar for me@tadeo.caTadeo Kondrak <me@tadeo.ca> 2020-05-04 09:24:46-06:00
committergravatar for me@tadeo.caTadeo Kondrak <me@tadeo.ca> 2020-05-05 09:37:59-06:00
logd0e996405bff4352c78c570b4944b369d642d058
treed2b43b7fe6889a77a1c15e2e43bf4be1f8dc0e53
parent7ada59f873738931b4d162372dff0a33442112b6
signature Commit is signed but in an unrecognized format.

add zig fmt fix for async/extern fn


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 present880 align_expr: ?*Node, // populated if align(A) is present
881 section_expr: ?*Node, // populated if linksection(A) is present881 section_expr: ?*Node, // populated if linksection(A) is present
882 callconv_expr: ?*Node, // populated if callconv(A) is present882 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
883885
884 pub const ParamList = SegmentedList(*Node, 2);886 pub const ParamList = SegmentedList(*Node, 2);
885887
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
337337
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)
339fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {339fn 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 };
385405
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" {
236test "zig fmt: async function" {236test "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}
437437
438test "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
447test "zig fmt: comment to disable/enable zig fmt first" {438test "zig fmt: comment to disable/enable zig fmt first" {
448 try testCanonical(439 try testCanonical(
449 \\// Test trailing comma syntax440 \\// 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" {
14991490
1500test "zig fmt: first line comment in struct initializer" {1491test "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 elision1495 \\ // 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" {
24842474
2485test "zig fmt: async functions" {2475test "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
2916test "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
2925test "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
2974fn testTransform(source: []const u8, expected_source: []const u8) !void {2982fn 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 works2984 // 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
3022fn testCanonical(source: []const u8) !void {3029fn testCanonical(source: []const u8) !void {
3023 return testTransform(source, source);3030 return testTransform(source, source);
3024}3031}
3025
3026fn testError(source: []const u8) !void {3032fn 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 }
14151415
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/export1417 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 }
14191420
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 }
15141519
1515 switch (fn_proto.return_type) {1520 switch (fn_proto.return_type) {