authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-06-13 19:49:41+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-06-13 19:49:41+03:00
logf58fbb1004e26982ad83c61b3fecf5e575fb9210
tree328036fa9c7eb125307437e0fdf0244d782c9736
parent46b9e061e07700ad1372ed2e9d2af9a29f24d76c
parent483933d88d4fbf00467a48df100075a40344766b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9074 from mattbork/parse-always-scratch

parse.zig: simplify parsing functions that build lists by always using scratch buffer

2 files changed, 342 insertions(+), 601 deletions(-)

lib/std/zig/parse.zig+341-600
...@@ -1850,65 +1850,54 @@ const Parser = struct {...@@ -1850,65 +1850,54 @@ const Parser = struct {
1850 /// Block <- LBRACE Statement* RBRACE1850 /// Block <- LBRACE Statement* RBRACE
1851 fn parseBlock(p: *Parser) !Node.Index {1851 fn parseBlock(p: *Parser) !Node.Index {
1852 const lbrace = p.eatToken(.l_brace) orelse return null_node;1852 const lbrace = p.eatToken(.l_brace) orelse return null_node;
18531853 const scratch_top = p.scratch.items.len;
1854 if (p.eatToken(.r_brace)) |_| {1854 defer p.scratch.shrinkRetainingCapacity(scratch_top);
1855 return p.addNode(.{1855 while (true) {
1856 if (p.token_tags[p.tok_i] == .r_brace) break;
1857 const statement = try p.expectStatementRecoverable();
1858 if (statement == 0) break;
1859 try p.scratch.append(p.gpa, statement);
1860 }
1861 _ = try p.expectToken(.r_brace);
1862 const semicolon = (p.token_tags[p.tok_i - 2] == .semicolon);
1863 const statements = p.scratch.items[scratch_top..];
1864 switch (statements.len) {
1865 0 => return p.addNode(.{
1856 .tag = .block_two,1866 .tag = .block_two,
1857 .main_token = lbrace,1867 .main_token = lbrace,
1858 .data = .{1868 .data = .{
1859 .lhs = 0,1869 .lhs = 0,
1860 .rhs = 0,1870 .rhs = 0,
1861 },1871 },
1862 });1872 }),
1863 }1873 1 => return p.addNode(.{
1864
1865 const stmt_one = try p.expectStatementRecoverable();
1866 if (p.eatToken(.r_brace)) |_| {
1867 const semicolon = p.token_tags[p.tok_i - 2] == .semicolon;
1868 return p.addNode(.{
1869 .tag = if (semicolon) .block_two_semicolon else .block_two,1874 .tag = if (semicolon) .block_two_semicolon else .block_two,
1870 .main_token = lbrace,1875 .main_token = lbrace,
1871 .data = .{1876 .data = .{
1872 .lhs = stmt_one,1877 .lhs = statements[0],
1873 .rhs = 0,1878 .rhs = 0,
1874 },1879 },
1875 });1880 }),
1876 }1881 2 => return p.addNode(.{
1877 const stmt_two = try p.expectStatementRecoverable();
1878 if (p.eatToken(.r_brace)) |_| {
1879 const semicolon = p.token_tags[p.tok_i - 2] == .semicolon;
1880 return p.addNode(.{
1881 .tag = if (semicolon) .block_two_semicolon else .block_two,1882 .tag = if (semicolon) .block_two_semicolon else .block_two,
1882 .main_token = lbrace,1883 .main_token = lbrace,
1883 .data = .{1884 .data = .{
1884 .lhs = stmt_one,1885 .lhs = statements[0],
1885 .rhs = stmt_two,1886 .rhs = statements[1],
1886 },1887 },
1887 });1888 }),
1888 }1889 else => {
18891890 const span = try p.listToSpan(statements);
1890 const scratch_top = p.scratch.items.len;1891 return p.addNode(.{
1891 defer p.scratch.shrinkRetainingCapacity(scratch_top);1892 .tag = if (semicolon) .block_semicolon else .block,
18921893 .main_token = lbrace,
1893 try p.scratch.appendSlice(p.gpa, &.{ stmt_one, stmt_two });1894 .data = .{
18941895 .lhs = span.start,
1895 while (true) {1896 .rhs = span.end,
1896 const statement = try p.expectStatementRecoverable();1897 },
1897 if (statement == 0) break;1898 });
1898 try p.scratch.append(p.gpa, statement);
1899 if (p.token_tags[p.tok_i] == .r_brace) break;
1900 }
1901 _ = try p.expectToken(.r_brace);
1902 const semicolon = p.token_tags[p.tok_i - 2] == .semicolon;
1903 const statements_span = try p.listToSpan(p.scratch.items[scratch_top..]);
1904 return p.addNode(.{
1905 .tag = if (semicolon) .block_semicolon else .block,
1906 .main_token = lbrace,
1907 .data = .{
1908 .lhs = statements_span.start,
1909 .rhs = statements_span.end,
1910 },1899 },
1911 });1900 }
1912 }1901 }
19131902
1914 /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload1903 /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload
...@@ -2010,114 +1999,86 @@ const Parser = struct {...@@ -2010,114 +1999,86 @@ const Parser = struct {
2010 // If there are 0 or 1 items, we can use ArrayInitOne/StructInitOne;1999 // If there are 0 or 1 items, we can use ArrayInitOne/StructInitOne;
2011 // otherwise we use the full ArrayInit/StructInit.2000 // otherwise we use the full ArrayInit/StructInit.
20122001
2013 if (p.eatToken(.r_brace)) |_| {2002 const scratch_top = p.scratch.items.len;
2014 return p.addNode(.{2003 defer p.scratch.shrinkRetainingCapacity(scratch_top);
2015 .tag = .struct_init_one,
2016 .main_token = lbrace,
2017 .data = .{
2018 .lhs = lhs,
2019 .rhs = 0,
2020 },
2021 });
2022 }
2023 const field_init = try p.parseFieldInit();2004 const field_init = try p.parseFieldInit();
2024 if (field_init != 0) {2005 if (field_init != 0) {
2025 const comma_one = p.eatToken(.comma);
2026 if (p.eatToken(.r_brace)) |_| {
2027 return p.addNode(.{
2028 .tag = if (comma_one != null) .struct_init_one_comma else .struct_init_one,
2029 .main_token = lbrace,
2030 .data = .{
2031 .lhs = lhs,
2032 .rhs = field_init,
2033 },
2034 });
2035 }
2036
2037 const scratch_top = p.scratch.items.len;
2038 defer p.scratch.shrinkRetainingCapacity(scratch_top);
2039
2040 try p.scratch.append(p.gpa, field_init);2006 try p.scratch.append(p.gpa, field_init);
2041
2042 while (true) {2007 while (true) {
2008 switch (p.token_tags[p.tok_i]) {
2009 .comma => p.tok_i += 1,
2010 .r_brace => { p.tok_i += 1; break; },
2011 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2012 // Likely just a missing comma; give error but continue parsing.
2013 else => try p.warnExpected(.comma),
2014 }
2015 if (p.eatToken(.r_brace)) |_| break;
2043 const next = try p.expectFieldInit();2016 const next = try p.expectFieldInit();
2044 try p.scratch.append(p.gpa, next);2017 try p.scratch.append(p.gpa, next);
20452018 }
2046 switch (p.token_tags[p.nextToken()]) {2019 const comma = (p.token_tags[p.tok_i - 2] == .comma);
2047 .comma => {2020 const inits = p.scratch.items[scratch_top..];
2048 if (p.eatToken(.r_brace)) |_| break;2021 switch (inits.len) {
2049 continue;2022 0 => unreachable,
2050 },2023 1 => return p.addNode(.{
2051 .r_brace => break,2024 .tag = if (comma) .struct_init_one_comma else .struct_init_one,
2052 .colon, .r_paren, .r_bracket => {2025 .main_token = lbrace,
2053 p.tok_i -= 1;2026 .data = .{
2054 return p.failExpected(.r_brace);2027 .lhs = lhs,
2028 .rhs = inits[0],
2055 },2029 },
2056 else => {2030 }),
2057 // This is likely just a missing comma;2031 else => return p.addNode(.{
2058 // give an error but continue parsing this list.2032 .tag = if (comma) .struct_init_comma else .struct_init,
2059 p.tok_i -= 1;2033 .main_token = lbrace,
2060 try p.warnExpected(.comma);2034 .data = .{
2035 .lhs = lhs,
2036 .rhs = try p.addExtra(try p.listToSpan(inits)),
2061 },2037 },
2062 }2038 }),
2063 }2039 }
2064 const span = try p.listToSpan(p.scratch.items[scratch_top..]);2040 }
2065 return p.addNode(.{2041
2066 .tag = if (p.token_tags[p.tok_i - 2] == .comma) .struct_init_comma else .struct_init,2042 while (true) {
2043 if (p.eatToken(.r_brace)) |_| break;
2044 const elem_init = try p.expectExpr();
2045 try p.scratch.append(p.gpa, elem_init);
2046 switch (p.token_tags[p.tok_i]) {
2047 .comma => p.tok_i += 1,
2048 .r_brace => { p.tok_i += 1; break; },
2049 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2050 // Likely just a missing comma; give error but continue parsing.
2051 else => try p.warnExpected(.comma),
2052 }
2053 }
2054 const comma = (p.token_tags[p.tok_i - 2] == .comma);
2055 const inits = p.scratch.items[scratch_top..];
2056 switch (inits.len) {
2057 0 => return p.addNode(.{
2058 .tag = .struct_init_one,
2067 .main_token = lbrace,2059 .main_token = lbrace,
2068 .data = .{2060 .data = .{
2069 .lhs = lhs,2061 .lhs = lhs,
2070 .rhs = try p.addExtra(Node.SubRange{2062 .rhs = 0,
2071 .start = span.start,
2072 .end = span.end,
2073 }),
2074 },2063 },
2075 });2064 }),
2076 }2065 1 => return p.addNode(.{
20772066 .tag = if (comma) .array_init_one_comma else .array_init_one,
2078 const elem_init = try p.expectExpr();
2079 const comma_one = p.eatToken(.comma);
2080 if (p.eatToken(.r_brace)) |_| {
2081 return p.addNode(.{
2082 .tag = if (comma_one != null) .array_init_one_comma else .array_init_one,
2083 .main_token = lbrace,2067 .main_token = lbrace,
2084 .data = .{2068 .data = .{
2085 .lhs = lhs,2069 .lhs = lhs,
2086 .rhs = elem_init,2070 .rhs = inits[0],
2087 },2071 },
2088 });2072 }),
2089 }2073 else => return p.addNode(.{
2090 if (comma_one == null) {2074 .tag = if (comma) .array_init_comma else .array_init,
2091 try p.warnExpected(.comma);2075 .main_token = lbrace,
2092 }2076 .data = .{
20932077 .lhs = lhs,
2094 const scratch_top = p.scratch.items.len;2078 .rhs = try p.addExtra(try p.listToSpan(inits)),
2095 defer p.scratch.shrinkRetainingCapacity(scratch_top);2079 },
20962080 }),
2097 try p.scratch.append(p.gpa, elem_init);
2098
2099 var trailing_comma = true;
2100 var next = try p.parseExpr();
2101 while (next != 0) : (next = try p.parseExpr()) {
2102 try p.scratch.append(p.gpa, next);
2103 if (p.eatToken(.comma) == null) {
2104 trailing_comma = false;
2105 break;
2106 }
2107 }2081 }
2108 _ = try p.expectToken(.r_brace);
2109 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2110 return p.addNode(.{
2111 .tag = if (trailing_comma) .array_init_comma else .array_init,
2112 .main_token = lbrace,
2113 .data = .{
2114 .lhs = lhs,
2115 .rhs = try p.addExtra(Node.SubRange{
2116 .start = span.start,
2117 .end = span.end,
2118 }),
2119 },
2120 });
2121 }2082 }
21222083
2123 /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?2084 /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
...@@ -2143,184 +2104,109 @@ const Parser = struct {...@@ -2143,184 +2104,109 @@ const Parser = struct {
2143 fn parseSuffixExpr(p: *Parser) !Node.Index {2104 fn parseSuffixExpr(p: *Parser) !Node.Index {
2144 if (p.eatToken(.keyword_async)) |async_token| {2105 if (p.eatToken(.keyword_async)) |async_token| {
2145 var res = try p.expectPrimaryTypeExpr();2106 var res = try p.expectPrimaryTypeExpr();
2146
2147 while (true) {2107 while (true) {
2148 const node = try p.parseSuffixOp(res);2108 const node = try p.parseSuffixOp(res);
2149 if (node == 0) break;2109 if (node == 0) break;
2150 res = node;2110 res = node;
2151 }2111 }
2152 const lparen = p.nextToken();2112 const lparen = p.eatToken(.l_paren) orelse {
2153 if (p.token_tags[lparen] != .l_paren) {
2154 p.tok_i -= 1;
2155 try p.warn(.expected_param_list);2113 try p.warn(.expected_param_list);
2156 return res;2114 return res;
2115 };
2116 const scratch_top = p.scratch.items.len;
2117 defer p.scratch.shrinkRetainingCapacity(scratch_top);
2118 while (true) {
2119 if (p.eatToken(.r_paren)) |_| break;
2120 const param = try p.expectExpr();
2121 try p.scratch.append(p.gpa, param);
2122 switch (p.token_tags[p.tok_i]) {
2123 .comma => p.tok_i += 1,
2124 .r_paren => { p.tok_i += 1; break; },
2125 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
2126 // Likely just a missing comma; give error but continue parsing.
2127 else => try p.warnExpected(.comma),
2128 }
2157 }2129 }
2158 if (p.eatToken(.r_paren)) |_| {2130 const comma = (p.token_tags[p.tok_i - 2] == .comma);
2159 return p.addNode(.{2131 const params = p.scratch.items[scratch_top..];
2160 .tag = .async_call_one,2132 switch(params.len) {
2133 0 => return p.addNode(.{
2134 .tag = if (comma) .async_call_one_comma else .async_call_one,
2161 .main_token = lparen,2135 .main_token = lparen,
2162 .data = .{2136 .data = .{
2163 .lhs = res,2137 .lhs = res,
2164 .rhs = 0,2138 .rhs = 0,
2165 },2139 },
2166 });2140 }),
2167 }2141 1 => return p.addNode(.{
2168 const param_one = try p.expectExpr();2142 .tag = if (comma) .async_call_one_comma else .async_call_one,
2169 const comma_one = p.eatToken(.comma);
2170 if (p.eatToken(.r_paren)) |_| {
2171 return p.addNode(.{
2172 .tag = if (comma_one == null) .async_call_one else .async_call_one_comma,
2173 .main_token = lparen,2143 .main_token = lparen,
2174 .data = .{2144 .data = .{
2175 .lhs = res,2145 .lhs = res,
2176 .rhs = param_one,2146 .rhs = params[0],
2177 },
2178 });
2179 }
2180 if (comma_one == null) {
2181 try p.warnExpected(.comma);
2182 }
2183
2184 const scratch_top = p.scratch.items.len;
2185 defer p.scratch.shrinkRetainingCapacity(scratch_top);
2186
2187 try p.scratch.append(p.gpa, param_one);
2188
2189 while (true) {
2190 const next = try p.expectExpr();
2191 try p.scratch.append(p.gpa, next);
2192 switch (p.token_tags[p.nextToken()]) {
2193 .comma => {
2194 if (p.eatToken(.r_paren)) |_| {
2195 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2196 return p.addNode(.{
2197 .tag = .async_call_comma,
2198 .main_token = lparen,
2199 .data = .{
2200 .lhs = res,
2201 .rhs = try p.addExtra(Node.SubRange{
2202 .start = span.start,
2203 .end = span.end,
2204 }),
2205 },
2206 });
2207 } else {
2208 continue;
2209 }
2210 },
2211 .r_paren => {
2212 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2213 return p.addNode(.{
2214 .tag = .async_call,
2215 .main_token = lparen,
2216 .data = .{
2217 .lhs = res,
2218 .rhs = try p.addExtra(Node.SubRange{
2219 .start = span.start,
2220 .end = span.end,
2221 }),
2222 },
2223 });
2224 },2147 },
2225 .colon, .r_brace, .r_bracket => {2148 }),
2226 p.tok_i -= 1;2149 else => return p.addNode(.{
2227 return p.failExpected(.r_paren);2150 .tag = if (comma) .async_call_comma else .async_call,
2228 },2151 .main_token = lparen,
2229 else => {2152 .data = .{
2230 p.tok_i -= 1;2153 .lhs = res,
2231 try p.warnExpected(.comma);2154 .rhs = try p.addExtra(try p.listToSpan(params)),
2232 },2155 },
2233 }2156 }),
2234 }2157 }
2235 }2158 }
2159
2236 var res = try p.parsePrimaryTypeExpr();2160 var res = try p.parsePrimaryTypeExpr();
2237 if (res == 0) return res;2161 if (res == 0) return res;
2238
2239 while (true) {2162 while (true) {
2240 const suffix_op = try p.parseSuffixOp(res);2163 const suffix_op = try p.parseSuffixOp(res);
2241 if (suffix_op != 0) {2164 if (suffix_op != 0) {
2242 res = suffix_op;2165 res = suffix_op;
2243 continue;2166 continue;
2244 }2167 }
2245 res = res: {2168 const lparen = p.eatToken(.l_paren) orelse return res;
2246 const lparen = p.eatToken(.l_paren) orelse return res;2169 const scratch_top = p.scratch.items.len;
2247 if (p.eatToken(.r_paren)) |_| {2170 defer p.scratch.shrinkRetainingCapacity(scratch_top);
2248 break :res try p.addNode(.{2171 while (true) {
2249 .tag = .call_one,2172 if (p.eatToken(.r_paren)) |_| break;
2250 .main_token = lparen,2173 const param = try p.expectExpr();
2251 .data = .{2174 try p.scratch.append(p.gpa, param);
2252 .lhs = res,2175 switch (p.token_tags[p.tok_i]) {
2253 .rhs = 0,2176 .comma => p.tok_i += 1,
2254 },2177 .r_paren => { p.tok_i += 1; break; },
2255 });2178 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
2256 }2179 // Likely just a missing comma; give error but continue parsing.
2257 const param_one = try p.expectExpr();2180 else => try p.warnExpected(.comma),
2258 const comma_one = p.eatToken(.comma);
2259 if (p.eatToken(.r_paren)) |_| {
2260 break :res try p.addNode(.{
2261 .tag = if (comma_one == null) .call_one else .call_one_comma,
2262 .main_token = lparen,
2263 .data = .{
2264 .lhs = res,
2265 .rhs = param_one,
2266 },
2267 });
2268 }
2269 if (comma_one == null) {
2270 try p.warnExpected(.comma);
2271 }
2272
2273 const scratch_top = p.scratch.items.len;
2274 defer p.scratch.shrinkRetainingCapacity(scratch_top);
2275
2276 try p.scratch.append(p.gpa, param_one);
2277
2278 while (true) {
2279 const next = try p.expectExpr();
2280 try p.scratch.append(p.gpa, next);
2281 switch (p.token_tags[p.nextToken()]) {
2282 .comma => {
2283 if (p.eatToken(.r_paren)) |_| {
2284 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2285 break :res try p.addNode(.{
2286 .tag = .call_comma,
2287 .main_token = lparen,
2288 .data = .{
2289 .lhs = res,
2290 .rhs = try p.addExtra(Node.SubRange{
2291 .start = span.start,
2292 .end = span.end,
2293 }),
2294 },
2295 });
2296 } else {
2297 continue;
2298 }
2299 },
2300 .r_paren => {
2301 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
2302 break :res try p.addNode(.{
2303 .tag = .call,
2304 .main_token = lparen,
2305 .data = .{
2306 .lhs = res,
2307 .rhs = try p.addExtra(Node.SubRange{
2308 .start = span.start,
2309 .end = span.end,
2310 }),
2311 },
2312 });
2313 },
2314 .colon, .r_brace, .r_bracket => {
2315 p.tok_i -= 1;
2316 return p.failExpected(.r_paren);
2317 },
2318 else => {
2319 p.tok_i -= 1;
2320 try p.warnExpected(.comma);
2321 },
2322 }
2323 }2181 }
2182 }
2183 const comma = (p.token_tags[p.tok_i - 2] == .comma);
2184 const params = p.scratch.items[scratch_top..];
2185 res = switch(params.len) {
2186 0 => try p.addNode(.{
2187 .tag = if (comma) .call_one_comma else .call_one,
2188 .main_token = lparen,
2189 .data = .{
2190 .lhs = res,
2191 .rhs = 0,
2192 },
2193 }),
2194 1 => try p.addNode(.{
2195 .tag = if (comma) .call_one_comma else .call_one,
2196 .main_token = lparen,
2197 .data = .{
2198 .lhs = res,
2199 .rhs = params[0],
2200 },
2201 }),
2202 else => try p.addNode(.{
2203 .tag = if (comma) .call_comma else .call,
2204 .main_token = lparen,
2205 .data = .{
2206 .lhs = res,
2207 .rhs = try p.addExtra(try p.listToSpan(params)),
2208 },
2209 }),
2324 };2210 };
2325 }2211 }
2326 }2212 }
...@@ -2554,148 +2440,108 @@ const Parser = struct {...@@ -2554,148 +2440,108 @@ const Parser = struct {
2554 // If there are 0, 1, or 2 items, we can use ArrayInitDotTwo/StructInitDotTwo;2440 // If there are 0, 1, or 2 items, we can use ArrayInitDotTwo/StructInitDotTwo;
2555 // otherwise we use the full ArrayInitDot/StructInitDot.2441 // otherwise we use the full ArrayInitDot/StructInitDot.
25562442
2557 if (p.eatToken(.r_brace)) |_| {2443 const scratch_top = p.scratch.items.len;
2558 return p.addNode(.{2444 defer p.scratch.shrinkRetainingCapacity(scratch_top);
2559 .tag = .struct_init_dot_two,2445 const field_init = try p.parseFieldInit();
2560 .main_token = lbrace,2446 if (field_init != 0) {
2561 .data = .{2447 try p.scratch.append(p.gpa, field_init);
2562 .lhs = 0,2448 while (true) {
2563 .rhs = 0,2449 switch (p.token_tags[p.tok_i]) {
2564 },2450 .comma => p.tok_i += 1,
2565 });2451 .r_brace => { p.tok_i += 1; break; },
2566 }2452 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2567 const field_init_one = try p.parseFieldInit();2453 // Likely just a missing comma; give error but continue parsing.
2568 if (field_init_one != 0) {2454 else => try p.warnExpected(.comma),
2569 const comma_one = p.eatToken(.comma);2455 }
2570 if (p.eatToken(.r_brace)) |_| {2456 if (p.eatToken(.r_brace)) |_| break;
2571 return p.addNode(.{2457 const next = try p.expectFieldInit();
2572 .tag = if (comma_one != null) .struct_init_dot_two_comma else .struct_init_dot_two,2458 try p.scratch.append(p.gpa, next);
2459 }
2460 const comma = (p.token_tags[p.tok_i - 2] == .comma);
2461 const inits = p.scratch.items[scratch_top..];
2462 switch (inits.len) {
2463 0 => unreachable,
2464 1 => return p.addNode(.{
2465 .tag = if (comma) .struct_init_dot_two_comma else .struct_init_dot_two,
2573 .main_token = lbrace,2466 .main_token = lbrace,
2574 .data = .{2467 .data = .{
2575 .lhs = field_init_one,2468 .lhs = inits[0],
2576 .rhs = 0,2469 .rhs = 0,
2577 },2470 },
2578 });2471 }),
2579 }2472 2 => return p.addNode(.{
2580 if (comma_one == null) {2473 .tag = if (comma) .struct_init_dot_two_comma else .struct_init_dot_two,
2581 try p.warnExpected(.comma);
2582 }
2583 const field_init_two = try p.expectFieldInit();
2584 const comma_two = p.eatToken(.comma);
2585 if (p.eatToken(.r_brace)) |_| {
2586 return p.addNode(.{
2587 .tag = if (comma_two != null) .struct_init_dot_two_comma else .struct_init_dot_two,
2588 .main_token = lbrace,2474 .main_token = lbrace,
2589 .data = .{2475 .data = .{
2590 .lhs = field_init_one,2476 .lhs = inits[0],
2591 .rhs = field_init_two,2477 .rhs = inits[1],
2592 },2478 },
2593 });2479 }),
2594 }2480 else => {
2595 if (comma_two == null) {2481 const span = try p.listToSpan(inits);
2596 try p.warnExpected(.comma);2482 return p.addNode(.{
2483 .tag = if (comma) .struct_init_dot_comma else .struct_init_dot,
2484 .main_token = lbrace,
2485 .data = .{
2486 .lhs = span.start,
2487 .rhs = span.end,
2488 },
2489 });
2490 },
2597 }2491 }
2598 const scratch_top = p.scratch.items.len;2492 }
2599 defer p.scratch.shrinkRetainingCapacity(scratch_top);
2600
2601 try p.scratch.appendSlice(p.gpa, &.{ field_init_one, field_init_two });
26022493
2603 while (true) {2494 while (true) {
2604 const next = try p.expectFieldInit();2495 if (p.eatToken(.r_brace)) |_| break;
2605 assert(next != 0);2496 const elem_init = try p.expectExpr();
2606 try p.scratch.append(p.gpa, next);2497 try p.scratch.append(p.gpa, elem_init);
2607 switch (p.token_tags[p.nextToken()]) {2498 switch (p.token_tags[p.tok_i]) {
2608 .comma => {2499 .comma => p.tok_i += 1,
2609 if (p.eatToken(.r_brace)) |_| break;2500 .r_brace => { p.tok_i += 1; break; },
2610 continue;2501 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2611 },2502 // Likely just a missing comma; give error but continue parsing.
2612 .r_brace => break,2503 else => try p.warnExpected(.comma),
2613 .colon, .r_paren, .r_bracket => {
2614 p.tok_i -= 1;
2615 return p.failExpected(.r_brace);
2616 },
2617 else => {
2618 p.tok_i -= 1;
2619 try p.warnExpected(.comma);
2620 },
2621 }
2622 }2504 }
2623 const span = try p.listToSpan(p.scratch.items[scratch_top..]);2505 }
2624 const trailing_comma = p.token_tags[p.tok_i - 2] == .comma;2506 const comma = (p.token_tags[p.tok_i - 2] == .comma);
2625 return p.addNode(.{2507 const inits = p.scratch.items[scratch_top..];
2626 .tag = if (trailing_comma) .struct_init_dot_comma else .struct_init_dot,2508 switch (inits.len) {
2509 0 => return p.addNode(.{
2510 .tag = .struct_init_dot_two,
2627 .main_token = lbrace,2511 .main_token = lbrace,
2628 .data = .{2512 .data = .{
2629 .lhs = span.start,2513 .lhs = 0,
2630 .rhs = span.end,2514 .rhs = 0,
2631 },2515 },
2632 });2516 }),
2633 }2517 1 => return p.addNode(.{
26342518 .tag = if (comma) .array_init_dot_two_comma else .array_init_dot_two,
2635 const elem_init_one = try p.expectExpr();
2636 const comma_one = p.eatToken(.comma);
2637 if (p.eatToken(.r_brace)) |_| {
2638 return p.addNode(.{
2639 .tag = if (comma_one != null) .array_init_dot_two_comma else .array_init_dot_two,
2640 .main_token = lbrace,2519 .main_token = lbrace,
2641 .data = .{2520 .data = .{
2642 .lhs = elem_init_one,2521 .lhs = inits[0],
2643 .rhs = 0,2522 .rhs = 0,
2644 },2523 },
2645 });2524 }),
2646 }2525 2 => return p.addNode(.{
2647 if (comma_one == null) {2526 .tag = if (comma) .array_init_dot_two_comma else .array_init_dot_two,
2648 try p.warnExpected(.comma);
2649 }
2650 const elem_init_two = try p.expectExpr();
2651 const comma_two = p.eatToken(.comma);
2652 if (p.eatToken(.r_brace)) |_| {
2653 return p.addNode(.{
2654 .tag = if (comma_two != null) .array_init_dot_two_comma else .array_init_dot_two,
2655 .main_token = lbrace,2527 .main_token = lbrace,
2656 .data = .{2528 .data = .{
2657 .lhs = elem_init_one,2529 .lhs = inits[0],
2658 .rhs = elem_init_two,2530 .rhs = inits[1],
2659 },
2660 });
2661 }
2662 if (comma_two == null) {
2663 try p.warnExpected(.comma);
2664 }
2665 const scratch_top = p.scratch.items.len;
2666 defer p.scratch.shrinkRetainingCapacity(scratch_top);
2667
2668 try p.scratch.appendSlice(p.gpa, &.{ elem_init_one, elem_init_two });
2669
2670 while (true) {
2671 const next = try p.expectExpr();
2672 if (next == 0) break;
2673 try p.scratch.append(p.gpa, next);
2674 switch (p.token_tags[p.nextToken()]) {
2675 .comma => {
2676 if (p.eatToken(.r_brace)) |_| break;
2677 continue;
2678 },
2679 .r_brace => break,
2680 .colon, .r_paren, .r_bracket => {
2681 p.tok_i -= 1;
2682 return p.failExpected(.r_brace);
2683 },2531 },
2684 else => {2532 }),
2685 p.tok_i -= 1;2533 else => {
2686 try p.warnExpected(.comma);2534 const span = try p.listToSpan(inits);
2687 },2535 return p.addNode(.{
2688 }2536 .tag = if (comma) .array_init_dot_comma else .array_init_dot,
2689 }2537 .main_token = lbrace,
2690 const span = try p.listToSpan(p.scratch.items[scratch_top..]);2538 .data = .{
2691 return p.addNode(.{2539 .lhs = span.start,
2692 .tag = if (p.token_tags[p.tok_i - 2] == .comma) .array_init_dot_comma else .array_init_dot,2540 .rhs = span.end,
2693 .main_token = lbrace,2541 },
2694 .data = .{2542 });
2695 .lhs = span.start,
2696 .rhs = span.end,
2697 },2543 },
2698 });2544 }
2699 },2545 },
2700 else => return null_node,2546 else => return null_node,
2701 },2547 },
...@@ -2703,37 +2549,16 @@ const Parser = struct {...@@ -2703,37 +2549,16 @@ const Parser = struct {
2703 .l_brace => {2549 .l_brace => {
2704 const error_token = p.tok_i;2550 const error_token = p.tok_i;
2705 p.tok_i += 2;2551 p.tok_i += 2;
2706
2707 if (p.eatToken(.r_brace)) |rbrace| {
2708 return p.addNode(.{
2709 .tag = .error_set_decl,
2710 .main_token = error_token,
2711 .data = .{
2712 .lhs = undefined,
2713 .rhs = rbrace,
2714 },
2715 });
2716 }
2717
2718 while (true) {2552 while (true) {
2553 if (p.eatToken(.r_brace)) |_| break;
2719 const doc_comment = try p.eatDocComments();2554 const doc_comment = try p.eatDocComments();
2720 const identifier = try p.expectToken(.identifier);2555 const identifier = try p.expectToken(.identifier);
2721 switch (p.token_tags[p.nextToken()]) {2556 switch (p.token_tags[p.tok_i]) {
2722 .comma => {2557 .comma => p.tok_i += 1,
2723 if (p.eatToken(.r_brace)) |_| break;2558 .r_brace => { p.tok_i += 1; break; },
2724 continue;2559 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2725 },2560 // Likely just a missing comma; give error but continue parsing.
2726 .r_brace => break,2561 else => try p.warnExpected(.comma),
2727 .colon, .r_paren, .r_bracket => {
2728 p.tok_i -= 1;
2729 return p.failExpected(.r_brace);
2730 },
2731 else => {
2732 // This is likely just a missing comma;
2733 // give an error but continue parsing this list.
2734 p.tok_i -= 1;
2735 try p.warnExpected(.comma);
2736 },
2737 }2562 }
2738 }2563 }
2739 return p.addNode(.{2564 return p.addNode(.{
...@@ -2791,7 +2616,7 @@ const Parser = struct {...@@ -2791,7 +2616,7 @@ const Parser = struct {
2791 const found_payload = try p.parsePtrIndexPayload();2616 const found_payload = try p.parsePtrIndexPayload();
2792 if (found_payload == 0) try p.warn(.expected_loop_payload);2617 if (found_payload == 0) try p.warn(.expected_loop_payload);
27932618
2794 const then_expr = try p.expectExpr();2619 const then_expr = try p.expectTypeExpr();
2795 const else_token = p.eatToken(.keyword_else) orelse {2620 const else_token = p.eatToken(.keyword_else) orelse {
2796 return p.addNode(.{2621 return p.addNode(.{
2797 .tag = .for_simple,2622 .tag = .for_simple,
...@@ -2926,12 +2751,10 @@ const Parser = struct {...@@ -2926,12 +2751,10 @@ const Parser = struct {
2926 try p.scratch.append(p.gpa, output_item);2751 try p.scratch.append(p.gpa, output_item);
2927 switch (p.token_tags[p.tok_i]) {2752 switch (p.token_tags[p.tok_i]) {
2928 .comma => p.tok_i += 1,2753 .comma => p.tok_i += 1,
2929 .colon, .r_paren, .r_brace, .r_bracket => break, // All possible delimiters.2754 // All possible delimiters.
2930 else => {2755 .colon, .r_paren, .r_brace, .r_bracket => break,
2931 // This is likely just a missing comma;2756 // Likely just a missing comma; give error but continue parsing.
2932 // give an error but continue parsing this list.2757 else => try p.warnExpected(.comma),
2933 try p.warnExpected(.comma);
2934 },
2935 }2758 }
2936 }2759 }
2937 if (p.eatToken(.colon)) |_| {2760 if (p.eatToken(.colon)) |_| {
...@@ -2941,12 +2764,10 @@ const Parser = struct {...@@ -2941,12 +2764,10 @@ const Parser = struct {
2941 try p.scratch.append(p.gpa, input_item);2764 try p.scratch.append(p.gpa, input_item);
2942 switch (p.token_tags[p.tok_i]) {2765 switch (p.token_tags[p.tok_i]) {
2943 .comma => p.tok_i += 1,2766 .comma => p.tok_i += 1,
2944 .colon, .r_paren, .r_brace, .r_bracket => break, // All possible delimiters.2767 // All possible delimiters.
2945 else => {2768 .colon, .r_paren, .r_brace, .r_bracket => break,
2946 // This is likely just a missing comma;2769 // Likely just a missing comma; give error but continue parsing.
2947 // give an error but continue parsing this list.2770 else => try p.warnExpected(.comma),
2948 try p.warnExpected(.comma);
2949 },
2950 }2771 }
2951 }2772 }
2952 if (p.eatToken(.colon)) |_| {2773 if (p.eatToken(.colon)) |_| {
...@@ -2954,11 +2775,8 @@ const Parser = struct {...@@ -2954,11 +2775,8 @@ const Parser = struct {
2954 switch (p.token_tags[p.tok_i]) {2775 switch (p.token_tags[p.tok_i]) {
2955 .comma => p.tok_i += 1,2776 .comma => p.tok_i += 1,
2956 .colon, .r_paren, .r_brace, .r_bracket => break,2777 .colon, .r_paren, .r_brace, .r_bracket => break,
2957 else => {2778 // Likely just a missing comma; give error but continue parsing.
2958 // This is likely just a missing comma;2779 else => try p.warnExpected(.comma),
2959 // give an error but continue parsing this list.
2960 try p.warnExpected(.comma);
2961 },
2962 }2780 }
2963 }2781 }
2964 }2782 }
...@@ -3158,56 +2976,48 @@ const Parser = struct {...@@ -3158,56 +2976,48 @@ const Parser = struct {
3158 /// <- SwitchItem (COMMA SwitchItem)* COMMA?2976 /// <- SwitchItem (COMMA SwitchItem)* COMMA?
3159 /// / KEYWORD_else2977 /// / KEYWORD_else
3160 fn parseSwitchProng(p: *Parser) !Node.Index {2978 fn parseSwitchProng(p: *Parser) !Node.Index {
3161 if (p.eatToken(.keyword_else)) |_| {2979 const scratch_top = p.scratch.items.len;
3162 const arrow_token = try p.expectToken(.equal_angle_bracket_right);2980 defer p.scratch.shrinkRetainingCapacity(scratch_top);
3163 _ = try p.parsePtrPayload();2981
3164 return p.addNode(.{2982 if (p.eatToken(.keyword_else) == null) {
2983 while (true) {
2984 const item = try p.parseSwitchItem();
2985 if (item == 0) break;
2986 try p.scratch.append(p.gpa, item);
2987 if (p.eatToken(.comma) == null) break;
2988 }
2989 if (scratch_top == p.scratch.items.len) return null_node;
2990 }
2991 const arrow_token = try p.expectToken(.equal_angle_bracket_right);
2992 _ = try p.parsePtrPayload();
2993
2994 const items = p.scratch.items[scratch_top..];
2995 switch(items.len) {
2996 0 => return p.addNode(.{
3165 .tag = .switch_case_one,2997 .tag = .switch_case_one,
3166 .main_token = arrow_token,2998 .main_token = arrow_token,
3167 .data = .{2999 .data = .{
3168 .lhs = 0,3000 .lhs = 0,
3169 .rhs = try p.expectAssignExpr(),3001 .rhs = try p.expectAssignExpr(),
3170 },3002 }
3171 });3003 }),
3172 }3004 1 => return p.addNode(.{
3173 const first_item = try p.parseSwitchItem();
3174 if (first_item == 0) return null_node;
3175
3176 if (p.eatToken(.equal_angle_bracket_right)) |arrow_token| {
3177 _ = try p.parsePtrPayload();
3178 return p.addNode(.{
3179 .tag = .switch_case_one,3005 .tag = .switch_case_one,
3180 .main_token = arrow_token,3006 .main_token = arrow_token,
3181 .data = .{3007 .data = .{
3182 .lhs = first_item,3008 .lhs = items[0],
3009 .rhs = try p.expectAssignExpr(),
3010 }
3011 }),
3012 else => return p.addNode(.{
3013 .tag = .switch_case,
3014 .main_token = arrow_token,
3015 .data = .{
3016 .lhs = try p.addExtra(try p.listToSpan(items)),
3183 .rhs = try p.expectAssignExpr(),3017 .rhs = try p.expectAssignExpr(),
3184 },3018 },
3185 });3019 }),
3186 }
3187
3188 const scratch_top = p.scratch.items.len;
3189 defer p.scratch.shrinkRetainingCapacity(scratch_top);
3190
3191 try p.scratch.append(p.gpa, first_item);
3192 while (p.eatToken(.comma)) |_| {
3193 const next_item = try p.parseSwitchItem();
3194 if (next_item == 0) break;
3195 try p.scratch.append(p.gpa, next_item);
3196 }3020 }
3197 const span = try p.listToSpan(p.scratch.items[scratch_top..]);
3198 const arrow_token = try p.expectToken(.equal_angle_bracket_right);
3199 _ = try p.parsePtrPayload();
3200 return p.addNode(.{
3201 .tag = .switch_case,
3202 .main_token = arrow_token,
3203 .data = .{
3204 .lhs = try p.addExtra(Node.SubRange{
3205 .start = span.start,
3206 .end = span.end,
3207 }),
3208 .rhs = try p.expectAssignExpr(),
3209 },
3210 });
3211 }3021 }
32123022
3213 /// SwitchItem <- Expr (DOT3 Expr)?3023 /// SwitchItem <- Expr (DOT3 Expr)?
...@@ -3563,19 +3373,12 @@ const Parser = struct {...@@ -3563,19 +3373,12 @@ const Parser = struct {
3563 } else if (p.token_tags[p.tok_i - 1] == .ellipsis3) {3373 } else if (p.token_tags[p.tok_i - 1] == .ellipsis3) {
3564 if (varargs == .none) varargs = .seen;3374 if (varargs == .none) varargs = .seen;
3565 }3375 }
3566 switch (p.token_tags[p.nextToken()]) {3376 switch (p.token_tags[p.tok_i]) {
3567 .comma => {},3377 .comma => p.tok_i += 1,
3568 .r_paren => break,3378 .r_paren => { p.tok_i += 1; break; },
3569 .colon, .r_brace, .r_bracket => {3379 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
3570 p.tok_i -= 1;3380 // Likely just a missing comma; give error but continue parsing.
3571 return p.failExpected(.r_paren);3381 else => try p.warnExpected(.comma),
3572 },
3573 else => {
3574 // This is likely just a missing comma;
3575 // give an error but continue parsing this list.
3576 p.tok_i -= 1;
3577 try p.warnExpected(.comma);
3578 },
3579 }3382 }
3580 }3383 }
3581 if (varargs == .nonfinal) {3384 if (varargs == .nonfinal) {
...@@ -3605,13 +3408,10 @@ const Parser = struct {...@@ -3605,13 +3408,10 @@ const Parser = struct {
36053408
3606 switch (p.token_tags[p.tok_i]) {3409 switch (p.token_tags[p.tok_i]) {
3607 .comma => p.tok_i += 1,3410 .comma => p.tok_i += 1,
3608 // all possible delimiters3411 // All possible delimiters.
3609 .colon, .r_paren, .r_brace, .r_bracket => break,3412 .colon, .r_paren, .r_brace, .r_bracket => break,
3610 else => {3413 // Likely just a missing comma; give error but continue parsing.
3611 // This is likely just a missing comma;3414 else => try p.warnExpected(.comma),
3612 // give an error but continue parsing this list.
3613 try p.warnExpected(.comma);
3614 },
3615 }3415 }
3616 }3416 }
3617 return p.listToSpan(p.scratch.items[scratch_top..]);3417 return p.listToSpan(p.scratch.items[scratch_top..]);
...@@ -3636,117 +3436,58 @@ const Parser = struct {...@@ -3636,117 +3436,58 @@ const Parser = struct {
3636 },3436 },
3637 });3437 });
3638 }3438 }
3639 if (p.eatToken(.r_paren)) |_| {3439 const scratch_top = p.scratch.items.len;
3640 return p.addNode(.{3440 defer p.scratch.shrinkRetainingCapacity(scratch_top);
3441 while (true) {
3442 if (p.eatToken(.r_paren)) |_| break;
3443 const param = try p.expectExpr();
3444 try p.scratch.append(p.gpa, param);
3445 switch (p.token_tags[p.tok_i]) {
3446 .comma => p.tok_i += 1,
3447 .r_paren => { p.tok_i += 1; break; },
3448 // Likely just a missing comma; give error but continue parsing.
3449 else => try p.warnExpected(.comma),
3450 }
3451 }
3452 const comma = (p.token_tags[p.tok_i - 2] == .comma);
3453 const params = p.scratch.items[scratch_top..];
3454 switch (params.len) {
3455 0 => return p.addNode(.{
3641 .tag = .builtin_call_two,3456 .tag = .builtin_call_two,
3642 .main_token = builtin_token,3457 .main_token = builtin_token,
3643 .data = .{3458 .data = .{
3644 .lhs = 0,3459 .lhs = 0,
3645 .rhs = 0,3460 .rhs = 0,
3646 },3461 },
3647 });3462 }),
3648 }3463 1 => return p.addNode(.{
3649 const param_one = try p.expectExpr();3464 .tag = if (comma) .builtin_call_two_comma else .builtin_call_two,
3650 switch (p.token_tags[p.nextToken()]) {
3651 .comma => {
3652 if (p.eatToken(.r_paren)) |_| {
3653 return p.addNode(.{
3654 .tag = .builtin_call_two_comma,
3655 .main_token = builtin_token,
3656 .data = .{
3657 .lhs = param_one,
3658 .rhs = 0,
3659 },
3660 });
3661 }
3662 },
3663 .r_paren => return p.addNode(.{
3664 .tag = .builtin_call_two,
3665 .main_token = builtin_token,3465 .main_token = builtin_token,
3666 .data = .{3466 .data = .{
3667 .lhs = param_one,3467 .lhs = params[0],
3668 .rhs = 0,3468 .rhs = 0,
3669 },3469 },
3670 }),3470 }),
3671 else => {3471 2 => return p.addNode(.{
3672 // This is likely just a missing comma;3472 .tag = if (comma) .builtin_call_two_comma else .builtin_call_two,
3673 // give an error but continue parsing this list.
3674 p.tok_i -= 1;
3675 try p.warnExpected(.comma);
3676 },
3677 }
3678 const param_two = try p.expectExpr();
3679 switch (p.token_tags[p.nextToken()]) {
3680 .comma => {
3681 if (p.eatToken(.r_paren)) |_| {
3682 return p.addNode(.{
3683 .tag = .builtin_call_two_comma,
3684 .main_token = builtin_token,
3685 .data = .{
3686 .lhs = param_one,
3687 .rhs = param_two,
3688 },
3689 });
3690 }
3691 },
3692 .r_paren => return p.addNode(.{
3693 .tag = .builtin_call_two,
3694 .main_token = builtin_token,3473 .main_token = builtin_token,
3695 .data = .{3474 .data = .{
3696 .lhs = param_one,3475 .lhs = params[0],
3697 .rhs = param_two,3476 .rhs = params[1],
3698 },3477 },
3699 }),3478 }),
3700 else => {3479 else => {
3701 // This is likely just a missing comma;3480 const span = try p.listToSpan(params);
3702 // give an error but continue parsing this list.3481 return p.addNode(.{
3703 p.tok_i -= 1;3482 .tag = if (comma) .builtin_call_comma else .builtin_call,
3704 try p.warnExpected(.comma);3483 .main_token = builtin_token,
3484 .data = .{
3485 .lhs = span.start,
3486 .rhs = span.end,
3487 },
3488 });
3705 },3489 },
3706 }3490 }
3707
3708 const scratch_top = p.scratch.items.len;
3709 defer p.scratch.shrinkRetainingCapacity(scratch_top);
3710
3711 try p.scratch.appendSlice(p.gpa, &.{ param_one, param_two });
3712
3713 while (true) {
3714 const param = try p.expectExpr();
3715 try p.scratch.append(p.gpa, param);
3716 switch (p.token_tags[p.nextToken()]) {
3717 .comma => {
3718 if (p.eatToken(.r_paren)) |_| {
3719 const params = try p.listToSpan(p.scratch.items[scratch_top..]);
3720 return p.addNode(.{
3721 .tag = .builtin_call_comma,
3722 .main_token = builtin_token,
3723 .data = .{
3724 .lhs = params.start,
3725 .rhs = params.end,
3726 },
3727 });
3728 }
3729 continue;
3730 },
3731 .r_paren => {
3732 const params = try p.listToSpan(p.scratch.items[scratch_top..]);
3733 return p.addNode(.{
3734 .tag = .builtin_call,
3735 .main_token = builtin_token,
3736 .data = .{
3737 .lhs = params.start,
3738 .rhs = params.end,
3739 },
3740 });
3741 },
3742 else => {
3743 // This is likely just a missing comma;
3744 // give an error but continue parsing this list.
3745 p.tok_i -= 1;
3746 try p.warnExpected(.comma);
3747 },
3748 }
3749 }
3750 }3491 }
37513492
3752 // string literal or multiline string literal3493 // string literal or multiline string literal
lib/std/zig/parser_test.zig+1-1
...@@ -5154,7 +5154,7 @@ test "recovery: missing for payload" {...@@ -5154,7 +5154,7 @@ test "recovery: missing for payload" {
5154 try testError(5154 try testError(
5155 \\comptime {5155 \\comptime {
5156 \\ const a = for(a) {};5156 \\ const a = for(a) {};
5157 \\ const a: for(a) {};5157 \\ const a: for(a) blk: {};
5158 \\ for(a) {}5158 \\ for(a) {}
5159 \\}5159 \\}
5160 , &[_]Error{5160 , &[_]Error{