Skip to content

Instantly share code, notes, and snippets.

@baronfel
Last active December 30, 2015 07:02
Show Gist options
  • Save baronfel/ecebe944bfc75087018e to your computer and use it in GitHub Desktop.
Save baronfel/ecebe944bfc75087018e to your computer and use it in GitHub Desktop.
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