Last active
December 30, 2015 07:02
-
-
Save baronfel/ecebe944bfc75087018e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace parsecccc | |
module Types = | |
type PMR = | |
| Literal of string | |
| Hostname of string | |
| Hash of uint32 | |
| IP of string | |
| Bool of BoolMatch | |
and BoolMatch = | |
| End | |
| Not of BoolMatch | |
| And of PMR * BoolMatch | |
| Or of PMR * BoolMatch | |
module Parsing = | |
open FParsec.CharParsers | |
open FParsec.Primitives | |
open FParsec | |
open Types | |
let doubleQuote = pchar '"' | |
let commaSpace = pstring ", " | |
let inline quoted p = doubleQuote >>. manyCharsTill p doubleQuote | |
let inline beforeLiteral lit p = p .>> skipString lit | |
let inline parensed p = between (pchar '(') (pchar ')') p | |
let dummyBool, (boolImp : Parser<BoolMatch, unit> ref) = createParserForwardedToRef() | |
// PMR parsers | |
let literal : Parser<PMR, unit> = anyChar |> quoted |> beforeLiteral ":literal" |>> Literal | |
let hostname : Parser<PMR, unit> = anyChar |> quoted |> beforeLiteral ":hostname" |>> Hostname | |
let hash : Parser<PMR, unit> = puint32 |> beforeLiteral ":hash" |>> Hash | |
// what does the IP parser take? here's a guess based on @abk's snippet | |
let ip : Parser<PMR, unit> = anyChar |> quoted |> beforeLiteral ":ip" |>> IP | |
// make a parser for the kind of PMR that required the recursive reference | |
let bool = dummyBool |>> Bool | |
let patternMatchRule = attempt literal <|> attempt hostname <|> attempt hash <|> attempt ip <|> bool | |
// boolmatch parsers | |
let endP = skipString "End" |>> fun _ -> End | |
let andP = skipString "And" >>. parensed (patternMatchRule .>>. (commaSpace >>. dummyBool)) |>> And | |
let notP = skipString "Not" >>. parensed dummyBool |>> Not | |
let orP = skipString "Or" >>. parensed (patternMatchRule .>>. (commaSpace >>. dummyBool)) |>> Or | |
// now hook up the implementation of the ACTUAL boolean match parser | |
boolImp := endP <|> andP <|> notP <|> orP | |
module Tests = | |
open FParsec | |
open FParsec.CharParsers | |
open Types | |
let run p source = | |
match runParserOnString p () "test" source with | |
| Success(s,_,_) -> s | |
| Failure(x,y,z) -> failwith x | |
let test p (source, expect) = if run p source = expect then () else (invalidArg "string" source) | |
let PMRs = [ | |
"\"cat\":literal", Literal("cat") | |
"\"www.lol.com\":hostname", Hostname("www.lol.com") | |
] | |
let bools = [ | |
"End", End | |
"And(\"cat\":literal, End)", And(Literal("cat"), End) | |
"Not(And(\"cat\":literal, End))", Not(And(Literal("cat"), End)) | |
] | |
PMRs |> List.iter (test Parsing.patternMatchRule) | |
bools |> List.iter (test Parsing.dummyBool) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment