Проверьте, соответствует ли последний результат последовательности анализатора предикату - FParsec - PullRequest
1 голос
/ 23 марта 2019

Я хотел бы создать парсер, который анализирует имена данных из модулей, например:

MyModule.myData // (a module name and a member of the module)

Для этого я хотел бы проанализировать все идентификаторы, которые разделены точкой. Проблема в том, что я могу применить предикат ко всем этим синтаксическим анализаторам, но я не мог знать, какой из них будет последним в последовательности, в этом случае я бы хотел, чтобы последний идентификатор начинался со строчной буквы. Вот код, который у меня есть:

type QualName = (string list) * string

let rec identifierP predicate =
    many1Satisfy
        (fun c -> isLetter c || isDigit c || c = ''') >>=
    fun id ->
        if isDigit id.[0]
        then fail "Error: starts by a number"
        else
            if predicate id
            then preturn id
            else fail "Error: identifier don't match with the predicate"

and private idP_capitalized (id: string) = System.Char.IsUpper id.[0]
and private idP_lowered (id: string) = System.Char.IsLower id.[0]
and private idP_nospecified (_: string) = true

and private qualName lastPredicate =
    (sepBy1 (identifierP idP_capitalized (* => from module(s) *)) (pstring "."))
    |>> fun lst -> (lst |> List.rev |> List.tail |> List.rev, lst.Last())

Если я применяю последующий анализ с предикатом, как в приведенном ниже коде, в случае ошибки, нет возможности вернуться назад (как в случае простого FParsec `fail '):

and private qualName lastPredicate =
    (sepBy1 (identifierP idP_capitalized (* => from module(s) *)) (pstring "."))
    |>> fun lst ->
        if lastPredicate lst = false
        then failwith "Error: identifier don't match with the predicate"
        else (lst |> List.rev |> List.tail |> List.rev, lst.Last())

Как я могу выполнить такой анализ с ошибками синтаксического анализа FParsec, если они есть?

...