У меня возникла проблема с анализом однородного json-подобного массива в FParsec. Я разложил проблему на короткий пример, который воспроизводит ее.Как разобрать однородные списки в FParsec?
#r @"..\packages\FParsec.1.0.2\lib\net40-client\FParsecCS.dll"
#r @"..\packages\FParsec.1.0.2\lib\net40-client\FParsec.dll"
open System
open FParsec
let test p str =
match run p str with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errormsg, _, _) -> printfn "Failure: %s" errormsg
type CValue = CInt of int64
| CBool of bool
| CList of CValue list
let P_WHITESPACE = spaces
let P_COMMA = pstring ","
let P_L_SBRACE = pstring "[" .>> P_WHITESPACE
let P_R_SBRACE = P_WHITESPACE >>. pstring "]"
let P_INT_VALUE = pint64 |>> CInt
let P_TRUE = stringReturn "true" (CBool true)
let P_FALSE = stringReturn "false" (CBool false)
let P_BOOL_VALUE = P_TRUE <|> P_FALSE
let P_LIST_VALUE =
let commaDelimitedList ptype = sepBy (ptype .>> P_WHITESPACE) (P_COMMA .>> P_WHITESPACE)
let delimitedList = (commaDelimitedList P_INT_VALUE) <|> (commaDelimitedList P_BOOL_VALUE)
let enclosedList = between P_L_SBRACE P_R_SBRACE delimitedList
enclosedList |>> CList
Когда я использую функцию test
, чтобы попробовать его, я получаю следующие результаты:
test P_LIST_VALUE "[1,2,3]"
Success: CList [CInt 1L; CInt 2L; CInt 3L]
test P_LIST_VALUE "[true,false]"
Failure: Error in Ln: 1 Col: 2
[true,false]
^
Expecting: integer number (64-bit, signed) or ']'
Если я поменять порядок P_INT_VALUE
и P_BOOL_VALUE
при использовании оператора <|>
, затем [true,false]
разбирает успешно но [1,2,3]
не работает с аналогичной ошибкой. Так что в основном, что когда-либо парсер, который я использую, это то, что он пытается использовать.
Я понимаю, что оператор <|>
не будет пытаться использовать парсер RHS, если LHS изменяет состояние пользователя - но я не вижу, как это может произойти. P_BOOL_VALUE и P_INT_VALUE не имеют никаких исходных символов, поэтому оба должны немедленно сбой при попытке проанализировать неправильный тип данных. Ints никогда не начинаются с «false» или «true», а bools никогда не начинаются с числовых цифр.
Что я делаю неправильно?
Я не тестировал ваш код, но быстрый совет - обернуть оба анализатора в 'try'. – bytebuster
«попытка» не требуется, и, как я только что протестировал, проблема не устраняется. Я честно не могу понять, почему это не работает. – Tarmil