Skip to content

Instantly share code, notes, and snippets.

@delbonis
Created January 12, 2020 05:19
Show Gist options
  • Save delbonis/eb413ef592f6bc3a215735fd0347c14a to your computer and use it in GitHub Desktop.
Save delbonis/eb413ef592f6bc3a215735fd0347c14a to your computer and use it in GitHub Desktop.
(*
* parse_sexpr returns (sexpr elements, span pos, remaining toks). It's pretty neat
* because it's nice and tail recursive, hopefully.
*
* The "prev" is actually in reverse order until we finalize it at an RPAREN.
*)
let rec parse_sexpr (start : pos) (prev : pos sexp list) (toks : pos tok list)
: (pos sexp list * pos * pos tok list, string) result =
match toks with
| TSym(s, p)::t -> (parse_sexpr start (Sym(s, p)::prev) t)
| TInt(i, p)::t -> (parse_sexpr start (Int(i, p)::prev) t)
| TBool(b, p)::t -> (parse_sexpr start (Bool(b, p)::prev) t)
| LPAREN(p)::t ->
(*
* This is a bit tricky. We have to set up a new sexp parse context
* starting here, eval it, and then make that into a Nest and continue.
*)
(match (parse_sexpr p [] t) with
| Ok((subexpr, subrange, remaining)) ->
(parse_sexpr start (Nest(subexpr, subrange)::prev) remaining)
| Error(e) -> Error(e))
(*
* This is where we actually finish up the sexpr and return it.
*)
| RPAREN(p)::t -> Ok(((List.rev prev), (pos_by_bounds start p), t))
(* Error case, shouldn't get this normally. Gotta do some work to find the
* last token's position *)
| [] ->
let (_, _, el, ec) =
(match prev with
| f::_ -> sexp_info f
| [] -> start) in
Error(Printf.sprintf "unexpected end of input after %d,%d" el ec)
(*
* This is where the heavy lifting for the top level of the S-expr parser
* happens. Once we get to the end of the list we reverse the prev list and
* return that as "the" final list of expressions.
*)
let rec parse_toks_inner (prev : pos sexp list) (toks : pos tok list) : (pos sexp list, string) result =
match toks with
| TSym(s, p)::t -> (parse_toks_inner (Sym(s, p)::prev) t)
| TInt(i, p)::t -> (parse_toks_inner (Int(i, p)::prev) t)
| TBool(b, p)::t -> (parse_toks_inner (Bool(b, p)::prev) t)
| LPAREN(p)::t ->
(match (parse_sexpr p [] t) with
| Ok((subexpr, subrange, remaining)) ->
(parse_toks_inner (Nest(subexpr, subrange)::prev) remaining)
| Error(e) -> Error(e))
| RPAREN((sl, sc, _, _))::_ -> Error(Printf.sprintf "unexpected RPAREN at %d,%d" sl sc)
| [] -> Ok(List.rev prev)
let rec parse_toks (toks : pos tok list) : (pos sexp list, string) result =
parse_toks_inner [] toks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment