|  | open Core | 
        
          |  |  | 
        
          |  | type ast = | 
        
          |  | | Func of (string * string list * ast) | 
        
          |  | | App of (string * (ast list)) | 
        
          |  | | Var of string | 
        
          |  | | True | 
        
          |  | | False | 
        
          |  | | Int of int | 
        
          |  | | And of ast * ast | 
        
          |  | | Or of ast * ast | 
        
          |  | | Not of ast | 
        
          |  | (* [@@deriving sexp] *) | 
        
          |  |  | 
        
          |  | let a x = Sexp.Atom x | 
        
          |  | let l xs = Sexp.List xs | 
        
          |  | let fmt = Format.sprintf | 
        
          |  |  | 
        
          |  | let rec sexp_of_ast = function | 
        
          |  | | Var s -> a (fmt "?%s" s) | 
        
          |  | | True -> a "true" | 
        
          |  | | False -> a "false" | 
        
          |  | | And (x, y) -> l [a "and"; sexp_of_ast x; sexp_of_ast y] | 
        
          |  | | Or (x, y) -> l [a "or"; sexp_of_ast x; sexp_of_ast y] | 
        
          |  | | Not x -> l [a "not"; sexp_of_ast x] | 
        
          |  | | Func (name, args, body) -> | 
        
          |  | l [a "define"; a name; l (List.map ~f:a args); sexp_of_ast body] | 
        
          |  | | App (f, args) -> | 
        
          |  | l ((a f) :: List.map ~f:sexp_of_ast args) | 
        
          |  | | Int i -> a (fmt "%d" i) | 
        
          |  |  | 
        
          |  | exception Parser_error of string | 
        
          |  |  | 
        
          |  | let rec ast_of_sexp = function | 
        
          |  | | Sexp.Atom "true" -> True | 
        
          |  | | Atom "false" -> False | 
        
          |  | | Atom v -> | 
        
          |  | (match int_of_string v with | 
        
          |  | | i -> Int i | 
        
          |  | | exception Failure _ -> | 
        
          |  | let first_char = String.get v 0 in | 
        
          |  | if Char.(first_char <> '?') | 
        
          |  | then raise (Parser_error (fmt "invalid atom %s" v)); | 
        
          |  | Var (String.sub v ~pos:1 ~len:((String.length v) - 1))) | 
        
          |  | | List [Atom "and"; a; b] -> | 
        
          |  | And (ast_of_sexp a, ast_of_sexp b) | 
        
          |  | | List [Atom "or"; a; b] -> | 
        
          |  | Or (ast_of_sexp a, ast_of_sexp b) | 
        
          |  | | List [Atom "not"; a] -> | 
        
          |  | Not (ast_of_sexp a) | 
        
          |  | | List [Atom "define"; Atom name; List arguments; body] as expr -> | 
        
          |  | let arguments = List.map ~f:(function Atom a -> a | List _ -> | 
        
          |  | raise (Parser_error | 
        
          |  | (fmt "invalid arguments list in %s" | 
        
          |  | (Sexp.to_string_hum expr)))) arguments in | 
        
          |  | Func (name, arguments, ast_of_sexp body) | 
        
          |  | | List (Atom fname :: arguments) -> | 
        
          |  | App (fname, List.map ~f:ast_of_sexp arguments) | 
        
          |  | | sexp -> raise (Parser_error | 
        
          |  | (fmt "invalid expression %s" (Sexp.to_string_hum sexp))) | 
        
          |  |  | 
        
          |  |  | 
        
          |  | let show_ast ast = | 
        
          |  | ast |> sexp_of_ast |> Sexp.to_string_hum | 
        
          |  |  | 
        
          |  | let parse input = | 
        
          |  | Parsexp.Many.parse_string_exn input | 
        
          |  | |> List.map ~f:ast_of_sexp | 
        
          |  |  | 
        
          |  | let unparse asts = | 
        
          |  | List.map ~f:(fun ast -> sexp_of_ast ast |> Sexp.to_string_hum) asts | 
        
          |  | |> String.concat ~sep:"\n" | 
        
          |  |  |