diff options
| author | Chouser <chouser@n01se.net> | 2015-01-22 02:59:48 -0500 |
|---|---|---|
| committer | Chouser <chouser@n01se.net> | 2015-01-30 12:54:42 -0500 |
| commit | 921a951fe4d088e60ce25866344bd534420f9ec6 (patch) | |
| tree | 411999aa4176c13e61f3cda4508f873f1f067975 | |
| parent | 59d10e1bd703f65e12fef85bceef4204f82685fb (diff) | |
| download | mal-921a951fe4d088e60ce25866344bd534420f9ec6.tar.gz mal-921a951fe4d088e60ce25866344bd534420f9ec6.zip | |
Ocaml: Add step 2, nothing optional
| -rw-r--r-- | ocaml/Makefile | 7 | ||||
| -rw-r--r-- | ocaml/printer.ml | 1 | ||||
| -rw-r--r-- | ocaml/reader.ml | 26 | ||||
| -rw-r--r-- | ocaml/step2_eval.ml | 50 | ||||
| -rw-r--r-- | ocaml/types.ml | 1 |
5 files changed, 69 insertions, 16 deletions
diff --git a/ocaml/Makefile b/ocaml/Makefile index a46b82a..a526ecf 100644 --- a/ocaml/Makefile +++ b/ocaml/Makefile @@ -1,14 +1,17 @@ -STEPS = step0_repl.ml step1_read_print.ml +STEPS = step0_repl.ml step1_read_print.ml step2_eval.ml MODULES = types.ml reader.ml printer.ml LIBS = str.cma BINS = $(STEPS:%.ml=%) -all: $(BINS) mal oc +all: $(BINS) mal mal: $(word $(words $(BINS)),$(BINS)) cp $< $@ +repl: $(MODULES) + rlwrap ocaml $(LIBS) $(MODULES:%.ml=%.cmo) + $(BINS): %: %.ml $(MODULES) ocamlc $(LIBS) $(MODULES) $< -o $@ diff --git a/ocaml/printer.ml b/ocaml/printer.ml index 30e4415..e87b3eb 100644 --- a/ocaml/printer.ml +++ b/ocaml/printer.ml @@ -13,3 +13,4 @@ let rec pr_str mal_obj = ^ (Str.global_replace (Str.regexp "\"") "\\\"" s) ^ "\"" | Types.MalList xs -> "(" ^ (join " " (List.map pr_str xs)) ^ ")" + | Types.Fn f -> "<fn>" diff --git a/ocaml/reader.ml b/ocaml/reader.ml index 51ab522..c32fa91 100644 --- a/ocaml/reader.ml +++ b/ocaml/reader.ml @@ -3,7 +3,7 @@ let find_re re str = (List.filter (function | Str.Delim x -> true | Str.Text x -> false) (Str.full_split re str)) ;; -let token_re = (Str.regexp "~@\\|[][{}()'`~^@]\\|\"\\(\\\\.\\|[^\"]\\)*\"\\|;.*\\|[^][ \n{}('\"`,;)]*") +let token_re = (Str.regexp "~@\\|[][{}()'`~^@]\\|\"\\(\\\\.\\|[^\"]\\)*\"\\|;.*\\|[^][ \n{}('\"`,;)]*") type reader = { form : Types.mal_type; @@ -36,11 +36,11 @@ let rec read_list list_reader = raise End_of_file; | token :: tokens -> if Str.string_match (Str.regexp "[])}]") token 0 then - {list_form = list_reader.list_form; tokens = tokens} + {list_form = list_reader.list_form; tokens = tokens} else - let reader = read_form list_reader.tokens in + let reader = read_form list_reader.tokens in read_list {list_form = list_reader.list_form @ [reader.form]; - tokens = reader.tokens} + tokens = reader.tokens} and read_quote sym tokens = let reader = read_form tokens in {form = Types.MalList [ Types.Symbol sym; reader.form ]; @@ -50,17 +50,15 @@ and read_form all_tokens = | [] -> raise End_of_file; | token :: tokens -> match token with - | "'" -> read_quote "quote" tokens - | "`" -> read_quote "quasiquote" tokens - | "~" -> read_quote "unquote" tokens + | "'" -> 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 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 diff --git a/ocaml/step2_eval.ml b/ocaml/step2_eval.ml new file mode 100644 index 0000000..4337a11 --- /dev/null +++ b/ocaml/step2_eval.ml @@ -0,0 +1,50 @@ +module Env = + Map.Make ( + String + (*(struct + type t = Types.Symbol + let compare (Types.Symbol a) (Types.Symbol b) = compare a b + end)*) + ) + +let num_fun f = Types.Fn + (function + | [(Types.Int a); (Types.Int b)] -> Types.Int (f a b) + | _ -> raise (Invalid_argument "Numeric args required for this Mal builtin")) + +let env = ref (List.fold_left (fun a b -> b a) Env.empty + [ Env.add "+" (num_fun ( + )); + Env.add "-" (num_fun ( - )); + Env.add "*" (num_fun ( * )); + Env.add "/" (num_fun ( / )) ]) + +let rec eval_ast ast env = + match ast with + | Types.Symbol s -> + (try Env.find s !env + with Not_found -> raise (Invalid_argument ("Symbol '" ^ s ^ "' not found"))) + | Types.MalList xs -> Types.MalList (List.map (fun x -> eval x env) xs) + | _ -> ast +and eval ast env = + let result = eval_ast ast env in + match result with + | Types.MalList ((Types.Fn f) :: args) -> (f args) + | _ -> result + +let read str = Reader.read_str str +let print exp = Printer.pr_str exp +let rep str env = print (eval (read str) env) + +let rec main = + try + while true do + print_string "user> "; + let line = read_line () in + try + print_endline (rep line env); + with End_of_file -> () + | Invalid_argument x -> + output_string stderr ("Invalid_argument exception: " ^ x ^ "\n"); + flush stderr + done + with End_of_file -> () diff --git a/ocaml/types.ml b/ocaml/types.ml index 92f3030..60d3725 100644 --- a/ocaml/types.ml +++ b/ocaml/types.ml @@ -6,3 +6,4 @@ type mal_type = | Nil | Bool of bool | String of string + | Fn of (mal_type list -> mal_type) |
