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