... | ... | @@ -441,7 +441,7 @@ One might argue that this makes our AST less abstract, so it’s actually a conc |
|
|
data LetKeywords = LK { lkLet :: AnnAnchor, lkIn :: AnnAnchor }
|
|
|
```
|
|
|
|
|
|
* Plan B, directly storing info in the syntax tree:
|
|
|
* Plan B1, directly storing info in the syntax tree:
|
|
|
|
|
|
```
|
|
|
-- In the shared code base, Language.Haskell.Syntax.Expr
|
... | ... | @@ -453,6 +453,13 @@ One might argue that this makes our AST less abstract, so it’s actually a conc |
|
|
|
|
|
Here the "let" parameter to LHsToken is entirely phantom, present mostly for documentation reasons.
|
|
|
|
|
|
* Plan B2, puts all the tokens in a single tuple field, thus:
|
|
|
```
|
|
|
data HsExpr p = HsLet (XLet p) -- Extension field
|
|
|
(LHsToken "let" p, LHsToken "in" p) -- Tokens
|
|
|
(HsLocalBinds p) (HsExpr p) -- Main payload
|
|
|
| ...
|
|
|
```
|
|
|
Let's see the pros and cons (Simon’s analysis):
|
|
|
|
|
|
* The big change is that the tokens become part of the (client-independent) syntax tree, in
|
... | ... | @@ -460,15 +467,18 @@ Let's see the pros and cons (Simon’s analysis): |
|
|
|
|
|
* With Plan A, clients can completely ignore all the exact-print
|
|
|
stuff. With Plan B they have to handle those fields, if only to
|
|
|
pass them on.
|
|
|
pass them on. With Plan B2 that is not too bad (one field), but it's pretty tiresome with Plan B1
|
|
|
|
|
|
* Plan B allocates more: every data construtor gets more fields, and each pass needs to copy those fields into a new copy of the construtor. Plan B2 is better than Plan B1 in this respect.
|
|
|
|
|
|
* With Plan B we can do exact-print in an almost GHC-free way,
|
|
|
provided only that we can extract enough info from the `XRec` thing.
|
|
|
provided only that we can extract enough info from the `XRec` thing. **SPJ asks**: what does it mean to "extract enough"? Without an actual design here I'm unsure what this means.
|
|
|
|
|
|
With Plan A, exact-print is deeply tied to GHC.
|
|
|
|
|
|
* Plan B has many, many fewer data types. And interspersing the
|
|
|
* Plan B1 has many fewer data types, at least if you define a `LetKeywords`-like type for each construct. An alternative would be to use a tuple as suggested in Plan B2; no new types. Interspersing the
|
|
|
tokens in the "right" place in the record (e.g. "let" then binds
|
|
|
then "in" then expression) is very perspicuous, much more so than a
|
|
|
then "in" then expression) is very perspicuous, rather more so than a
|
|
|
`lkLet` field in `LetKeywords`.
|
|
|
|
|
|
* Many GHC passes use those extension fields. With Plan A GHC will need
|
... | ... | |