【问题标题】:Can an F# Type Provider be designed to generate an AST type and parser?是否可以将 F# 类型提供程序设计为生成 AST 类型和解析器?
【发布时间】:2020-01-14 18:52:06
【问题描述】:

我对 F# 类型提供程序的理解是,它们实际上是从字符串到类型的编译时函数。该类型还可以附加静态方法,因此它们也可以用于代码生成。

在高层次上,这与解析器生成器工具(如 ANTLR)相同,后者采用语法文件并为目标语言生成代码。

所以我正在想象一个 F# 类型提供程序,它接受一个语法字符串并为 AST 和解析函数提供一个类型作为静态成员。

它可能看起来像这样:

[<Literal>]
let Grammar = "
program
   : statement +
   ;

statement
   : 'if' paren_expr statement
   | 'if' paren_expr statement 'else' statement
   | 'while' paren_expr statement
   | 'do' statement 'while' paren_expr ';'
   | '{' statement* '}'
   | expr ';'
   | ';'
   ;

paren_expr
   : '(' expr ')'
   ;

expr
   : test
   | id '=' expr
   ;

test
   : sum
   | sum '<' sum
   ;

sum
   : term
   | sum '+' term
   | sum '-' term
   ;

term
   : id
   | integer
   | paren_expr
   ;

id
   : STRING
   ;

integer
   : INT
   ;


STRING
   : [a-z]+
   ;


INT
   : [0-9] +
   ;

WS
   : [ \r\n\t] -> skip
   ;
"

type MyAst = AstProvider<Grammar>

let myAst = MyAst.TryParse("int x = 1;")

问题:

  1. 现在的类型提供者真的可以做到这一点吗?
  2. 是否有任何正在实施的示例?

【问题讨论】:

    标签: f# type-providers


    【解决方案1】:

    我在 4 年前建立了这样一个库,您可以在 https://github.com/aastevenson/FSharp.Text.Experimental.Transform 仔细阅读

    documentation 相当广泛和完整,包括教程、示例、API 参考等。如果您只是对解析器感兴趣,请参阅Parsing with FSharp.Text.Experimental.Transform,它通过与 FParsec 的比较进行演示。

    该库还可以通过定义转换子树的函数对生成的 AST 进行转换。这是来自the documentation的一个非常简单的Hello World示例

    open FSharp.Text.Experimental.Transform
    
    // specify the grammar
    [<Literal>]
    let grammar = """
        Program     :   Greeting 'world';
        Greeting    :   'welcome' | 'hello';
        """ 
    
    // pass the grammar to the type provider
    type HW = GrammarProvider<grammar>
    
    let welcomeToHello (inp: HW.Greeting) =
        match inp.TryMatch<"welcome">() with
        | Some _ -> HW.Greeting.Construct<"hello">()
        | None   -> inp
    
    HW.ParseString "welcome world"                  // parse input string
    |> HW.Program.ApplyOnePass welcomeToHello       // apply transformation function
    |> HW.Pretty                                    // unparse to a string
    |> printfn "%s"                                 // prints "hello world"
    

    但是,如果您只是对解析器感兴趣,那么您可以忽略库的转换部分。提取已解析字符串的不同 AST 元素仍然非常容易。

    请注意,我已经很久没有接触这个项目了。

    【讨论】:

      【解决方案2】:

      这当然是可以构建的,因为您需要做的就是根据 SDK 的工作方式“填写类型”。类型提供程序本身将为您的语法实现解析器,就像 FSharp.Data 类型提供程序如何为 JSON、XML 等实现解析器一样。

      Mixin Type Provider 是一个非常有趣(也很有趣!)的例子,它接受 F# 源作为输入,生成程序集,读取该程序集,并使用类型提供程序基础结构读取程序集并提供生成的代码中的类型。所以你真的可以做很多事情,虽然我不能说我会推荐遵循 Mixin Type Provider 所做的事情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多