Skip to content

Instantly share code, notes, and snippets.

@jdh30
Last active May 22, 2019 05:12
Show Gist options
  • Save jdh30/38ea9080aa8088364cf5e195600ff234 to your computer and use it in GitHub Desktop.
Save jdh30/38ea9080aa8088364cf5e195600ff234 to your computer and use it in GitHub Desktop.
FemtoML parser in F# using active patterns
> let alpha = set['a'..'z'] + set['A'..'Z'];;
> let num = set['0'..'9'];;
> let alphanum = alpha + num;;
> let (|Char|_|) alphabet = function
| c::cs when Set.contains c alphabet -> Some(c, cs)
| _ -> None;;
> let rec (|Chars|) alphabet = function
| Char alphabet (c, Chars alphabet (cs, t)) -> c::cs, t
| t -> [], t;;
> let stringOf : seq<char> -> string = Seq.map string >> String.concat "";;
> let (|INT|IDENT|KWD|END|) t =
let rec ws = function ' '::t -> ws t | t -> t
match ws t with
| '-'::Char num (c, Chars num (cs, t)) -> INT(-int(stringOf(c::cs)), t)
| Char num (c, Chars num (cs, t)) -> INT(int(stringOf(c::cs)), t)
| Char alpha (c, Chars alphanum (cs, t)) ->
match stringOf(c::cs) with
| "if" | "then" | "else"
| "fun"
| "let" | "rec" | "in" as s -> KWD(s, t)
| s -> IDENT(s, t)
| '-'::'>'::t -> KWD("->", t)
| ('=' | '(' | ')' as c)::t -> KWD(string c, t)
| t -> END;;
> let rec (|Atom|_|) = function
| INT(n, t) -> Some(Int n, t)
| IDENT(x, t) -> Some(Var x, t)
| KWD("(", Expr(f, KWD(")", t))) -> Some(f, t)
| _ -> None
and (|PApply|_|) = function
| Atom(f, PApply(fs, t)) -> Some(f::fs, t)
| Atom(f, t) -> Some([f], t)
| _ -> None
and (|Expr|_|) = function
| PApply(fs, t) -> Some(List.reduce (fun f g -> Apply(f, g)) fs, t)
| KWD("if", Expr(p, KWD("then", Expr(f, KWD("else", Expr(g, t)))))) ->
Some(If(p, f, g), t)
| KWD("fun", IDENT(x, KWD("->", Expr(f, t)))) ->
Some(Fun(x, f), t)
| KWD("let", IDENT(x, KWD("=", Expr(f, KWD("in", Expr(g, t)))))) ->
Some(Let(false, x, f, g), t)
| KWD("let", KWD("rec", IDENT(x, KWD("=", Expr(f, KWD("in", Expr(g, t))))))) ->
Some(Let(true, x, f, g), t)
| _ -> None;;
> let parse t =
match List.ofSeq t with
| Expr(f, []) -> f
| Expr(_, t) -> failwithf "Failed to parse remainder '%s'" (stringOf t)
| t -> failwithf "Failed to parse '%s'" (stringOf t);;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment