-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Hi Patrick, thanks again for the demo.
Some stuff, that came to mind (in random order):
- The untyped tree is used to represent both valid and invalid code. That is why certain trivia will be represented as optional.
let astill gets parsed to a tree with errors:
trivia = {
LeadingKeyword = SynLeadingKeyword.Let(R("(1,0--1,3)"))
InlineKeyword = None
EqualsRange = None
}
Incomplete structured construct at or before this point in binding. Expected '=' or other token.We don't process any tree with errors (and certain warnings), so we can assume in ASTTransformer that stuff is just there. This means that you need to put in Some range0 in certain places. Just to tell Fantomas that the keyword is present.
We transform the ParsedInput to an Oak internally, to only print out the code again.
It is possible to print source code from an Oak, this is more convenient than the untyped tree.
I hoped that one day https://edgarfgp.github.io/Fabulous.AST/ would have taken off and become the recommended way to generate code.
-
I think as a rule of thumb, every token or keyword that you want to see in the output code should be present (as
Some range0). So, when generating a let binding, you know thatletand=should be in the tree. The same with commas in tuples,=in record fields. These days, there are few tokens not represented in the tree. -
Myriad seems like a bit of a mixed bag. I think it isn't that hard to cook up some tool that is similar to how the analyzers work. Crack a fsproj, get type-check information of a file and use Fantomas to generate a new file.
Did you ever explore other options?
- It is ok to take some shortcuts when generating code. For example:
#r "nuget: Fantomas.Core, 6.3.0-alpha-005"
open Fantomas.FCS.Syntax
let cheatABit (e: SynExpr) : SynBinding =
let source = "let a b = ()"
let parsedInput =
CodeFormatter.ParseAsync(false, source)
|> Async.RunSynchronously
|> Array.head
|> fst
match parsedInput with
| ParsedInput.ImplFile(ParsedImplFileInput(
contents = [ SynModuleOrNamespace(decls = [ SynModuleDecl.Let(bindings = [ b ]) ]) ])) ->
match b with
| SynBinding(accessibility,
kind,
isInline,
isMutable,
attributes,
xmlDoc,
valData,
headPat,
returnInfo,
_,
range,
debugPoint,
trivia) ->
SynBinding(
accessibility,
kind,
isInline,
isMutable,
attributes,
xmlDoc,
valData,
headPat,
returnInfo,
e,
range,
debugPoint,
trivia
)
| _ -> failwith "unexpected"Parsing small strings to grab the AST nodes is a trick I do in Telplin from time to time.
- Myriad really misses some unit tests to cover https://github.com/MoiraeSoftware/myriad/blob/master/src/Myriad.Core/AstExtensions.fs. Every year or so, they upgrade Fantomas, tweak until things compile and then complain when stuff no longer is generated at runtime.