authorgravatar for jhc@dismail.deJimmi Holst Christensen <jhc@dismail.de> 2018-04-07 01:38:38+02:00
committergravatar for jhc@dismail.deJimmi Holst Christensen <jhc@dismail.de> 2018-04-07 01:38:38+02:00
logbdff5bfa3e9f6ab490771b54109cb200b180b4da
tree9176bf8191165fe5af14c7d466934c1c5a1be3b5
parent820de1716b83ee99ed94461996ca592a302eccae

std.zig.parser now parses switch


3 files changed, 251 insertions(+), 36 deletions(-)

std/zig/ast.zig+21
......@@ -22,6 +22,7 @@ pub const Node = struct {
2222 Block,
2323 Switch,
2424 SwitchCase,
25 SwitchElse,
2526 InfixOp,
2627 PrefixOp,
2728 SuffixOp,
......@@ -59,6 +60,7 @@ pub const Node = struct {
5960 Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index),
6061 Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).iterate(index),
6162 Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).iterate(index),
63 Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).iterate(index),
6264 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index),
6365 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index),
6466 Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).iterate(index),
......@@ -97,6 +99,7 @@ pub const Node = struct {
9799 Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(),
98100 Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).firstToken(),
99101 Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).firstToken(),
102 Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).firstToken(),
100103 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).firstToken(),
101104 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).firstToken(),
102105 Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).firstToken(),
......@@ -135,6 +138,7 @@ pub const Node = struct {
135138 Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(),
136139 Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).lastToken(),
137140 Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).lastToken(),
141 Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).firstToken(),
138142 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).lastToken(),
139143 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).lastToken(),
140144 Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).lastToken(),
......@@ -606,6 +610,23 @@ pub const NodeSwitchCase = struct {
606610 }
607611};
608612
613pub const NodeSwitchElse = struct {
614 base: Node,
615 token: Token,
616
617 pub fn iterate(self: &NodeSwitchElse, index: usize) ?&Node {
618 return null;
619 }
620
621 pub fn firstToken(self: &NodeSwitchElse) Token {
622 return self.token;
623 }
624
625 pub fn lastToken(self: &NodeSwitchElse) Token {
626 return self.token;
627 }
628};
629
609630pub const NodeInfixOp = struct {
610631 base: Node,
611632 op_token: Token,
std/zig/parser.zig+224-36
......@@ -98,10 +98,15 @@ pub const Parser = struct {
9898 ptr: &?&ast.Node,
9999 };
100100
101 fn ListState(comptime T: type) type {
101 const ExprListCtx = struct {
102 list: &ArrayList(&ast.Node),
103 end: Token.Id,
104 ptr: &Token,
105 };
106
107 fn ListSave(comptime T: type) type {
102108 return struct {
103109 list: &ArrayList(T),
104 end: Token.Id,
105110 ptr: &Token,
106111 };
107112 }
......@@ -129,11 +134,16 @@ pub const Parser = struct {
129134 FnDef: &ast.NodeFnProto,
130135 Block: &ast.NodeBlock,
131136 Statement: &ast.NodeBlock,
132 ExprListItemOrEnd: ListState(&ast.Node),
133 ExprListCommaOrEnd: ListState(&ast.Node),
134 FieldInitListItemOrEnd: ListState(&ast.NodeFieldInitializer),
135 FieldInitListCommaOrEnd: ListState(&ast.NodeFieldInitializer),
137 ExprListItemOrEnd: ExprListCtx,
138 ExprListCommaOrEnd: ExprListCtx,
139 FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer),
140 FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer),
136141 FieldListCommaOrEnd: &ast.NodeContainerDecl,
142 SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase),
143 SwitchCaseCapture: &?ast.NodeSwitchCase.Capture,
144 SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase),
145 SwitchCaseItem: &ArrayList(&ast.Node),
146 SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
137147
138148 /// A state that can be appended before any other State. If an error occures,
139149 /// the parser will first try looking for the closest optional state. If an
......@@ -245,17 +255,8 @@ pub const Parser = struct {
245255 Token.Id.Keyword_test => {
246256 stack.append(State.TopLevel) catch unreachable;
247257
248 const name_token = self.getNextToken();
249 if (name_token.id != Token.Id.StringLiteral) {
250 try self.parseError(&stack, token, "expected {}, found {}", @tagName(Token.Id.StringLiteral), @tagName(name_token.id));
251 continue;
252 }
253
254 const lbrace = self.getNextToken();
255 if (lbrace.id != Token.Id.LBrace) {
256 try self.parseError(&stack, token, "expected {}, found {}", @tagName(Token.Id.LBrace), @tagName(name_token.id));
257 continue;
258 }
258 const name_token = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;
259 const lbrace = (try self.eatToken(&stack, Token.Id.LBrace)) ?? continue;
259260
260261 const name = try self.createStringLiteral(arena, name_token);
261262 const block = try self.createBlock(arena, (?Token)(null), token);
......@@ -974,9 +975,8 @@ pub const Parser = struct {
974975
975976 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
976977 try stack.append(State {
977 .FieldInitListItemOrEnd = ListState(&ast.NodeFieldInitializer) {
978 .FieldInitListItemOrEnd = ListSave(&ast.NodeFieldInitializer) {
978979 .list = &node.op.StructInitializer,
979 .end = Token.Id.RBrace,
980980 .ptr = &node.rtoken,
981981 }
982982 });
......@@ -992,7 +992,7 @@ pub const Parser = struct {
992992
993993 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
994994 try stack.append(State {
995 .ExprListItemOrEnd = ListState(&ast.Node) {
995 .ExprListItemOrEnd = ExprListCtx {
996996 .list = &node.op.ArrayInitializer,
997997 .end = Token.Id.RBrace,
998998 .ptr = &node.rtoken,
......@@ -1084,7 +1084,7 @@ pub const Parser = struct {
10841084
10851085 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
10861086 try stack.append(State {
1087 .ExprListItemOrEnd = ListState(&ast.Node) {
1087 .ExprListItemOrEnd = ExprListCtx {
10881088 .list = &node.op.Call.params,
10891089 .end = Token.Id.RParen,
10901090 .ptr = &node.rtoken,
......@@ -1238,7 +1238,7 @@ pub const Parser = struct {
12381238 };
12391239 dest_ptr.store(&node.base);
12401240 stack.append(State {
1241 .ExprListItemOrEnd = ListState(&ast.Node) {
1241 .ExprListItemOrEnd = ExprListCtx {
12421242 .list = &node.params,
12431243 .end = Token.Id.RParen,
12441244 .ptr = &node.rparen_token,
......@@ -1400,6 +1400,43 @@ pub const Parser = struct {
14001400 Token.Id.Keyword_asm => {
14011401 @panic("TODO: inline asm");
14021402 },
1403 Token.Id.Keyword_if => {
1404 @panic("TODO: inline if");
1405 },
1406 Token.Id.Keyword_while => {
1407 @panic("TODO: inline while");
1408 },
1409 Token.Id.Keyword_for => {
1410 @panic("TODO: inline for");
1411 },
1412 Token.Id.Keyword_switch => {
1413 const node = try arena.create(ast.NodeSwitch);
1414 *node = ast.NodeSwitch {
1415 .base = self.initNode(ast.Node.Id.Switch),
1416 .switch_token = token,
1417 .expr = undefined,
1418 .cases = ArrayList(&ast.NodeSwitchCase).init(arena),
1419 .rbrace = undefined,
1420 };
1421 dest_ptr.store(&node.base);
1422
1423 stack.append(State {
1424 .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) {
1425 .list = &node.cases,
1426 .ptr = &node.rbrace,
1427 },
1428 }) catch unreachable;
1429 try stack.append(State { .ExpectToken = Token.Id.LBrace });
1430 try stack.append(State { .ExpectToken = Token.Id.RParen });
1431 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
1432 try stack.append(State { .ExpectToken = Token.Id.LParen });
1433 },
1434 Token.Id.Keyword_comptime => {
1435 @panic("TODO: inline comptime");
1436 },
1437 Token.Id.Keyword_suspend => {
1438 @panic("TODO: inline suspend");
1439 },
14031440 else => {
14041441 try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id));
14051442 continue;
......@@ -1463,8 +1500,7 @@ pub const Parser = struct {
14631500 State.FieldInitListItemOrEnd => |list_state| {
14641501 var token = self.getNextToken();
14651502
1466 const IdTag = @TagType(Token.Id);
1467 if (IdTag(list_state.end) == token.id){
1503 if (token.id == Token.Id.RBrace){
14681504 *list_state.ptr = token;
14691505 continue;
14701506 }
......@@ -1497,13 +1533,82 @@ pub const Parser = struct {
14971533 });
14981534 },
14991535
1536 State.SwitchCaseOrEnd => |list_state| {
1537 var token = self.getNextToken();
1538
1539 if (token.id == Token.Id.RBrace){
1540 *list_state.ptr = token;
1541 continue;
1542 }
1543
1544 self.putBackToken(token);
1545
1546 const node = try arena.create(ast.NodeSwitchCase);
1547 *node = ast.NodeSwitchCase {
1548 .base = self.initNode(ast.Node.Id.SwitchCase),
1549 .items = ArrayList(&ast.Node).init(arena),
1550 .capture = null,
1551 .expr = undefined,
1552 };
1553 try list_state.list.append(node);
1554 stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;
1555 try stack.append(State { .Expression = DestPtr{ .Field = &node.expr } });
1556 try stack.append(State { .SwitchCaseCapture = &node.capture });
1557
1558 const maybe_else = self.getNextToken();
1559 if (maybe_else.id == Token.Id.Keyword_else) {
1560 const else_node = try arena.create(ast.NodeSwitchElse);
1561 *else_node = ast.NodeSwitchElse {
1562 .base = self.initNode(ast.Node.Id.SwitchElse),
1563 .token = maybe_else,
1564 };
1565 try node.items.append(&else_node.base);
1566 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1567 continue;
1568 } else {
1569 self.putBackToken(maybe_else);
1570 try stack.append(State { .SwitchCaseItem = &node.items });
1571 continue;
1572 }
1573 },
1574
1575 State.SwitchCaseCapture => |capture| {
1576 const token = self.getNextToken();
1577 if (token.id != Token.Id.Pipe) {
1578 self.putBackToken(token);
1579 continue;
1580 }
1581
1582 const is_ptr = blk: {
1583 const asterik = self.getNextToken();
1584 if (asterik.id == Token.Id.Asterisk) {
1585 break :blk true;
1586 } else {
1587 self.putBackToken(asterik);
1588 break :blk false;
1589 }
1590 };
1591
1592 const ident = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
1593 _ = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;
1594 *capture = ast.NodeSwitchCase.Capture {
1595 .symbol = try self.createIdentifier(arena, ident),
1596 .is_ptr = is_ptr
1597 };
1598 },
1599
1600 State.SwitchCaseItem => |case_items| {
1601 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1602 try stack.append(State { .RangeExpressionBegin = DestPtr{ .Field = try case_items.addOne() } });
1603 },
1604
15001605 State.ExprListCommaOrEnd => |list_state| {
15011606 try self.commaOrEnd(&stack, list_state.end, list_state.ptr, State { .ExprListItemOrEnd = list_state });
15021607 continue;
15031608 },
15041609
15051610 State.FieldInitListCommaOrEnd => |list_state| {
1506 try self.commaOrEnd(&stack, list_state.end, list_state.ptr, State { .FieldInitListItemOrEnd = list_state });
1611 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .FieldInitListItemOrEnd = list_state });
15071612 continue;
15081613 },
15091614
......@@ -1513,6 +1618,16 @@ pub const Parser = struct {
15131618 continue;
15141619 },
15151620
1621 State.SwitchCaseCommaOrEnd => |list_state| {
1622 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .SwitchCaseOrEnd = list_state });
1623 continue;
1624 },
1625
1626 State.SwitchCaseItemCommaOrEnd => |case_items| {
1627 try self.commaOrEnd(&stack, Token.Id.EqualAngleBracketRight, null, State { .SwitchCaseItem = case_items });
1628 continue;
1629 },
1630
15161631 State.AddrOfModifiers => |addr_of_info| {
15171632 var token = self.getNextToken();
15181633 switch (token.id) {
......@@ -1741,6 +1856,11 @@ pub const Parser = struct {
17411856 stack.append(State { .Block = inner_block }) catch unreachable;
17421857 continue;
17431858 },
1859 Token.Id.Keyword_switch => {
1860 self.putBackToken(next);
1861 stack.append(State { .Expression = DestPtr{.Field = try block.statements.addOne() } }) catch unreachable;
1862 continue;
1863 },
17441864 else => {
17451865 self.putBackToken(next);
17461866 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
......@@ -1754,7 +1874,7 @@ pub const Parser = struct {
17541874 }
17551875 }
17561876
1757 fn commaOrEnd(self: &Parser, stack: &ArrayList(State), end: &const Token.Id, ptr: &Token, state_after_comma: &const State) !void {
1877 fn commaOrEnd(self: &Parser, stack: &ArrayList(State), end: &const Token.Id, maybe_ptr: ?&Token, state_after_comma: &const State) !void {
17581878 var token = self.getNextToken();
17591879 switch (token.id) {
17601880 Token.Id.Comma => {
......@@ -1763,7 +1883,9 @@ pub const Parser = struct {
17631883 else => {
17641884 const IdTag = @TagType(Token.Id);
17651885 if (IdTag(*end) == token.id) {
1766 *ptr = token;
1886 if (maybe_ptr) |ptr| {
1887 *ptr = token;
1888 }
17671889 return;
17681890 }
17691891
......@@ -2498,7 +2620,8 @@ pub const Parser = struct {
24982620 ast.NodeInfixOp.InfixOp.Sub => " - ",
24992621 ast.NodeInfixOp.InfixOp.SubWrap => " -% ",
25002622 ast.NodeInfixOp.InfixOp.UnwrapMaybe => " ?? ",
2501 else => unreachable,
2623 ast.NodeInfixOp.InfixOp.Range => " ... ",
2624 ast.NodeInfixOp.InfixOp.Catch => unreachable,
25022625 };
25032626
25042627 try stack.append(RenderState { .Text = text });
......@@ -2821,8 +2944,73 @@ pub const Parser = struct {
28212944 },
28222945 ast.Node.Id.FnProto => @panic("TODO fn proto in an expression"),
28232946 ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),
2824 ast.Node.Id.Switch => @panic("TODO switch"),
2825 ast.Node.Id.SwitchCase => @panic("TODO switch case"),
2947 ast.Node.Id.Switch => {
2948 const switch_node = @fieldParentPtr(ast.NodeSwitch, "base", base);
2949 try stream.print("{} (", self.tokenizer.getTokenSlice(switch_node.switch_token));
2950
2951 try stack.append(RenderState { .Text = "}"});
2952 try stack.append(RenderState.PrintIndent);
2953 try stack.append(RenderState { .Indent = indent });
2954 try stack.append(RenderState { .Text = "\n"});
2955
2956 const cases = switch_node.cases.toSliceConst();
2957 var i = cases.len;
2958 while (i != 0) {
2959 i -= 1;
2960 const node = cases[i];
2961 try stack.append(RenderState { .Expression = &node.base});
2962 try stack.append(RenderState.PrintIndent);
2963 try stack.append(RenderState {
2964 .Text = blk: {
2965 if (i != 0) {
2966 const prev_node = cases[i - 1];
2967 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
2968 if (loc.line >= 2) {
2969 break :blk "\n\n";
2970 }
2971 }
2972 break :blk "\n";
2973 },
2974 });
2975
2976 if (i != 0) {
2977 try stack.append(RenderState { .Text = "," });
2978 }
2979 }
2980 try stack.append(RenderState { .Indent = indent + indent_delta});
2981 try stack.append(RenderState { .Text = ") {"});
2982 try stack.append(RenderState { .Expression = switch_node.expr });
2983 },
2984 ast.Node.Id.SwitchCase => {
2985 const switch_case = @fieldParentPtr(ast.NodeSwitchCase, "base", base);
2986
2987 try stack.append(RenderState { .Expression = switch_case.expr });
2988 if (switch_case.capture) |capture| {
2989 try stack.append(RenderState { .Text = "| "});
2990 try stack.append(RenderState { .Expression = &capture.symbol.base });
2991
2992 if (capture.is_ptr) {
2993 try stack.append(RenderState { .Text = "*"});
2994 }
2995 try stack.append(RenderState { .Text = "|"});
2996 }
2997 try stack.append(RenderState { .Text = " => "});
2998
2999 const items = switch_case.items.toSliceConst();
3000 var i = items.len;
3001 while (i != 0) {
3002 i -= 1;
3003 try stack.append(RenderState { .Expression = items[i] });
3004
3005 if (i != 0) {
3006 try stack.append(RenderState { .Text = ", " });
3007 }
3008 }
3009 },
3010 ast.Node.Id.SwitchElse => {
3011 const switch_else = @fieldParentPtr(ast.NodeSwitchElse, "base", base);
3012 try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token));
3013 },
28263014
28273015 ast.Node.Id.StructField,
28283016 ast.Node.Id.UnionTag,
......@@ -2867,7 +3055,7 @@ pub const Parser = struct {
28673055 const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", base);
28683056 try stack.append(RenderState { .VarDecl = var_decl});
28693057 },
2870 ast.Node.Id.Block => {
3058 ast.Node.Id.Block, ast.Node.Id.Switch => {
28713059 try stack.append(RenderState { .Expression = base});
28723060 },
28733061 else => {
......@@ -3436,24 +3624,24 @@ test "zig fmt: switch" {
34363624 \\ else => {
34373625 \\ const a = 1;
34383626 \\ const b = a;
3439 \\ },
3627 \\ }
34403628 \\ }
34413629 \\
34423630 \\ const res = switch (0) {
34433631 \\ 0 => 0,
34443632 \\ 1 => 2,
3445 \\ else => 4,
3633 \\ else => 4
34463634 \\ };
34473635 \\
34483636 \\ const Union = union(enum) {
34493637 \\ Int: i64,
3450 \\ Float: f64,
3638 \\ Float: f64
34513639 \\ };
34523640 \\
3453 \\ const u = Union { .Int = 0 };
3641 \\ const u = Union{ .Int = 0 };
34543642 \\ switch (u) {
34553643 \\ Union.Int => |int| {},
3456 \\ Union.Float => |*float| unreachable,
3644 \\ Union.Float => |*float| unreachable
34573645 \\ }
34583646 \\}
34593647 \\
std/zig/tokenizer.zig+6
......@@ -86,6 +86,7 @@ pub const Token = struct {
8686 PipeEqual,
8787 Equal,
8888 EqualEqual,
89 EqualAngleBracketRight,
8990 BangEqual,
9091 LParen,
9192 RParen,
......@@ -688,6 +689,11 @@ pub const Tokenizer = struct {
688689 self.index += 1;
689690 break;
690691 },
692 '>' => {
693 result.id = Token.Id.EqualAngleBracketRight;
694 self.index += 1;
695 break;
696 },
691697 else => {
692698 result.id = Token.Id.Equal;
693699 break;