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 {...@@ -102,7 +102,7 @@ pub const NodeFnProto = struct {
102 fn_token: Token,102 fn_token: Token,
103 name_token: ?Token,103 name_token: ?Token,
104 params: ArrayList(&Node),104 params: ArrayList(&Node),
105 return_type: &Node,105 return_type: ReturnType,
106 var_args_token: ?Token,106 var_args_token: ?Token,
107 extern_token: ?Token,107 extern_token: ?Token,
108 inline_token: ?Token,108 inline_token: ?Token,
...@@ -111,6 +111,12 @@ pub const NodeFnProto = struct {...@@ -111,6 +111,12 @@ pub const NodeFnProto = struct {
111 lib_name: ?&Node, // populated if this is an extern declaration111 lib_name: ?&Node, // populated if this is an extern declaration
112 align_expr: ?&Node, // populated if align(A) is present112 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
114 pub fn iterate(self: &NodeFnProto, index: usize) ?&Node {120 pub fn iterate(self: &NodeFnProto, index: usize) ?&Node {
115 var i = index;121 var i = index;
116122
...@@ -119,8 +125,18 @@ pub const NodeFnProto = struct {...@@ -119,8 +125,18 @@ pub const NodeFnProto = struct {
119 i -= 1;125 i -= 1;
120 }126 }
121127
122 if (i < 1) return self.return_type;128 switch (self.return_type) {
123 i -= 1;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
125 if (self.align_expr) |align_expr| {141 if (self.align_expr) |align_expr| {
126 if (i < 1) return align_expr;142 if (i < 1) return align_expr;
std/zig/parser.zig+64-15
...@@ -87,6 +87,7 @@ pub const Parser = struct {...@@ -87,6 +87,7 @@ pub const Parser = struct {
87 ExpectToken: @TagType(Token.Id),87 ExpectToken: @TagType(Token.Id),
88 FnProto: &ast.NodeFnProto,88 FnProto: &ast.NodeFnProto,
89 FnProtoAlign: &ast.NodeFnProto,89 FnProtoAlign: &ast.NodeFnProto,
90 FnProtoReturnType: &ast.NodeFnProto,
90 ParamDecl: &ast.NodeFnProto,91 ParamDecl: &ast.NodeFnProto,
91 ParamDeclComma,92 ParamDeclComma,
92 FnDef: &ast.NodeFnProto,93 FnDef: &ast.NodeFnProto,
...@@ -178,7 +179,7 @@ pub const Parser = struct {...@@ -178,7 +179,7 @@ pub const Parser = struct {
178 stack.append(State.TopLevel) catch unreachable;179 stack.append(State.TopLevel) catch unreachable;
179 // TODO shouldn't need these casts180 // TODO shouldn't need these casts
180 const fn_proto = try self.createAttachFnProto(arena, &root_node.decls, token,181 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));
182 try stack.append(State { .FnDef = fn_proto });183 try stack.append(State { .FnDef = fn_proto });
183 try stack.append(State { .FnProto = fn_proto });184 try stack.append(State { .FnProto = fn_proto });
184 continue;185 continue;
...@@ -466,11 +467,37 @@ pub const Parser = struct {...@@ -466,11 +467,37 @@ pub const Parser = struct {
466 }467 }
467 self.putBackToken(token);468 self.putBackToken(token);
468 stack.append(State {469 stack.append(State {
469 .TypeExpr = DestPtr {.Field = &fn_proto.return_type},470 .FnProtoReturnType = fn_proto,
470 }) catch unreachable;471 }) catch unreachable;
471 continue;472 continue;
472 },473 },
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
474 State.ParamDecl => |fn_proto| {501 State.ParamDecl => |fn_proto| {
475 var token = self.getNextToken();502 var token = self.getNextToken();
476 if (token.id == Token.Id.RParen) {503 if (token.id == Token.Id.RParen) {
...@@ -977,19 +1004,23 @@ pub const Parser = struct {...@@ -977,19 +1004,23 @@ pub const Parser = struct {
977 },1004 },
978 ast.Node.Id.Block => {1005 ast.Node.Id.Block => {
979 const block = @fieldParentPtr(ast.NodeBlock, "base", base);1006 const block = @fieldParentPtr(ast.NodeBlock, "base", base);
980 try stream.write("{");1007 if (block.statements.len == 0) {
981 try stack.append(RenderState { .Text = "}"});1008 try stream.write("{}");
982 try stack.append(RenderState.PrintIndent);1009 } else {
983 try stack.append(RenderState { .Indent = indent});1010 try stream.write("{");
984 try stack.append(RenderState { .Text = "\n"});1011 try stack.append(RenderState { .Text = "}"});
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});
990 try stack.append(RenderState.PrintIndent);1012 try stack.append(RenderState.PrintIndent);
991 try stack.append(RenderState { .Indent = indent + indent_delta});1013 try stack.append(RenderState { .Indent = indent});
992 try stack.append(RenderState { .Text = "\n" });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 }
993 }1024 }
994 },1025 },
995 ast.Node.Id.InfixOp => {1026 ast.Node.Id.InfixOp => {
...@@ -1071,7 +1102,18 @@ pub const Parser = struct {...@@ -1071,7 +1102,18 @@ pub const Parser = struct {
1071 try stack.append(RenderState { .Expression = body_node});1102 try stack.append(RenderState { .Expression = body_node});
1072 try stack.append(RenderState { .Text = " "});1103 try stack.append(RenderState { .Text = " "});
1073 }1104 }
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 }
1075 },1117 },
1076 RenderState.Statement => |base| {1118 RenderState.Statement => |base| {
1077 switch (base.id) {1119 switch (base.id) {
...@@ -1169,6 +1211,13 @@ fn testCanonical(source: []const u8) !void {...@@ -1169,6 +1211,13 @@ fn testCanonical(source: []const u8) !void {
1169}1211}
11701212
1171test "zig fmt" {1213test "zig fmt" {
1214 try testCanonical(
1215 \\pub fn main() !void {}
1216 \\pub fn main() var {}
1217 \\pub fn main() i32 {}
1218 \\
1219 );
1220
1172 try testCanonical(1221 try testCanonical(
1173 \\const std = @import("std");1222 \\const std = @import("std");
1174 \\const std = @import();1223 \\const std = @import();