Я хотел бы создать парсер, который анализирует имена данных из модулей, например:
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, если они есть?