Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Position information in fparsec

Tags:

f#

fparsec

My AST model needs to carry location information (filename, line, index). Is there any built in way to access this information? From the reference docs, the stream seems to carry the position, but I'd prefer that I dont have to implement a dummy parser just to save the position, and add that everywhere.

Thanks in advance

like image 506
hammett Avatar asked Jun 14 '11 22:06

hammett


1 Answers

Parsers are actually type abbreviations for functions from streams to replies:

Parser<_,_> is just CharStream<_> -> Reply<_>

Keeping that in mind, you can easily write a custom parser for positions:

let position : CharStream<_> -> Reply<Position> = fun stream -> Reply(stream.Position)
(* OR *)
let position : Parser<_,_> = fun stream -> Reply stream.Position

and atttach position information to every bit you parse using

position .>>. yourParser (*or tuple2 position yourParser*)

position parser does not consume any input and thus it is safe to combine in that way.

You can keep the code change required restricted to a single line and avoid uncontrollable code spread:

type AST = Slash of int64
         | Hash  of int64

let slash : Parser<AST,_> = char '/' >>. pint64 |>> Slash
let hash  : Parser<AST,_> = char '#' >>. pint64 |>> Hash
let ast   : Parser<AST,_> = slash <|> hash

(*if this is the final parser used for parsing lists of your ASTs*)
let manyAst  : Parser<            AST  list,_> = many                (ast  .>> spaces)

let manyAstP : Parser<(Position * AST) list,_> = many ((position .>>. ast) .>> spaces)
(*you can opt in to parse position information for every bit
  you parse just by modifiying only the combined parser     *)

Update: FParsec has a predefined parser for positions: http://www.quanttec.com/fparsec/reference/charparsers.html#members.getPosition

like image 179
Cetin Sert Avatar answered Nov 17 '22 10:11

Cetin Sert