I'd like to build active patterns with type Token list -> Ast * Token list
.
I have a simple Pascal grammar <program> ::= "program" <id> ";" <block> "."
. By remodelling code to this grammar, I have to make Program
, Identifier
and Block
patterns like:
let rec (|Program|_|) tokens =
match tokens with
| Token.Program :: tokens ->
match tokens with
| Identifier (identifier, tokens) ->
match tokens with
| Semicolon :: tokens ->
match tokens with
| Block (block, tokens) ->
match tokens with
| Dot :: tokens -> Some (Ast.Program (identifier, block), tokens)
| _ -> failwithf "Expected %A" Dot
| _ -> failwith "Expected Block"
| _ -> failwithf "Expected %A" Semicolon
| _ -> failwith "Expected Identifier"
| _ -> failwithf "Expected %A" Token.Program
and (|Identifier|_|) tokens =
match tokens with
| Token.Identifier identifier :: tokens ->
Some (Ast.Identifier identifier, tokens)
| _ -> failwith "Expected Identifier"
...
Because there are many duplicated Option None
, I tried to shorten the pattern to this:
type rec (|Program|_|) tokens =
match tokens with
| Token.Program :: Identifier (ident, Semicolon :: Block (block, Dot :: rest)) ->
Some (Ast.Program (identifier, block), rest)
| _ -> None
Could the new pattern work as expected? And how can I make the active patterns shorter, but somehow also return errors on bad input?
Also, I read that FParsec use monad to parse and retain the errors, how could I make a similar simple computing expression like FParsec.