aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChouser <chouser@n01se.net>2015-01-22 02:59:48 -0500
committerChouser <chouser@n01se.net>2015-01-30 12:54:42 -0500
commit921a951fe4d088e60ce25866344bd534420f9ec6 (patch)
tree411999aa4176c13e61f3cda4508f873f1f067975
parent59d10e1bd703f65e12fef85bceef4204f82685fb (diff)
downloadmal-921a951fe4d088e60ce25866344bd534420f9ec6.tar.gz
mal-921a951fe4d088e60ce25866344bd534420f9ec6.zip
Ocaml: Add step 2, nothing optional
-rw-r--r--ocaml/Makefile7
-rw-r--r--ocaml/printer.ml1
-rw-r--r--ocaml/reader.ml26
-rw-r--r--ocaml/step2_eval.ml50
-rw-r--r--ocaml/types.ml1
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)