blob: 8fa9c79084fcaf8bedba7c2dec70866b81eac249 [file] [log] [blame] [edit]
type expression =
| Constant of int
| Variable of string
| Assignment of string * expression
| Call of string * expression list
| Throw of expression
| Await of expression
type statement =
| EmptyStatement
| Block of statement list
| Expression of expression
| Return of expression
| If of expression * statement * statement
| Label of string * statement
| Break of string
| While of string * expression * statement
| Continue of string
| TryCatch of statement * string * statement
| TryFinally of statement * statement
type function_declaration =
| Sync of string * string list * string list * statement
| Async of string * string list * string list * statement
(* ==== Construction from S-expressions ==== *)
(* The Sexp is assumed to be well-formed, otherwise a pattern match failure
will occur. *)
open Sexp
let build_string = function
| Atom s -> s
| _ -> failwith "not an atom"
let build_string_list = function
| Slist lst -> List.map build_string lst
| _ -> failwith "not a list"
let bad_atom_msg kind atom = "bad " ^ kind ^ ": " ^ atom
let bad_slist_msg kind slist =
let msg =
"bad " ^ kind ^ ": list[" ^ string_of_int (List.length slist) ^ "]" in
match slist with
| Atom tag :: _ -> msg ^ " tagged: " ^ tag
| _ -> msg
let rec build_expression = function
| Slist [Atom "Constant"; Atom value] ->
Constant (int_of_string value)
| Slist [Atom "Variable"; Atom name] ->
Variable name
| Slist [Atom "Assignment"; Atom name; expr] ->
Assignment (name, build_expression expr)
| Slist [Atom "Call"; Atom name; args] ->
Call (name, build_expression_list args)
| Slist [Atom "Throw"; expr] ->
Throw (build_expression expr)
| Slist [Atom "Await"; expr] ->
Await (build_expression expr)
| Slist slist -> failwith (bad_slist_msg "expression" slist)
| Atom atom -> failwith (bad_atom_msg "expression" atom)
and build_expression_list = function
| Slist lst -> List.map build_expression lst
| _ -> failwith "not a list"
let rec build_statement = function
| Atom "EmptyStatement" -> EmptyStatement
| Slist [Atom "Block"; statements] -> Block (build_statement_list statements)
| Slist [Atom "Expression"; expr] -> Expression (build_expression expr)
| Slist [Atom "Return"; expr] -> Return (build_expression expr)
| Slist [Atom "If"; cond; thn; els] ->
If (build_expression cond, build_statement thn, build_statement els)
| Slist [Atom "Label"; Atom label; stmt] -> Label (label, build_statement stmt)
| Slist [Atom "Break"; Atom label] -> Break (label)
| Slist [Atom "While"; Atom label; cond; body] ->
While (label, build_expression cond, build_statement body)
| Slist [Atom "Continue"; Atom label] -> Continue (label)
| Slist [Atom "TryCatch"; body; Atom exn; catch] ->
TryCatch (build_statement body, exn, build_statement catch)
| Slist [Atom "TryFinally"; body; finally] ->
TryFinally (build_statement body, build_statement finally)
| Slist slist -> failwith (bad_slist_msg "statement" slist)
| Atom atom -> failwith (bad_atom_msg "statement" atom)
and build_statement_list = function
| Slist lst -> List.map build_statement lst
| _ -> failwith "not a list"
let build_function_declaration = function
| Slist [Atom tag; Atom name; parameters; locals; body] ->
let parameters = build_string_list parameters in
let locals = build_string_list locals in
let body = build_statement body in
(match tag with
| "Sync" -> Sync (name, parameters, locals, body)
| "Async" -> Async (name, parameters, locals, body)
| _ -> failwith ("unexpected tag " ^ tag))
| Slist slist -> failwith (bad_slist_msg "declaration" slist)
| Atom atom -> failwith (bad_atom_msg "declaration" atom)
(* Read an S-expression from standard in, return a list of Asts. *)
let read_asts chan =
match Sexp.read_sexp chan with
| Slist slist -> List.map build_function_declaration slist
| Atom atom -> failwith (bad_atom_msg "compilation unit" atom)