| ... | ... | @@ -44,7 +44,6 @@ pub fn renderTree(buffer: *std.ArrayList(u8), tree: ast.Tree) Error!void { |
| 44 | 44 | /// Render all members in the given slice, keeping empty lines where appropriate |
| 45 | 45 | fn renderMembers(gpa: *Allocator, ais: *Ais, tree: ast.Tree, members: []const ast.Node.Index) Error!void { |
| 46 | 46 | if (members.len == 0) return; |
| 47 | | //try renderExtraNewline(ais, tree, members[0]); |
| 48 | 47 | try renderMember(gpa, ais, tree, members[0], .newline); |
| 49 | 48 | for (members[1..]) |member| { |
| 50 | 49 | try renderExtraNewline(ais, tree, member); |
| ... | ... | @@ -202,10 +201,8 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I |
| 202 | 201 | while (locked_indents > 0) : (locked_indents -= 1) ais.popIndent(); |
| 203 | 202 | |
| 204 | 203 | switch (space) { |
| 205 | | .none, .space, .newline => {}, |
| 206 | | .newline_pop => ais.popIndent(), |
| 204 | .none, .space, .newline, .skip => {}, |
| 207 | 205 | .semicolon => if (token_tags[i] == .semicolon) try renderToken(ais, tree, i, .newline), |
| 208 | | .semicolon_pop => if (token_tags[i] == .semicolon) try renderToken(ais, tree, i, .newline_pop), |
| 209 | 206 | .comma => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .newline), |
| 210 | 207 | .comma_space => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .space), |
| 211 | 208 | } |
| ... | ... | @@ -1147,15 +1144,11 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full. |
| 1147 | 1144 | } else { |
| 1148 | 1145 | try renderToken(ais, tree, while_node.else_token, .newline); // else |
| 1149 | 1146 | } |
| 1150 | | ais.pushIndent(); |
| 1151 | | try renderExpression(gpa, ais, tree, while_node.ast.else_expr, space); |
| 1152 | | ais.popIndent(); |
| 1147 | try renderExpressionIndented(gpa, ais, tree, while_node.ast.else_expr, space); |
| 1153 | 1148 | return; |
| 1154 | 1149 | } |
| 1155 | 1150 | } else { |
| 1156 | | ais.pushIndent(); |
| 1157 | | assert(space == .semicolon); |
| 1158 | | try renderExpression(gpa, ais, tree, while_node.ast.then_expr, .semicolon_pop); |
| 1151 | try renderExpressionIndented(gpa, ais, tree, while_node.ast.then_expr, space); |
| 1159 | 1152 | return; |
| 1160 | 1153 | } |
| 1161 | 1154 | } |
| ... | ... | @@ -2168,6 +2161,64 @@ fn renderCall( |
| 2168 | 2161 | return renderToken(ais, tree, after_last_param_tok, space); // ) |
| 2169 | 2162 | } |
| 2170 | 2163 | |
| 2164 | /// Renders the given expression indented, popping the indent before rendering |
| 2165 | /// any following line comments |
| 2166 | fn renderExpressionIndented(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void { |
| 2167 | const token_starts = tree.tokens.items(.start); |
| 2168 | const token_tags = tree.tokens.items(.tag); |
| 2169 | |
| 2170 | ais.pushIndent(); |
| 2171 | |
| 2172 | var last_token = tree.lastToken(node); |
| 2173 | const punctuation = switch (space) { |
| 2174 | .none, .space, .newline, .skip => false, |
| 2175 | .comma => true, |
| 2176 | .comma_space => token_tags[last_token + 1] == .comma, |
| 2177 | .semicolon => token_tags[last_token + 1] == .semicolon, |
| 2178 | }; |
| 2179 | |
| 2180 | try renderExpression(gpa, ais, tree, node, if (punctuation) .none else .skip); |
| 2181 | |
| 2182 | switch (space) { |
| 2183 | .none, .space, .newline, .skip => {}, |
| 2184 | .comma => { |
| 2185 | if (token_tags[last_token + 1] == .comma) { |
| 2186 | try renderToken(ais, tree, last_token + 1, .skip); |
| 2187 | last_token += 1; |
| 2188 | } else { |
| 2189 | try ais.writer().writeByte(','); |
| 2190 | } |
| 2191 | }, |
| 2192 | .comma_space => if (token_tags[last_token + 1] == .comma) { |
| 2193 | try renderToken(ais, tree, last_token + 1, .skip); |
| 2194 | last_token += 1; |
| 2195 | }, |
| 2196 | .semicolon => if (token_tags[last_token + 1] == .semicolon) { |
| 2197 | try renderToken(ais, tree, last_token + 1, .skip); |
| 2198 | last_token += 1; |
| 2199 | }, |
| 2200 | } |
| 2201 | |
| 2202 | ais.popIndent(); |
| 2203 | |
| 2204 | if (space == .skip) return; |
| 2205 | |
| 2206 | const comment_start = token_starts[last_token] + tokenSliceForRender(tree, last_token).len; |
| 2207 | const comment = try renderComments(ais, tree, comment_start, token_starts[last_token + 1]); |
| 2208 | |
| 2209 | if (!comment) switch (space) { |
| 2210 | .none => {}, |
| 2211 | .space, |
| 2212 | .comma_space, |
| 2213 | => try ais.writer().writeByte(' '), |
| 2214 | .newline, |
| 2215 | .comma, |
| 2216 | .semicolon, |
| 2217 | => try ais.insertNewline(), |
| 2218 | .skip => unreachable, |
| 2219 | }; |
| 2220 | } |
| 2221 | |
| 2171 | 2222 | /// Render an expression, and the comma that follows it, if it is present in the source. |
| 2172 | 2223 | fn renderExpressionComma(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void { |
| 2173 | 2224 | const token_tags = tree.tokens.items(.tag); |
| ... | ... | @@ -2198,9 +2249,6 @@ const Space = enum { |
| 2198 | 2249 | space, |
| 2199 | 2250 | /// Output the token lexeme followed by a newline. |
| 2200 | 2251 | newline, |
| 2201 | | /// Same as newline, but pop an indent level before rendering the |
| 2202 | | /// following comments if any. |
| 2203 | | newline_pop, |
| 2204 | 2252 | /// If the next token is a comma, render it as well. If not, insert one. |
| 2205 | 2253 | /// In either case, a newline will be inserted afterwards. |
| 2206 | 2254 | comma, |
| ... | ... | @@ -2210,9 +2258,9 @@ const Space = enum { |
| 2210 | 2258 | /// Additionally consume the next token if it is a semicolon. |
| 2211 | 2259 | /// In either case, a newline will be inserted afterwards. |
| 2212 | 2260 | semicolon, |
| 2213 | | /// Same as semicolon, but pop an indent level before rendering the |
| 2214 | | /// following comments if any. |
| 2215 | | semicolon_pop, |
| 2261 | /// Skip rendering whitespace and comments. If this is used, the caller |
| 2262 | /// *must* handle handle whitespace and comments manually. |
| 2263 | skip, |
| 2216 | 2264 | }; |
| 2217 | 2265 | |
| 2218 | 2266 | fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Space) Error!void { |
| ... | ... | @@ -2224,65 +2272,37 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp |
| 2224 | 2272 | |
| 2225 | 2273 | try ais.writer().writeAll(lexeme); |
| 2226 | 2274 | |
| 2227 | | const token_end = token_start + lexeme.len; |
| 2228 | | const next_token_start = token_starts[token_index + 1]; |
| 2229 | | switch (space) { |
| 2230 | | .none => _ = try renderComments(ais, tree, token_end, next_token_start), |
| 2231 | | |
| 2232 | | .space => if (!try renderComments(ais, tree, token_end, next_token_start)) { |
| 2233 | | try ais.writer().writeByte(' '); |
| 2234 | | }, |
| 2275 | if (space == .skip) return; |
| 2235 | 2276 | |
| 2236 | | .newline => if (!try renderComments(ais, tree, token_end, next_token_start)) { |
| 2237 | | try ais.insertNewline(); |
| 2238 | | }, |
| 2277 | if (space == .comma and token_tags[token_index + 1] != .comma) { |
| 2278 | try ais.writer().writeByte(','); |
| 2279 | } |
| 2239 | 2280 | |
| 2240 | | .newline_pop => { |
| 2241 | | ais.popIndent(); |
| 2242 | | if (!try renderComments(ais, tree, token_end, next_token_start)) { |
| 2243 | | try ais.insertNewline(); |
| 2244 | | } |
| 2245 | | }, |
| 2281 | const comment = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1]); |
| 2282 | switch (space) { |
| 2283 | .none => {}, |
| 2284 | .space => if (!comment) try ais.writer().writeByte(' '), |
| 2285 | .newline => if (!comment) try ais.insertNewline(), |
| 2246 | 2286 | |
| 2247 | 2287 | .comma => if (token_tags[token_index + 1] == .comma) { |
| 2248 | | _ = try renderComments(ais, tree, token_end, next_token_start); |
| 2249 | 2288 | try renderToken(ais, tree, token_index + 1, .newline); |
| 2250 | | } else { |
| 2251 | | try ais.writer().writeByte(','); |
| 2252 | | if (!try renderComments(ais, tree, token_end, next_token_start)) { |
| 2253 | | try ais.insertNewline(); |
| 2254 | | } |
| 2289 | } else if (!comment) { |
| 2290 | try ais.insertNewline(); |
| 2255 | 2291 | }, |
| 2256 | 2292 | |
| 2257 | | .comma_space => { |
| 2258 | | const comment = try renderComments(ais, tree, token_end, next_token_start); |
| 2259 | | if (token_tags[token_index + 1] == .comma) { |
| 2260 | | try renderToken(ais, tree, token_index + 1, .space); |
| 2261 | | } else if (!comment) { |
| 2262 | | try ais.writer().writeByte(' '); |
| 2263 | | } |
| 2293 | .comma_space => if (token_tags[token_index + 1] == .comma) { |
| 2294 | try renderToken(ais, tree, token_index + 1, .space); |
| 2295 | } else if (!comment) { |
| 2296 | try ais.writer().writeByte(' '); |
| 2264 | 2297 | }, |
| 2265 | 2298 | |
| 2266 | | .semicolon => { |
| 2267 | | const comment = try renderComments(ais, tree, token_end, next_token_start); |
| 2268 | | if (token_tags[token_index + 1] == .semicolon) { |
| 2269 | | try renderToken(ais, tree, token_index + 1, .newline); |
| 2270 | | } else if (!comment) { |
| 2271 | | try ais.insertNewline(); |
| 2272 | | } |
| 2299 | .semicolon => if (token_tags[token_index + 1] == .semicolon) { |
| 2300 | try renderToken(ais, tree, token_index + 1, .newline); |
| 2301 | } else if (!comment) { |
| 2302 | try ais.insertNewline(); |
| 2273 | 2303 | }, |
| 2274 | 2304 | |
| 2275 | | .semicolon_pop => { |
| 2276 | | if (token_tags[token_index + 1] == .semicolon) { |
| 2277 | | _ = try renderComments(ais, tree, token_end, next_token_start); |
| 2278 | | try renderToken(ais, tree, token_index + 1, .newline_pop); |
| 2279 | | } else { |
| 2280 | | ais.popIndent(); |
| 2281 | | if (!try renderComments(ais, tree, token_end, next_token_start)) { |
| 2282 | | try ais.insertNewline(); |
| 2283 | | } |
| 2284 | | } |
| 2285 | | }, |
| 2305 | .skip => unreachable, |
| 2286 | 2306 | } |
| 2287 | 2307 | } |
| 2288 | 2308 | |