parsing - How can I parse homogeneous lists in FParsec? -
i'm having issue trying parse homogeneous json-like array in fparsec. i've decomposed problem short example reproduces it.
#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 | 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 when use test function try out, following results:
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 ']' if swap order of p_int_value , p_bool_value when using <|> operator, [true,false] parses [1,2,3] fails similar error. basically, ever parser use first tries use.
i understand <|> operator won't attempt rhs parser if lhs mutates user state - can't see how happening. p_bool_value , p_int_value don't have starting characters in common, both should failing when trying parse wrong data type. ints never start 'false' or 'true' , bools never start numeric digits.
what doing wrong?
ah, i've figured out. hint in error message or ']'. problem sepby succeeds on empty input, when hits t, returns empty list, , control passes between tries , fails find terminating ].
the solution move empty list case out of int/bool-specific parsers, this:
let p_list_value = let commadelimitedlist ptype = sepby1 (ptype .>> p_whitespace) (p_comma .>> p_whitespace) let delimitedlist = (commadelimitedlist p_int_value) <|> (commadelimitedlist p_bool_value) <|> preturn [] let enclosedlist = between p_l_sbrace p_r_sbrace delimitedlist enclosedlist |>> clist note use of sepby1 instead of sepby, , addition of <|> preturn [] handle empty case once in delimitedlist.
as side-note, don't know exact application, not such idea enforce typing in parser; more common way implement parse commadelimitedlist (p_int_value <|> p_bool_value) (with original commadelimitedlist) , check typing in subsequent analysis phase.
Comments
Post a Comment