Может ли провайдер типа F # быть спроектирован для генерации типа AST и анализатора? - PullRequest
2 голосов
/ 14 января 2020

Мое понимание провайдеров F # -типа заключается в том, что они являются функциями времени компиляции от строк до типов. К типу также могут быть прикреплены методы stati c, поэтому они также могут использоваться для генерации кода.

На высоком уровне это то же самое, что и инструменты генератора синтаксических анализаторов, такие как ANTLR, которые принимают файл грамматики и генерируют код для целевого языка.

Итак, я представляю себе поставщика типа F #, который принимает строку грамматики и предоставляет тип для AST и функции синтаксического анализа в качестве члена stati c.

Это может выглядеть так:

[<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. Есть ли примеры реализации этого?

Ответы [ 2 ]

4 голосов
/ 15 января 2020

Я построил такую ​​библиотеку 4 года go, которую вы можете просмотреть на https://github.com/aastevenson/FSharp.Text.Experimental.Transform

Документация довольно обширна и полна, включая учебные пособия, примеры, справка по API и т. д. c. Если вам просто интересен синтаксический анализатор, см. Синтаксический анализ с FSharp.Text.Experimental.Transform , который демонстрирует сравнение с FParse c.

. Библиотека может дополнительно выполнять преобразования на результирующий 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 из проанализированной строки.

Обратите внимание, что я не затрагивал этот проект в течение длительного времени.

2 голосов
/ 14 января 2020

Это, безусловно, возможно построить, так как все, что вам нужно сделать, это "заполнить типы" в соответствии с тем, как работает SDK. Сам провайдер типов будет реализовывать парсер для вашей грамматики, очень похоже на то, как провайдеры типов FSharp.Data реализуют парсеры для JSON, XML, et c.

Довольно весело (и забавно!) Примером чего-то подобного является Поставщик смешанных типов , который принимает источник F # в качестве входных данных, генерирует сборку, читает эту сборку и использует инфраструктуру поставщика типов для чтения сборки и предоставляет типы из сгенерированного кода. , Таким образом, вы действительно можете многое сделать, хотя я не могу сказать, что рекомендую следовать тому, что делает провайдер типов Mixin.

...