10

I would like to generate F# code for a .fs file using the abstract syntax tree. I am able to generate a .cs file using the Roslyn API. Here is an example riak.cs file that the unit tests generate based on the riak.proto. I would like to do the same thing in F#. I do not want to create a type provider yet. Does anyone have any examples using FSharp.Compiler.Service, possible with Fantomas?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Cameron Taggart
  • 5,771
  • 4
  • 45
  • 70

2 Answers2

9

Fantomas is certainly the right thing to look at here. If you want to generate F# source code, you basically need two things:

  1. Build the AST that represents the source code you want to build. To do that, you need to use the untyped AST from the F# compiler service. The untyped syntax tree page documents how you can process it, but it should be a good starting point for learning about it. The AST of expressions is defined by the SynExpr type.

  2. Once you build the AST, you need to format it. The F# compiler does not include a pretty printer, but this is exactly what Fantomas does in the CodePrinter file, so you should be able to copy this & pass your AST to the formatting implemented there. I think Visual F# PowerTools might actually have a newer version of Fantomas, so check that out first.

This answer is all using untyped AST, which is probably a good fit for working with syntax of the language. There is also typed AST (created after type inference finishes), but that's hard to use and not a good fit here.

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • And this gives you F# source from an untyped AST? I thought you needed a CodeDOM provider of some sort. – Robert Harvey Jul 14 '14 at 17:12
  • @RobertHarvey Yes - Fantomas is a tool that re-formats your F# code and it implements a pretty printer that does this. So, yes, this gives you F# code. CodeDOM is another option, but it generates very ugly code (because it has been designed for C#/VB) – Tomas Petricek Jul 14 '14 at 17:17
  • Fantomas accepts an AST as input, not source? Does it parse source into an AST first, and then re-emit it? – Robert Harvey Jul 14 '14 at 17:18
  • 2
    It accepts source, uses the compiler to build AST and then pretty prints the AST. So a part of it does what the OP needs here. How else could it work? [Regular expressions?](http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags) – Tomas Petricek Jul 14 '14 at 17:21
  • Well, no, I wouldn't use regular expressions. Having an AST is certainly a very cool bonus, but I doubt that's how online code prettifiers work; you're essentially re-implementing a compiler (well, the lexing and parsing part of it, anyway). Visual Studio gets the AST for free, so they might as well use it for their code formatting. – Robert Harvey Jul 14 '14 at 17:23
  • 1
    Having the AST is the only reasonable way to do this... But yes, I suppose it could be written using an ad-hoc set of rules that process a list of lines represented as strings and sometimes get it right :-) – Tomas Petricek Jul 14 '14 at 17:25
7

I totally agree with Tomas' answer. You need the latter half of Fantomas pipeline. Here is some relevant information.

  • FSharp.Compiler.Service's AST module consists of relevant ASTs and other utility functions for creating AST nodes, which might be helpful for you.

  • In Fantomas project, there is formatAST function that takes an AST as an input and output a source code string.

pad
  • 41,040
  • 7
  • 92
  • 166
  • 1
    Finally had time to follow up with this. My blog post is here: http://blog.ctaggart.com/2014/09/generating-f-code-using-its-ast.html – Cameron Taggart Sep 22 '14 at 05:23