| ... | ... | @@ -562,9 +562,9 @@ const AstNodeVarDecl = struct { |
| 562 | 562 | visib_token: ?Token, |
| 563 | 563 | name_token: Token, |
| 564 | 564 | eq_token: Token, |
| 565 | | mut: Mutability, |
| 566 | | is_comptime: Comptime, |
| 567 | | is_extern: Extern, |
| 565 | mut_token: Token, |
| 566 | comptime_token: ?Token, |
| 567 | extern_token: ?Token, |
| 568 | 568 | lib_name: ?&AstNode, |
| 569 | 569 | type_node: ?&AstNode, |
| 570 | 570 | align_node: ?&AstNode, |
| ... | ... | @@ -608,10 +608,10 @@ const AstNodeFnProto = struct { |
| 608 | 608 | name_token: ?Token, |
| 609 | 609 | params: ArrayList(&AstNode), |
| 610 | 610 | return_type: ?&AstNode, |
| 611 | | var_args: VarArgs, |
| 612 | | is_extern: Extern, |
| 613 | | is_inline: Inline, |
| 614 | | cc: CallingConvention, |
| 611 | var_args_token: ?Token, |
| 612 | extern_token: ?Token, |
| 613 | inline_token: ?Token, |
| 614 | cc_token: ?Token, |
| 615 | 615 | fn_def_node: ?&AstNode, |
| 616 | 616 | lib_name: ?&AstNode, // populated if this is an extern declaration |
| 617 | 617 | align_expr: ?&AstNode, // populated if align(A) is present |
| ... | ... | @@ -729,10 +729,15 @@ const Parser = struct { |
| 729 | 729 | self.allocator.free(self.utility_bytes); |
| 730 | 730 | } |
| 731 | 731 | |
| 732 | const TopLevelExternCtx = struct { |
| 733 | visib_token: ?Token, |
| 734 | extern_token: Token, |
| 735 | }; |
| 736 | |
| 732 | 737 | const State = union(enum) { |
| 733 | 738 | TopLevel, |
| 734 | 739 | TopLevelModifier: ?Token, |
| 735 | | TopLevelExtern: ?Token, |
| 740 | TopLevelExtern: TopLevelExternCtx, |
| 736 | 741 | Expression: &&AstNode, |
| 737 | 742 | GroupedExpression: &&AstNode, |
| 738 | 743 | UnwrapExpression: &&AstNode, |
| ... | ... | @@ -803,25 +808,22 @@ const Parser = struct { |
| 803 | 808 | stack.append(State { .TopLevelModifier = token }) %% unreachable; |
| 804 | 809 | continue; |
| 805 | 810 | }, |
| 806 | | Token.Id.Keyword_const => { |
| 807 | | stack.append(State.TopLevel) %% unreachable; |
| 808 | | // TODO shouldn't need this cast |
| 809 | | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, (?Token)(null), |
| 810 | | Mutability.Const, Comptime.No, Extern.No); |
| 811 | | %return stack.append(State { .VarDecl = var_decl_node }); |
| 812 | | continue; |
| 813 | | }, |
| 814 | | Token.Id.Keyword_var => { |
| 811 | Token.Id.Keyword_const, Token.Id.Keyword_var => { |
| 815 | 812 | stack.append(State.TopLevel) %% unreachable; |
| 816 | 813 | // TODO shouldn't need this cast |
| 817 | 814 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, (?Token)(null), |
| 818 | | Mutability.Var, Comptime.No, Extern.No); |
| 815 | token, (?Token)(null), (?Token)(null)); |
| 819 | 816 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 820 | 817 | continue; |
| 821 | 818 | }, |
| 822 | 819 | Token.Id.Eof => return root_node, |
| 823 | 820 | Token.Id.Keyword_extern => { |
| 824 | | stack.append(State { .TopLevelExtern = null }) %% unreachable; |
| 821 | stack.append(State { |
| 822 | .TopLevelExtern = TopLevelExternCtx { |
| 823 | .visib_token = null, |
| 824 | .extern_token = token, |
| 825 | } |
| 826 | }) %% unreachable; |
| 825 | 827 | continue; |
| 826 | 828 | }, |
| 827 | 829 | else => return self.parseError(token, "expected top level declaration, found {}", @tagName(token.id)), |
| ... | ... | @@ -830,43 +832,43 @@ const Parser = struct { |
| 830 | 832 | State.TopLevelModifier => |visib_token| { |
| 831 | 833 | const token = self.getNextToken(); |
| 832 | 834 | switch (token.id) { |
| 833 | | Token.Id.Keyword_const => { |
| 834 | | stack.append(State.TopLevel) %% unreachable; |
| 835 | | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token, |
| 836 | | Mutability.Const, Comptime.No, Extern.No); |
| 837 | | %return stack.append(State { .VarDecl = var_decl_node }); |
| 838 | | continue; |
| 839 | | }, |
| 840 | | Token.Id.Keyword_var => { |
| 835 | Token.Id.Keyword_const, Token.Id.Keyword_var => { |
| 841 | 836 | stack.append(State.TopLevel) %% unreachable; |
| 837 | // TODO shouldn't need the casts here |
| 842 | 838 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token, |
| 843 | | Mutability.Var, Comptime.No, Extern.No); |
| 839 | token, (?Token)(null), (?Token)(null)); |
| 844 | 840 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 845 | 841 | continue; |
| 846 | 842 | }, |
| 847 | 843 | Token.Id.Keyword_extern => { |
| 848 | | stack.append(State { .TopLevelExtern = visib_token }) %% unreachable; |
| 844 | stack.append(State { |
| 845 | .TopLevelExtern = TopLevelExternCtx { |
| 846 | .visib_token = visib_token, |
| 847 | .extern_token = token, |
| 848 | }, |
| 849 | }) %% unreachable; |
| 849 | 850 | continue; |
| 850 | 851 | }, |
| 851 | 852 | else => return self.parseError(token, "expected top level declaration, found {}", @tagName(token.id)), |
| 852 | 853 | } |
| 853 | 854 | }, |
| 854 | | State.TopLevelExtern => |visib_token| { |
| 855 | State.TopLevelExtern => |ctx| { |
| 855 | 856 | const token = self.getNextToken(); |
| 856 | 857 | switch (token.id) { |
| 857 | | Token.Id.Keyword_var => { |
| 858 | Token.Id.Keyword_var, Token.Id.Keyword_const => { |
| 858 | 859 | stack.append(State.TopLevel) %% unreachable; |
| 859 | | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token, |
| 860 | | Mutability.Var, Comptime.No, Extern.Yes); |
| 860 | // TODO shouldn't need these casts |
| 861 | const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, ctx.visib_token, |
| 862 | token, (?Token)(null), (?Token)(ctx.extern_token)); |
| 861 | 863 | %return stack.append(State { .VarDecl = var_decl_node }); |
| 862 | 864 | continue; |
| 863 | 865 | }, |
| 864 | 866 | Token.Id.Keyword_fn => { |
| 865 | 867 | stack.append(State.TopLevel) %% unreachable; |
| 866 | 868 | %return stack.append(State { .ExpectToken = Token.Id.Semicolon }); |
| 867 | | // TODO shouldn't need this cast |
| 869 | // TODO shouldn't need these casts |
| 868 | 870 | const fn_proto_node = %return self.createAttachFnProto(&root_node.decls, token, |
| 869 | | Extern.Yes, CallingConvention.Auto, (?Token)(null), Inline.Auto); |
| 871 | (?Token)(ctx.extern_token), (?Token)(null), (?Token)(null), (?Token)(null)); |
| 870 | 872 | %return stack.append(State { .FnProto = fn_proto_node }); |
| 871 | 873 | continue; |
| 872 | 874 | }, |
| ... | ... | @@ -876,16 +878,10 @@ const Parser = struct { |
| 876 | 878 | Token.Id.Keyword_coldcc, Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => { |
| 877 | 879 | stack.append(State.TopLevel) %% unreachable; |
| 878 | 880 | %return stack.append(State { .ExpectToken = Token.Id.Semicolon }); |
| 879 | | const cc = switch (token.id) { |
| 880 | | Token.Id.Keyword_coldcc => CallingConvention.Cold, |
| 881 | | Token.Id.Keyword_nakedcc => CallingConvention.Naked, |
| 882 | | Token.Id.Keyword_stdcallcc => CallingConvention.Stdcall, |
| 883 | | else => unreachable, |
| 884 | | }; |
| 885 | 881 | const fn_token = %return self.eatToken(Token.Id.Keyword_fn); |
| 886 | 882 | // TODO shouldn't need this cast |
| 887 | 883 | const fn_proto_node = %return self.createAttachFnProto(&root_node.decls, fn_token, |
| 888 | | Extern.Yes, cc, (?Token)(null), Inline.Auto); |
| 884 | (?Token)(ctx.extern_token), (?Token)(token), (?Token)(null), (?Token)(null)); |
| 889 | 885 | %return stack.append(State { .FnProto = fn_proto_node }); |
| 890 | 886 | continue; |
| 891 | 887 | }, |
| ... | ... | @@ -1137,8 +1133,8 @@ const Parser = struct { |
| 1137 | 1133 | return node; |
| 1138 | 1134 | } |
| 1139 | 1135 | |
| 1140 | | fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut: Mutability, is_comptime: Comptime, |
| 1141 | | is_extern: Extern) -> %&AstNodeVarDecl |
| 1136 | fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token, |
| 1137 | extern_token: &const ?Token) -> %&AstNodeVarDecl |
| 1142 | 1138 | { |
| 1143 | 1139 | const node = %return self.allocator.create(AstNodeVarDecl); |
| 1144 | 1140 | %defer self.allocator.destroy(node); |
| ... | ... | @@ -1146,9 +1142,9 @@ const Parser = struct { |
| 1146 | 1142 | *node = AstNodeVarDecl { |
| 1147 | 1143 | .base = AstNode {.id = AstNode.Id.VarDecl}, |
| 1148 | 1144 | .visib_token = *visib_token, |
| 1149 | | .mut = mut, |
| 1150 | | .is_comptime = is_comptime, |
| 1151 | | .is_extern = is_extern, |
| 1145 | .mut_token = *mut_token, |
| 1146 | .comptime_token = *comptime_token, |
| 1147 | .extern_token = *extern_token, |
| 1152 | 1148 | .type_node = null, |
| 1153 | 1149 | .align_node = null, |
| 1154 | 1150 | .init_node = null, |
| ... | ... | @@ -1171,8 +1167,8 @@ const Parser = struct { |
| 1171 | 1167 | return node; |
| 1172 | 1168 | } |
| 1173 | 1169 | |
| 1174 | | fn createFnProto(self: &Parser, fn_token: &const Token, is_extern: Extern, |
| 1175 | | cc: CallingConvention, visib_token: &const ?Token, is_inline: Inline) -> %&AstNodeFnProto |
| 1170 | fn createFnProto(self: &Parser, fn_token: &const Token, extern_token: &const ?Token, |
| 1171 | cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) -> %&AstNodeFnProto |
| 1176 | 1172 | { |
| 1177 | 1173 | const node = %return self.allocator.create(AstNodeFnProto); |
| 1178 | 1174 | %defer self.allocator.destroy(node); |
| ... | ... | @@ -1184,10 +1180,10 @@ const Parser = struct { |
| 1184 | 1180 | .fn_token = *fn_token, |
| 1185 | 1181 | .params = ArrayList(&AstNode).init(self.allocator), |
| 1186 | 1182 | .return_type = null, |
| 1187 | | .var_args = VarArgs.No, |
| 1188 | | .is_extern = is_extern, |
| 1189 | | .is_inline = is_inline, |
| 1190 | | .cc = cc, |
| 1183 | .var_args_token = null, |
| 1184 | .extern_token = *extern_token, |
| 1185 | .inline_token = *inline_token, |
| 1186 | .cc_token = *cc_token, |
| 1191 | 1187 | .fn_def_node = null, |
| 1192 | 1188 | .lib_name = null, |
| 1193 | 1189 | .align_expr = null, |
| ... | ... | @@ -1242,18 +1238,19 @@ const Parser = struct { |
| 1242 | 1238 | } |
| 1243 | 1239 | |
| 1244 | 1240 | fn createAttachFnProto(self: &Parser, list: &ArrayList(&AstNode), fn_token: &const Token, |
| 1245 | | is_extern: Extern, cc: CallingConvention, visib_token: &const ?Token, is_inline: Inline) -> %&AstNodeFnProto |
| 1241 | extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token, |
| 1242 | inline_token: &const ?Token) -> %&AstNodeFnProto |
| 1246 | 1243 | { |
| 1247 | | const node = %return self.createFnProto(fn_token, is_extern, cc, visib_token, is_inline); |
| 1244 | const node = %return self.createFnProto(fn_token, extern_token, cc_token, visib_token, inline_token); |
| 1248 | 1245 | %defer self.allocator.destroy(node); |
| 1249 | 1246 | %return list.append(&node.base); |
| 1250 | 1247 | return node; |
| 1251 | 1248 | } |
| 1252 | 1249 | |
| 1253 | | fn createAttachVarDecl(self: &Parser, list: &ArrayList(&AstNode), visib_token: &const ?Token, mut: Mutability, |
| 1254 | | is_comptime: Comptime, is_extern: Extern) -> %&AstNodeVarDecl |
| 1250 | fn createAttachVarDecl(self: &Parser, list: &ArrayList(&AstNode), visib_token: &const ?Token, |
| 1251 | mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) -> %&AstNodeVarDecl |
| 1255 | 1252 | { |
| 1256 | | const node = %return self.createVarDecl(visib_token, mut, is_comptime, is_extern); |
| 1253 | const node = %return self.createVarDecl(visib_token, mut_token, comptime_token, extern_token); |
| 1257 | 1254 | %defer self.allocator.destroy(node); |
| 1258 | 1255 | %return list.append(&node.base); |
| 1259 | 1256 | return node; |
| ... | ... | @@ -1376,8 +1373,8 @@ const Parser = struct { |
| 1376 | 1373 | else => unreachable, |
| 1377 | 1374 | }; |
| 1378 | 1375 | } |
| 1379 | | if (fn_proto.is_extern == Extern.Yes) { |
| 1380 | | %return stream.print("extern "); |
| 1376 | if (fn_proto.extern_token) |extern_token| { |
| 1377 | %return stream.print("{} ", self.tokenizer.getTokenSlice(extern_token)); |
| 1381 | 1378 | } |
| 1382 | 1379 | %return stream.print("fn"); |
| 1383 | 1380 | |
| ... | ... | @@ -1403,6 +1400,30 @@ const Parser = struct { |
| 1403 | 1400 | } |
| 1404 | 1401 | } |
| 1405 | 1402 | }, |
| 1403 | AstNode.Id.VarDecl => { |
| 1404 | const var_decl = @fieldParentPtr(AstNodeVarDecl, "base", decl); |
| 1405 | if (var_decl.visib_token) |visib_token| { |
| 1406 | %return stream.print("{} ", self.tokenizer.getTokenSlice(visib_token)); |
| 1407 | } |
| 1408 | if (var_decl.extern_token) |extern_token| { |
| 1409 | %return stream.print("{} ", self.tokenizer.getTokenSlice(extern_token)); |
| 1410 | if (var_decl.lib_name != null) { |
| 1411 | @panic("TODO"); |
| 1412 | } |
| 1413 | } |
| 1414 | if (var_decl.comptime_token) |comptime_token| { |
| 1415 | %return stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token)); |
| 1416 | } |
| 1417 | %return stream.print("{} ", self.tokenizer.getTokenSlice(var_decl.mut_token)); |
| 1418 | %return stream.print("{}", self.tokenizer.getTokenSlice(var_decl.name_token)); |
| 1419 | |
| 1420 | %return stream.print(" = "); |
| 1421 | |
| 1422 | %return stack.append(RenderState { .Text = ";\n" }); |
| 1423 | if (var_decl.init_node) |init_node| { |
| 1424 | %return stack.append(RenderState { .Expression = init_node }); |
| 1425 | } |
| 1426 | }, |
| 1406 | 1427 | else => unreachable, |
| 1407 | 1428 | } |
| 1408 | 1429 | }, |
| ... | ... | @@ -1570,4 +1591,12 @@ test "zig fmt" { |
| 1570 | 1591 | \\extern fn puts(s: &const u8) -> c_int; |
| 1571 | 1592 | \\ |
| 1572 | 1593 | ); |
| 1594 | |
| 1595 | testCanonical( |
| 1596 | \\const a = b; |
| 1597 | \\pub const a = b; |
| 1598 | \\var a = b; |
| 1599 | \\pub var a = b; |
| 1600 | \\ |
| 1601 | ); |
| 1573 | 1602 | } |