Some minor refactors to improve building performance
Getty Ritter
6 years ago
194 | 194 | -- s-expressions, then we might as well consider it flat and let |
195 | 195 | -- it take the whole line |
196 | 196 | | Just strings <- T.traverse ppBasic (initial Seq.<| values) = |
197 |
Seq.singleton (B. |
|
197 | Seq.singleton (B.singleton '(' <> buildUnwords strings <> pTail rest) | |
198 | 198 | |
199 | 199 | -- it's not "flat", so we might want to swing after the first thing |
200 | 200 | | Swing <- iv = |
206 | 206 | -- ...or after several things |
207 | 207 | | SwingAfter n <- iv = |
208 | 208 | let (hs, xs) = Seq.splitAt n (initial Seq.<| values) |
209 |
hd = B. |
|
209 | hd = B.singleton '(' <> buildUnwords (F.foldMap go hs) | |
210 | 210 | butLast = hd Seq.<| fmap doIndent (F.foldMap go xs) |
211 | 211 | in handleTail rest butLast |
212 | 212 | |
229 | 229 | -- with spaces and everything else gets indended the |
230 | 230 | -- forementioned length |
231 | 231 | y Seq.:< ys -> |
232 |
let hd = B. |
|
232 | let hd = B.singleton '(' <> buildUnwords (F.foldMap go (Seq.fromList [initial, y])) | |
233 | 233 | butLast = hd Seq.<| fmap (doIndentOf (fromIntegral len)) (F.foldMap go ys) |
234 | 234 | in handleTail rest butLast |
235 | 235 | |
242 | 242 | insertParen :: Seq.Seq B.Builder -> Seq.Seq B.Builder |
243 | 243 | insertParen s = case Seq.viewl s of |
244 | 244 | Seq.EmptyL -> s |
245 |
x Seq.:< xs -> (B. |
|
245 | x Seq.:< xs -> (B.singleton '(' <> x) Seq.<| xs | |
246 | 246 | |
247 | 247 | handleTail :: Maybe Text -> Seq.Seq B.Builder -> Seq.Seq B.Builder |
248 | 248 | handleTail Nothing = insertCloseParen |
249 | 249 | handleTail (Just t) = |
250 |
(Seq.|> (B.fromString " . " <> B.fromText t <> B. |
|
250 | (Seq.|> (B.fromString " . " <> B.fromText t <> B.singleton ')')) | |
251 | 251 | |
252 | 252 | insertCloseParen :: Seq.Seq B.Builder -> Seq.Seq B.Builder |
253 | 253 | insertCloseParen s = case Seq.viewr s of |
254 | Seq.EmptyR -> Seq.singleton (B.fromString ")") | |
255 | xs Seq.:> x -> xs Seq.|> (x <> B.fromString ")") | |
254 | Seq.EmptyR -> Seq.singleton (B.singleton ')') | |
255 | xs Seq.:> x -> xs Seq.|> (x <> B.singleton ')') | |
256 | 256 | |
257 | 257 | buildUnwords sq = |
258 | 258 | case Seq.viewl sq of |
259 | 259 | Seq.EmptyL -> mempty |
260 | t Seq.:< ts -> t <> F.foldMap (\ x -> B.fromString " " <> x) ts | |
261 | ||
262 | pTail Nothing = B.fromString ")" | |
263 | pTail (Just t) = B.fromString " . " <> B.fromText t <> B.fromString ")" | |
260 | t Seq.:< ts -> t <> F.foldMap (\ x -> B.singleton ' ' <> x) ts | |
261 | ||
262 | pTail Nothing = B.singleton ')' | |
263 | pTail (Just t) = B.fromString " . " <> B.fromText t <> B.singleton ')' | |
264 | 264 | |
265 | 265 | ppBasic (IAtom t) = Just (B.fromText t) |
266 | 266 | ppBasic (IEmpty) = Just (B.fromString "()") |
324 | 324 | setIndentStrategy st pr = pr { swingIndent = st } |
325 | 325 | |
326 | 326 | |
327 | spaceDot :: B.Builder | |
328 | spaceDot = B.singleton ' ' <> B.singleton '.' <> B.singleton ' ' | |
329 | ||
327 | 330 | -- Indents a line by n spaces |
328 | 331 | indent :: Int -> B.Builder -> B.Builder |
329 |
indent n ts = |
|
332 | indent n ts = | |
333 | mconcat [ B.singleton ' ' | _ <- [1..n]] <> ts | |
330 | 334 | |
331 | 335 | |
332 | 336 | -- Sort of like 'unlines' but without the trailing newline |
386 | 390 | pp ind (IList i sz h values end) = |
387 | 391 | -- we always are going to have a head, a (possibly empty) body, |
388 | 392 | -- and a (possibly empty) tail in our list formats |
389 |
B. |
|
393 | B.singleton '(' <> hd <> body <> tl <> B.singleton ')' | |
390 | 394 | where |
391 | 395 | -- the tail is either nothing, or the final dotted pair |
392 | 396 | tl = case end of |
416 | 420 | | length values == 0 = mempty |
417 | 421 | -- if we can't fit the whole next s-expression on the same |
418 | 422 | -- line, then we use the indented form |
419 |
| sizeSum sz + ind > maxAmt = B. |
|
423 | | sizeSum sz + ind > maxAmt = B.singleton ' ' <> indented | |
420 | 424 | | otherwise = |
421 | 425 | -- otherwise we print the whole thing on one line! |
422 |
B. |
|
426 | B.singleton ' ' <> unwordsS (fmap (pp (ind + 1)) values) | |
423 | 427 | |
424 | 428 | |
425 | 429 | -- if we don't indent anything, then we can ignore a bunch of the |
428 | 432 | flatPrintSExpr = B.toLazyText . pHead |
429 | 433 | where |
430 | 434 | pHead (SCons x xs) = |
431 |
B. |
|
435 | B.singleton '(' <> pHead x <> pTail xs | |
432 | 436 | pHead (SAtom t) = |
433 | 437 | B.fromText t |
434 | 438 | pHead SNil = |
435 |
B. |
|
439 | B.singleton '(' <> B.singleton ')' | |
436 | 440 | |
437 | 441 | pTail (SCons x xs) = |
438 |
B. |
|
442 | B.singleton ' ' <> pHead x <> pTail xs | |
439 | 443 | pTail (SAtom t) = |
440 |
|
|
444 | spaceDot <> | |
445 | B.fromText t <> | |
446 | B.singleton ')' | |
441 | 447 | pTail SNil = |
442 |
B. |
|
448 | B.singleton ')' | |
449 | ||
443 | 450 | |
444 | 451 | -- | Turn a single s-expression into a string according to a given |
445 | 452 | -- 'SExprPrinter'. |
447 | 454 | encodeOne s@(SExprPrinter { .. }) = |
448 | 455 | TL.toStrict . prettyPrintSExpr (s { fromCarrier = id }) . fromCarrier |
449 | 456 | |
457 | ||
450 | 458 | -- | Turn a list of s-expressions into a single string according to |
451 | 459 | -- a given 'SExprPrinter'. |
452 | 460 | encode :: SExprPrinter atom carrier -> [carrier] -> Text |
453 | 461 | encode spec = |
454 | 462 | T.intercalate "\n\n" . map (encodeOne spec) |
455 | 463 | |
464 | ||
456 | 465 | -- | Turn a single s-expression into a lazy 'Text' according to a given |
457 | 466 | -- 'SExprPrinter'. |
458 | 467 | encodeOneLazy :: SExprPrinter atom carrier -> carrier -> TL.Text |
459 | 468 | encodeOneLazy s@(SExprPrinter { .. }) = |
460 | 469 | prettyPrintSExpr (s { fromCarrier = id }) . fromCarrier |
461 | 470 | |
471 | ||
462 | 472 | -- | Turn a list of s-expressions into a lazy 'Text' according to |
463 | 473 | -- a given 'SExprPrinter'. |
464 | 474 | encodeLazy :: SExprPrinter atom carrier -> [carrier] -> TL.Text |