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

Popular posts from this blog

javascript - Thinglink image not visible until browser resize -

firebird - Error "invalid transaction handle (expecting explicit transaction start)" executing script from Delphi -

mongodb - How to keep track of users making Stripe Payments -