f# - 是否可以将 F# 类型提供程序设计为生成 AST 类型和解析器?
问题描述
我对 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;")
问题:
- 这对于现在的类型提供者来说真的可行吗?
- 有没有实施的例子?
解决方案
我在 4 年前建立了这样一个库,您可以在https://github.com/aastevenson/FSharp.Text.Experimental.Transform仔细阅读
文档相当广泛和完整,包括教程、示例、API 参考等。如果您只是对解析器感兴趣,请参阅Parsing with FSharp.Text.Experimental.Transform,它通过与 FParsec 的比较进行演示。
该库还可以通过定义转换子树的函数对生成的 AST 进行转换。这是文档中一个非常简单的 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 元素仍然非常容易。
请注意,我已经很久没有接触过这个项目了。
推荐阅读
- python - 如何在 for 循环中正确地将列表附加到 DataFrame
- java - 连接两个表,其中第二个表中的值的值不等于特定数字
- scala - 我可以在 Spark 中调用 RDD.map 操作中的任意函数吗?
- python - 如何使用递归方法更改 2D 列表中的所有相邻元素?
- javascript - Javascript 无法在边缘运行,但在 Firefox、Chrome 中运行良好
- machine-learning - 有多少种不同的编程范式——它们是什么?
- java - 如何在 HashSet 类型的集合中将所有字符串转换为小写
? - php - 如果php中的变量内有完整的url,如何仅获取参数?
- php - 基于 CSS :root 变量动态生成 add_theme_support('editor-color-palette') 颜色
- reactjs - 如何在 React 中手动删除事件监听器