| ... | ... | @@ -59,6 +59,11 @@ pub const Parser = struct { |
| 59 | 59 | lib_name: ?&ast.Node, |
| 60 | 60 | }; |
| 61 | 61 | |
| 62 | const ContainerExternCtx = struct { |
| 63 | ltoken: Token, |
| 64 | layout: ast.NodeContainerDecl.Layout, |
| 65 | }; |
| 66 | |
| 62 | 67 | const DestPtr = union(enum) { |
| 63 | 68 | Field: &&ast.Node, |
| 64 | 69 | NullableField: &?&ast.Node, |
| ... | ... | @@ -90,6 +95,7 @@ pub const Parser = struct { |
| 90 | 95 | TopLevel, |
| 91 | 96 | TopLevelExtern: TopLevelDeclCtx, |
| 92 | 97 | TopLevelDecl: TopLevelDeclCtx, |
| 98 | ContainerExtern: ContainerExternCtx, |
| 93 | 99 | ContainerDecl: &ast.NodeContainerDecl, |
| 94 | 100 | Expression: DestPtr, |
| 95 | 101 | ExpectOperand, |
| ... | ... | @@ -338,6 +344,63 @@ pub const Parser = struct { |
| 338 | 344 | return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id)); |
| 339 | 345 | }, |
| 340 | 346 | |
| 347 | State.ContainerExtern => |ctx| { |
| 348 | const token = self.getNextToken(); |
| 349 | |
| 350 | const node = try arena.create(ast.NodeContainerDecl); |
| 351 | *node = ast.NodeContainerDecl { |
| 352 | .base = self.initNode(ast.Node.Id.ContainerDecl), |
| 353 | .ltoken = ctx.ltoken, |
| 354 | .layout = ctx.layout, |
| 355 | .kind = switch (token.id) { |
| 356 | Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct, |
| 357 | Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union, |
| 358 | Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum, |
| 359 | else => { |
| 360 | return self.parseError(token, "expected {}, {} or {}, found {}", |
| 361 | @tagName(Token.Id.Keyword_struct), |
| 362 | @tagName(Token.Id.Keyword_union), |
| 363 | @tagName(Token.Id.Keyword_enum), |
| 364 | @tagName(token.id)); |
| 365 | }, |
| 366 | }, |
| 367 | .init_arg_expr = undefined, |
| 368 | .fields_and_decls = ArrayList(&ast.Node).init(arena), |
| 369 | .rbrace_token = undefined, |
| 370 | }; |
| 371 | |
| 372 | try stack.append(State { .Operand = &node.base }); |
| 373 | try stack.append(State.AfterOperand); |
| 374 | try stack.append(State { .ContainerDecl = node }); |
| 375 | try stack.append(State { .ExpectToken = Token.Id.LBrace }); |
| 376 | |
| 377 | const lparen = self.getNextToken(); |
| 378 | if (lparen.id != Token.Id.LParen) { |
| 379 | self.putBackToken(lparen); |
| 380 | node.init_arg_expr = ast.NodeContainerDecl.InitArg.None; |
| 381 | continue; |
| 382 | } |
| 383 | |
| 384 | try stack.append(State { .ExpectToken = Token.Id.RParen }); |
| 385 | |
| 386 | const init_arg_token = self.getNextToken(); |
| 387 | switch (init_arg_token.id) { |
| 388 | Token.Id.Keyword_enum => { |
| 389 | node.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum; |
| 390 | }, |
| 391 | else => { |
| 392 | self.putBackToken(init_arg_token); |
| 393 | node.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined }; |
| 394 | try stack.append(State { |
| 395 | .Expression = DestPtr { |
| 396 | .Field = &node.init_arg_expr.Type |
| 397 | } |
| 398 | }); |
| 399 | }, |
| 400 | } |
| 401 | continue; |
| 402 | }, |
| 403 | |
| 341 | 404 | State.ContainerDecl => |container_decl| { |
| 342 | 405 | const token = self.getNextToken(); |
| 343 | 406 | |
| ... | ... | @@ -633,52 +696,30 @@ pub const Parser = struct { |
| 633 | 696 | try stack.append(State.AfterOperand); |
| 634 | 697 | continue; |
| 635 | 698 | }, |
| 636 | | Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => { |
| 637 | | const node = try arena.create(ast.NodeContainerDecl); |
| 638 | | *node = ast.NodeContainerDecl { |
| 639 | | .base = self.initNode(ast.Node.Id.ContainerDecl), |
| 640 | | .kind_token = token, |
| 641 | | .kind = switch (token.id) { |
| 642 | | Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct, |
| 643 | | Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union, |
| 644 | | Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum, |
| 645 | | else => unreachable, |
| 699 | Token.Id.Keyword_packed => { |
| 700 | try stack.append(State { |
| 701 | .ContainerExtern = ContainerExternCtx { |
| 702 | .ltoken = token, |
| 703 | .layout = ast.NodeContainerDecl.Layout.Packed, |
| 646 | 704 | }, |
| 647 | | .init_arg_expr = undefined, |
| 648 | | .fields_and_decls = ArrayList(&ast.Node).init(arena), |
| 649 | | .rbrace_token = undefined, |
| 650 | | }; |
| 651 | | |
| 652 | | try stack.append(State { .Operand = &node.base }); |
| 653 | | try stack.append(State.AfterOperand); |
| 654 | | try stack.append(State { .ContainerDecl = node }); |
| 655 | | try stack.append(State { .ExpectToken = Token.Id.LBrace }); |
| 656 | | |
| 657 | | const lparen = self.getNextToken(); |
| 658 | | if (lparen.id != Token.Id.LParen) { |
| 659 | | self.putBackToken(lparen); |
| 660 | | node.init_arg_expr = ast.NodeContainerDecl.InitArg.None; |
| 661 | | continue; |
| 662 | | } |
| 663 | | |
| 664 | | try stack.append(State { .ExpectToken = Token.Id.RParen }); |
| 665 | | |
| 666 | | const init_arg_token = self.getNextToken(); |
| 667 | | switch (init_arg_token.id) { |
| 668 | | Token.Id.Keyword_enum => { |
| 669 | | node.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum; |
| 705 | }); |
| 706 | }, |
| 707 | Token.Id.Keyword_extern => { |
| 708 | try stack.append(State { |
| 709 | .ContainerExtern = ContainerExternCtx { |
| 710 | .ltoken = token, |
| 711 | .layout = ast.NodeContainerDecl.Layout.Extern, |
| 670 | 712 | }, |
| 671 | | else => { |
| 672 | | self.putBackToken(lparen); |
| 673 | | node.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined }; |
| 674 | | try stack.append(State { |
| 675 | | .Expression = DestPtr { |
| 676 | | .Field = &node.init_arg_expr.Type |
| 677 | | } |
| 678 | | }); |
| 713 | }); |
| 714 | }, |
| 715 | Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => { |
| 716 | self.putBackToken(token); |
| 717 | try stack.append(State { |
| 718 | .ContainerExtern = ContainerExternCtx { |
| 719 | .ltoken = token, |
| 720 | .layout = ast.NodeContainerDecl.Layout.Auto, |
| 679 | 721 | }, |
| 680 | | } |
| 681 | | continue; |
| 722 | }); |
| 682 | 723 | }, |
| 683 | 724 | Token.Id.Builtin => { |
| 684 | 725 | const node = try arena.create(ast.NodeBuiltinCall); |
| ... | ... | @@ -1706,6 +1747,29 @@ pub const Parser = struct { |
| 1706 | 1747 | try stack.append(RenderState { .Text = " " }); |
| 1707 | 1748 | try stack.append(RenderState { .Expression = test_decl.name }); |
| 1708 | 1749 | }, |
| 1750 | ast.Node.Id.StructField => { |
| 1751 | const field = @fieldParentPtr(ast.NodeStructField, "base", decl); |
| 1752 | try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token)); |
| 1753 | try stack.append(RenderState { .Expression = field.type_expr}); |
| 1754 | }, |
| 1755 | ast.Node.Id.UnionTag => { |
| 1756 | const tag = @fieldParentPtr(ast.NodeUnionTag, "base", decl); |
| 1757 | try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token)); |
| 1758 | |
| 1759 | if (tag.type_expr) |type_expr| { |
| 1760 | try stream.print(": "); |
| 1761 | try stack.append(RenderState { .Expression = type_expr}); |
| 1762 | } |
| 1763 | }, |
| 1764 | ast.Node.Id.EnumTag => { |
| 1765 | const tag = @fieldParentPtr(ast.NodeEnumTag, "base", decl); |
| 1766 | try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token)); |
| 1767 | |
| 1768 | if (tag.value) |value| { |
| 1769 | try stream.print(" = "); |
| 1770 | try stack.append(RenderState { .Expression = value}); |
| 1771 | } |
| 1772 | }, |
| 1709 | 1773 | else => unreachable, |
| 1710 | 1774 | } |
| 1711 | 1775 | }, |
| ... | ... | @@ -1990,27 +2054,30 @@ pub const Parser = struct { |
| 1990 | 2054 | }, |
| 1991 | 2055 | ast.Node.Id.ContainerDecl => { |
| 1992 | 2056 | const container_decl = @fieldParentPtr(ast.NodeContainerDecl, "base", base); |
| 1993 | | try stream.print("{} {{", self.tokenizer.getTokenSlice(container_decl.kind_token)); |
| 2057 | |
| 2058 | switch (container_decl.layout) { |
| 2059 | ast.NodeContainerDecl.Layout.Packed => try stream.print("packed "), |
| 2060 | ast.NodeContainerDecl.Layout.Extern => try stream.print("extern "), |
| 2061 | ast.NodeContainerDecl.Layout.Auto => { }, |
| 2062 | } |
| 2063 | |
| 2064 | switch (container_decl.kind) { |
| 2065 | ast.NodeContainerDecl.Kind.Struct => try stream.print("struct"), |
| 2066 | ast.NodeContainerDecl.Kind.Enum => try stream.print("enum"), |
| 2067 | ast.NodeContainerDecl.Kind.Union => try stream.print("union"), |
| 2068 | } |
| 2069 | |
| 1994 | 2070 | try stack.append(RenderState { .Text = "}"}); |
| 1995 | 2071 | try stack.append(RenderState.PrintIndent); |
| 1996 | 2072 | try stack.append(RenderState { .Indent = indent }); |
| 2073 | try stack.append(RenderState { .Text = "\n"}); |
| 1997 | 2074 | |
| 1998 | 2075 | const fields_and_decls = container_decl.fields_and_decls.toSliceConst(); |
| 1999 | 2076 | var i = fields_and_decls.len; |
| 2000 | 2077 | while (i != 0) { |
| 2001 | 2078 | i -= 1; |
| 2002 | 2079 | const node = fields_and_decls[i]; |
| 2003 | | if (i != 0) { |
| 2004 | | switch (node.id) { |
| 2005 | | ast.Node.Id.StructField, |
| 2006 | | ast.Node.Id.UnionTag, |
| 2007 | | ast.Node.Id.EnumTag => { |
| 2008 | | try stack.append(RenderState { .Text = "," }); |
| 2009 | | }, |
| 2010 | | else => { } |
| 2011 | | } |
| 2012 | | } |
| 2013 | | try stack.append(RenderState { .Expression = node}); |
| 2080 | try stack.append(RenderState { .TopLevelDecl = node}); |
| 2014 | 2081 | try stack.append(RenderState.PrintIndent); |
| 2015 | 2082 | try stack.append(RenderState { |
| 2016 | 2083 | .Text = blk: { |
| ... | ... | @@ -2025,22 +2092,43 @@ pub const Parser = struct { |
| 2025 | 2092 | break :blk "\n"; |
| 2026 | 2093 | }, |
| 2027 | 2094 | }); |
| 2095 | |
| 2096 | if (i != 0) { |
| 2097 | const prev_node = fields_and_decls[i - 1]; |
| 2098 | switch (prev_node.id) { |
| 2099 | ast.Node.Id.StructField, |
| 2100 | ast.Node.Id.UnionTag, |
| 2101 | ast.Node.Id.EnumTag => { |
| 2102 | try stack.append(RenderState { .Text = "," }); |
| 2103 | }, |
| 2104 | else => { } |
| 2105 | } |
| 2106 | } |
| 2028 | 2107 | } |
| 2029 | 2108 | try stack.append(RenderState { .Indent = indent + indent_delta}); |
| 2109 | try stack.append(RenderState { .Text = "{"}); |
| 2110 | |
| 2111 | switch (container_decl.init_arg_expr) { |
| 2112 | ast.NodeContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}), |
| 2113 | ast.NodeContainerDecl.InitArg.Enum => try stack.append(RenderState { .Text = "(enum) "}), |
| 2114 | ast.NodeContainerDecl.InitArg.Type => |type_expr| { |
| 2115 | try stack.append(RenderState { .Text = ") "}); |
| 2116 | try stack.append(RenderState { .Expression = type_expr}); |
| 2117 | try stack.append(RenderState { .Text = "("}); |
| 2118 | }, |
| 2119 | } |
| 2030 | 2120 | }, |
| 2031 | 2121 | ast.Node.Id.MultilineStringLiteral => { |
| 2032 | 2122 | const multiline_str_literal = @fieldParentPtr(ast.NodeMultilineStringLiteral, "base", base); |
| 2033 | 2123 | try stream.print("\n"); |
| 2034 | 2124 | |
| 2035 | 2125 | var i : usize = 0; |
| 2036 | | indent += 4; |
| 2037 | 2126 | while (i < multiline_str_literal.tokens.len) : (i += 1) { |
| 2038 | 2127 | const t = multiline_str_literal.tokens.at(i); |
| 2039 | | try stream.writeByteNTimes(' ', indent); |
| 2128 | try stream.writeByteNTimes(' ', indent + indent_delta); |
| 2040 | 2129 | try stream.print("{}", self.tokenizer.getTokenSlice(t)); |
| 2041 | 2130 | } |
| 2042 | | try stream.writeByteNTimes(' ', indent); |
| 2043 | | indent -= 4; |
| 2131 | try stream.writeByteNTimes(' ', indent + indent_delta); |
| 2044 | 2132 | }, |
| 2045 | 2133 | ast.Node.Id.UndefinedLiteral => { |
| 2046 | 2134 | const undefined_literal = @fieldParentPtr(ast.NodeUndefinedLiteral, "base", base); |
| ... | ... | @@ -2060,31 +2148,12 @@ pub const Parser = struct { |
| 2060 | 2148 | } |
| 2061 | 2149 | } |
| 2062 | 2150 | }, |
| 2063 | | ast.Node.Id.StructField => { |
| 2064 | | const field = @fieldParentPtr(ast.NodeStructField, "base", base); |
| 2065 | | try stream.print("{}:", self.tokenizer.getTokenSlice(field.name_token)); |
| 2066 | | }, |
| 2067 | | ast.Node.Id.UnionTag => { |
| 2068 | | const tag = @fieldParentPtr(ast.NodeUnionTag, "base", base); |
| 2069 | | try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token)); |
| 2070 | | |
| 2071 | | if (tag.type_expr) |type_expr| { |
| 2072 | | try stream.print(": "); |
| 2073 | | try stack.append(RenderState { .Expression = type_expr}); |
| 2074 | | } |
| 2075 | | }, |
| 2076 | | ast.Node.Id.EnumTag => { |
| 2077 | | const tag = @fieldParentPtr(ast.NodeEnumTag, "base", base); |
| 2078 | | try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token)); |
| 2079 | | |
| 2080 | | if (tag.value) |value| { |
| 2081 | | try stream.print(" = "); |
| 2082 | | try stack.append(RenderState { .Expression = value}); |
| 2083 | | } |
| 2084 | | }, |
| 2085 | 2151 | ast.Node.Id.FnProto => @panic("TODO fn proto in an expression"), |
| 2086 | 2152 | ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"), |
| 2087 | 2153 | |
| 2154 | ast.Node.Id.StructField, |
| 2155 | ast.Node.Id.UnionTag, |
| 2156 | ast.Node.Id.EnumTag, |
| 2088 | 2157 | ast.Node.Id.Root, |
| 2089 | 2158 | ast.Node.Id.VarDecl, |
| 2090 | 2159 | ast.Node.Id.TestDecl, |
| ... | ... | @@ -2489,21 +2558,21 @@ test "zig fmt: struct declaration" { |
| 2489 | 2558 | \\ return *self; |
| 2490 | 2559 | \\ } |
| 2491 | 2560 | \\ |
| 2492 | | \\ f2: u8, |
| 2561 | \\ f2: u8 |
| 2493 | 2562 | \\}; |
| 2494 | 2563 | \\ |
| 2495 | 2564 | \\const Ps = packed struct { |
| 2496 | 2565 | \\ a: u8, |
| 2497 | 2566 | \\ b: u8, |
| 2498 | 2567 | \\ |
| 2499 | | \\ c: u8, |
| 2568 | \\ c: u8 |
| 2500 | 2569 | \\}; |
| 2501 | 2570 | \\ |
| 2502 | 2571 | \\const Es = extern struct { |
| 2503 | 2572 | \\ a: u8, |
| 2504 | 2573 | \\ b: u8, |
| 2505 | 2574 | \\ |
| 2506 | | \\ c: u8, |
| 2575 | \\ c: u8 |
| 2507 | 2576 | \\}; |
| 2508 | 2577 | \\ |
| 2509 | 2578 | ); |
| ... | ... | @@ -2513,25 +2582,25 @@ test "zig fmt: enum declaration" { |
| 2513 | 2582 | try testCanonical( |
| 2514 | 2583 | \\const E = enum { |
| 2515 | 2584 | \\ Ok, |
| 2516 | | \\ SomethingElse = 0, |
| 2585 | \\ SomethingElse = 0 |
| 2517 | 2586 | \\}; |
| 2518 | 2587 | \\ |
| 2519 | 2588 | \\const E2 = enum(u8) { |
| 2520 | 2589 | \\ Ok, |
| 2521 | 2590 | \\ SomethingElse = 255, |
| 2522 | | \\ SomethingThird, |
| 2591 | \\ SomethingThird |
| 2523 | 2592 | \\}; |
| 2524 | 2593 | \\ |
| 2525 | 2594 | \\const Ee = extern enum { |
| 2526 | 2595 | \\ Ok, |
| 2527 | 2596 | \\ SomethingElse, |
| 2528 | | \\ SomethingThird, |
| 2597 | \\ SomethingThird |
| 2529 | 2598 | \\}; |
| 2530 | 2599 | \\ |
| 2531 | 2600 | \\const Ep = packed enum { |
| 2532 | 2601 | \\ Ok, |
| 2533 | 2602 | \\ SomethingElse, |
| 2534 | | \\ SomethingThird, |
| 2603 | \\ SomethingThird |
| 2535 | 2604 | \\}; |
| 2536 | 2605 | \\ |
| 2537 | 2606 | ); |
| ... | ... | @@ -2542,31 +2611,36 @@ test "zig fmt: union declaration" { |
| 2542 | 2611 | \\const U = union { |
| 2543 | 2612 | \\ Int: u8, |
| 2544 | 2613 | \\ Float: f32, |
| 2545 | | \\ Bool: bool, |
| 2614 | \\ None, |
| 2615 | \\ Bool: bool |
| 2546 | 2616 | \\}; |
| 2547 | 2617 | \\ |
| 2548 | 2618 | \\const Ue = union(enum) { |
| 2549 | 2619 | \\ Int: u8, |
| 2550 | 2620 | \\ Float: f32, |
| 2551 | | \\ Bool: bool, |
| 2621 | \\ None, |
| 2622 | \\ Bool: bool |
| 2552 | 2623 | \\}; |
| 2553 | 2624 | \\ |
| 2554 | 2625 | \\const E = enum { |
| 2555 | 2626 | \\ Int, |
| 2556 | 2627 | \\ Float, |
| 2557 | | \\ Bool, |
| 2628 | \\ None, |
| 2629 | \\ Bool |
| 2558 | 2630 | \\}; |
| 2559 | 2631 | \\ |
| 2560 | 2632 | \\const Ue2 = union(E) { |
| 2561 | 2633 | \\ Int: u8, |
| 2562 | 2634 | \\ Float: f32, |
| 2563 | | \\ Bool: bool, |
| 2635 | \\ None, |
| 2636 | \\ Bool: bool |
| 2564 | 2637 | \\}; |
| 2565 | 2638 | \\ |
| 2566 | 2639 | \\const Eu = extern union { |
| 2567 | 2640 | \\ Int: u8, |
| 2568 | 2641 | \\ Float: f32, |
| 2569 | | \\ Bool: bool, |
| 2642 | \\ None, |
| 2643 | \\ Bool: bool |
| 2570 | 2644 | \\}; |
| 2571 | 2645 | \\ |
| 2572 | 2646 | ); |