mirror of
https://github.com/kanaka/mal.git
synced 2024-11-10 02:45:44 +03:00
67 lines
2.3 KiB
OCaml
67 lines
2.3 KiB
OCaml
|
let find_re re str =
|
||
|
List.map (function | Str.Delim x -> x | Str.Text x -> "impossible!")
|
||
|
(List.filter (function | Str.Delim x -> true | Str.Text x -> false)
|
||
|
(Str.full_split re str)) ;;
|
||
|
|
||
|
let token_re = (Str.regexp "~@\\|[][{}()'`~^@]\\|\"\\(\\\\.\\|[^\"]\\)*\"\\|;.*\\|[^][ \n{}('\"`,;)]*")
|
||
|
|
||
|
type reader = {
|
||
|
form : Types.mal_type;
|
||
|
tokens : string list;
|
||
|
}
|
||
|
|
||
|
type list_reader = {
|
||
|
list_form : Types.mal_type list;
|
||
|
tokens : string list;
|
||
|
}
|
||
|
|
||
|
let read_atom token =
|
||
|
match token with
|
||
|
| "nil" -> Types.Nil
|
||
|
| "true" -> Types.Bool true
|
||
|
| "false" -> Types.Bool false
|
||
|
| _ ->
|
||
|
match token.[0] with
|
||
|
| '0'..'9' -> Types.Int (int_of_string token)
|
||
|
| '"' -> Types.String (Str.global_replace (Str.regexp "\\\\\\(.\\)")
|
||
|
"\\1"
|
||
|
(String.sub token 1 ((String.length token) - 2)))
|
||
|
| ':' -> Types.Keyword (Str.replace_first (Str.regexp "^:") "" token)
|
||
|
| _ -> Types.Symbol token
|
||
|
|
||
|
let rec read_list list_reader =
|
||
|
match list_reader.tokens with
|
||
|
| [] -> output_string stderr "expected ')', got EOF\n";
|
||
|
flush stderr;
|
||
|
raise End_of_file;
|
||
|
| token :: tokens ->
|
||
|
if Str.string_match (Str.regexp "[])}]") token 0 then
|
||
|
{list_form = list_reader.list_form; tokens = tokens}
|
||
|
else
|
||
|
let reader = read_form list_reader.tokens in
|
||
|
read_list {list_form = list_reader.list_form @ [reader.form];
|
||
|
tokens = reader.tokens}
|
||
|
and read_quote sym tokens =
|
||
|
let reader = read_form tokens in
|
||
|
{form = Types.MalList [ Types.Symbol sym; reader.form ];
|
||
|
tokens = reader.tokens}
|
||
|
and read_form all_tokens =
|
||
|
match all_tokens with
|
||
|
| [] -> raise End_of_file;
|
||
|
| token :: tokens ->
|
||
|
match token with
|
||
|
| "'" -> read_quote "quote" tokens
|
||
|
| "`" -> read_quote "quasiquote" tokens
|
||
|
| "~" -> read_quote "unquote" tokens
|
||
|
| "~@" -> read_quote "splice-unquote" tokens
|
||
|
| _ ->
|
||
|
match token.[0] with
|
||
|
| '[' | '(' | '{' -> let list_reader =
|
||
|
read_list {list_form = []; tokens = tokens} in
|
||
|
{form = Types.MalList list_reader.list_form;
|
||
|
tokens = list_reader.tokens}
|
||
|
| _ -> {form = read_atom token; tokens = tokens}
|
||
|
|
||
|
let read_str str = (read_form (List.filter ((<>) "") (find_re token_re str))).form
|
||
|
|