authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-14 15:48:15-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-14 15:50:40-05:00
log629f134d3805f99938f59a6ee7f6598591abc9d7
tree4d09da57fc0119e240343c32d3fce81fbbb9c874
parente8d81c5acf69245f863394f207d63bf07c722bf4

std.zig.parser understands inferred return type and error inference


2 files changed, 83 insertions(+), 18 deletions(-)

std/zig/ast.zig+19-3
......@@ -102,7 +102,7 @@ pub const NodeFnProto = struct {
102102 fn_token: Token,
103103 name_token: ?Token,
104104 params: ArrayList(&Node),
105 return_type: &Node,
105 return_type: ReturnType,
106106 var_args_token: ?Token,
107107 extern_token: ?Token,
108108 inline_token: ?Token,
......@@ -111,6 +111,12 @@ pub const NodeFnProto = struct {
111111 lib_name: ?&Node, // populated if this is an extern declaration
112112 align_expr: ?&Node, // populated if align(A) is present
113113
114 pub const ReturnType = union(enum) {
115 Explicit: &Node,
116 Infer,
117 InferErrorSet: &Node,
118 };
119
114120 pub fn iterate(self: &NodeFnProto, index: usize) ?&Node {
115121 var i = index;
116122
......@@ -119,8 +125,18 @@ pub const NodeFnProto = struct {
119125 i -= 1;
120126 }
121127
122 if (i < 1) return self.return_type;
123 i -= 1;
128 switch (self.return_type) {
129 // TODO allow this and next prong to share bodies since the types are the same
130 ReturnType.Explicit => |node| {
131 if (i < 1) return node;
132 i -= 1;
133 },
134 ReturnType.InferErrorSet => |node| {
135 if (i < 1) return node;
136 i -= 1;
137 },
138 ReturnType.Infer => {},
139 }
124140
125141 if (self.align_expr) |align_expr| {
126142 if (i < 1) return align_expr;
std/zig/parser.zig+64-15
......@@ -87,6 +87,7 @@ pub const Parser = struct {
8787 ExpectToken: @TagType(Token.Id),
8888 FnProto: &ast.NodeFnProto,
8989 FnProtoAlign: &ast.NodeFnProto,
90 FnProtoReturnType: &ast.NodeFnProto,
9091 ParamDecl: &ast.NodeFnProto,
9192 ParamDeclComma,
9293 FnDef: &ast.NodeFnProto,
......@@ -178,7 +179,7 @@ pub const Parser = struct {
178179 stack.append(State.TopLevel) catch unreachable;
179180 // TODO shouldn't need these casts
180181 const fn_proto = try self.createAttachFnProto(arena, &root_node.decls, token,
181 ctx.extern_token, (?Token)(null), (?Token)(null), (?Token)(null));
182 ctx.extern_token, (?Token)(null), ctx.visib_token, (?Token)(null));
182183 try stack.append(State { .FnDef = fn_proto });
183184 try stack.append(State { .FnProto = fn_proto });
184185 continue;
......@@ -466,11 +467,37 @@ pub const Parser = struct {
466467 }
467468 self.putBackToken(token);
468469 stack.append(State {
469 .TypeExpr = DestPtr {.Field = &fn_proto.return_type},
470 .FnProtoReturnType = fn_proto,
470471 }) catch unreachable;
471472 continue;
472473 },
473474
475 State.FnProtoReturnType => |fn_proto| {
476 const token = self.getNextToken();
477 switch (token.id) {
478 Token.Id.Keyword_var => {
479 fn_proto.return_type = ast.NodeFnProto.ReturnType.Infer;
480 },
481 Token.Id.Bang => {
482 fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined };
483 stack.append(State {
484 .TypeExpr = DestPtr {.Field = &fn_proto.return_type.InferErrorSet},
485 }) catch unreachable;
486 },
487 else => {
488 self.putBackToken(token);
489 fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };
490 stack.append(State {
491 .TypeExpr = DestPtr {.Field = &fn_proto.return_type.Explicit},
492 }) catch unreachable;
493 },
494 }
495 if (token.id == Token.Id.Keyword_align) {
496 @panic("TODO fn proto align");
497 }
498 continue;
499 },
500
474501 State.ParamDecl => |fn_proto| {
475502 var token = self.getNextToken();
476503 if (token.id == Token.Id.RParen) {
......@@ -977,19 +1004,23 @@ pub const Parser = struct {
9771004 },
9781005 ast.Node.Id.Block => {
9791006 const block = @fieldParentPtr(ast.NodeBlock, "base", base);
980 try stream.write("{");
981 try stack.append(RenderState { .Text = "}"});
982 try stack.append(RenderState.PrintIndent);
983 try stack.append(RenderState { .Indent = indent});
984 try stack.append(RenderState { .Text = "\n"});
985 var i = block.statements.len;
986 while (i != 0) {
987 i -= 1;
988 const statement_node = block.statements.items[i];
989 try stack.append(RenderState { .Statement = statement_node});
1007 if (block.statements.len == 0) {
1008 try stream.write("{}");
1009 } else {
1010 try stream.write("{");
1011 try stack.append(RenderState { .Text = "}"});
9901012 try stack.append(RenderState.PrintIndent);
991 try stack.append(RenderState { .Indent = indent + indent_delta});
992 try stack.append(RenderState { .Text = "\n" });
1013 try stack.append(RenderState { .Indent = indent});
1014 try stack.append(RenderState { .Text = "\n"});
1015 var i = block.statements.len;
1016 while (i != 0) {
1017 i -= 1;
1018 const statement_node = block.statements.items[i];
1019 try stack.append(RenderState { .Statement = statement_node});
1020 try stack.append(RenderState.PrintIndent);
1021 try stack.append(RenderState { .Indent = indent + indent_delta});
1022 try stack.append(RenderState { .Text = "\n" });
1023 }
9931024 }
9941025 },
9951026 ast.Node.Id.InfixOp => {
......@@ -1071,7 +1102,18 @@ pub const Parser = struct {
10711102 try stack.append(RenderState { .Expression = body_node});
10721103 try stack.append(RenderState { .Text = " "});
10731104 }
1074 try stack.append(RenderState { .Expression = fn_proto.return_type});
1105 switch (fn_proto.return_type) {
1106 ast.NodeFnProto.ReturnType.Explicit => |node| {
1107 try stack.append(RenderState { .Expression = node});
1108 },
1109 ast.NodeFnProto.ReturnType.Infer => {
1110 try stream.print("var");
1111 },
1112 ast.NodeFnProto.ReturnType.InferErrorSet => |node| {
1113 try stream.print("!");
1114 try stack.append(RenderState { .Expression = node});
1115 },
1116 }
10751117 },
10761118 RenderState.Statement => |base| {
10771119 switch (base.id) {
......@@ -1169,6 +1211,13 @@ fn testCanonical(source: []const u8) !void {
11691211}
11701212
11711213test "zig fmt" {
1214 try testCanonical(
1215 \\pub fn main() !void {}
1216 \\pub fn main() var {}
1217 \\pub fn main() i32 {}
1218 \\
1219 );
1220
11721221 try testCanonical(
11731222 \\const std = @import("std");
11741223 \\const std = @import();