ref: df79e7e4c7f40d06925385e94365b5cba554f1fe
parent: 6a277f5b5fd8b91b71aba6352118f004b1f4fc3a
author: smazga <[email protected]>
date: Thu Aug 27 13:14:32 EDT 2020
macro
--- /dev/null
+++ b/eval.ml
@@ -1,0 +1,134 @@
+module T = Types.Types
+
+let rec quasiquote ast =
+ match ast with
+ | T.List { T.value = [ T.Symbol { T.value = "unquote" }; ast ] } -> ast
+ | T.Vector { T.value = [ T.Symbol { T.value = "unquote" }; ast ] } -> ast
+ | T.List
+ { T.value =
+ T.List { T.value = [ T.Symbol { T.value = "unquote-splicing" }; head ] } :: tail
+ }
+ | T.Vector
+ { T.value =
+ T.List { T.value = [ T.Symbol { T.value = "unquote-splicing" }; head ] } :: tail
+ } -> Types.list [ Types.symbol "concat"; head; quasiquote (Types.list tail) ]
+ | T.List { T.value = head :: tail } | T.Vector { T.value = head :: tail } ->
+ Types.list [ Types.symbol "cons"; quasiquote head; quasiquote (Types.list tail) ]
+ | ast -> Types.list [ Types.symbol "quote"; ast ]
+;;
+
+let rec eval_ast ast env =
+ match ast with
+ | T.Symbol s -> Env.get env ast
+ | T.List { T.value = xs; T.meta } ->
+ T.List { T.value = List.map (fun x -> eval x env) xs; T.meta }
+ | T.Vector { T.value = xs; T.meta } ->
+ T.Vector { T.value = List.map (fun x -> eval x env) xs; T.meta }
+ | _ -> ast
+
+and preparse ast env =
+ match ast with
+ | T.List { T.value = s :: args } ->
+ (match
+ try Env.get env s with
+ | _ -> T.Nil
+ with
+ | T.Macro { T.value = sym; meta = meta } ->
+ let foo = Macro.expand ast env args sym meta in
+ print_endline ("PREPARSE: " ^ (Printer.print foo true)); eval foo env
+ | _ -> ast)
+ | _ -> ast
+
+and eval ast env =
+ match preparse ast env with
+ | T.List { T.value = [] } -> ast
+ (* Can this be replaced with a define-syntax thing? *)
+ | T.List
+ { T.value = [ T.Symbol { T.value = "define" }; T.List { T.value = arg_list }; body ]
+ } ->
+ let sym = List.hd arg_list in
+ let rest = List.tl arg_list in
+ let func =
+ eval
+ (Reader.read
+ ("(lambda ("
+ ^ Printer.stringify rest false
+ ^ ") "
+ ^ Printer.print body true
+ ^ ")"))
+ env
+ in
+ Env.set env sym func;
+ func
+ | T.List { T.value = [ T.Symbol { T.value = "define" }; key; expr ] } ->
+ let value = eval expr env in
+ Env.set env key value;
+ value
+ | T.List
+ { T.value =
+ [ T.Symbol { T.value = "define-syntax" }; keyword; T.List { T.value = macro } ]
+ } ->
+ print_endline ("define-syntax: " ^ Printer.print keyword true);
+ (match macro with
+ | _ :: literals :: groups ->
+ let macro_entry =
+ Types.macro (Printer.print keyword true) literals (Types.list groups)
+ in
+ Env.set env keyword macro_entry;
+ macro_entry
+ | _ -> T.Nil)
+ | T.List
+ { T.value =
+ [ T.Symbol { T.value = "lambda" }; T.Vector { T.value = arg_names }; expr ]
+ }
+ | T.List
+ { T.value =
+ [ T.Symbol { T.value = "lambda" }; T.List { T.value = arg_names }; expr ]
+ } ->
+ Types.proc (function args ->
+ let sub_env = Env.make (Some env) in
+ let rec bind_args a b =
+ match a, b with
+ | [ T.Symbol { T.value = "." }; name ], args ->
+ Env.set sub_env name (Types.list args)
+ | name :: names, arg :: args ->
+ Env.set sub_env name arg;
+ bind_args names args
+ | [], [] -> ()
+ | _ -> raise (Reader.Syntax_error "wrong parameter count for lambda")
+ in
+ bind_args arg_names args;
+ eval expr sub_env)
+ (* Can these be replace with define-syntax stuff? *)
+ | T.List
+ { T.value = [ T.Symbol { T.value = "let" }; T.Vector { T.value = bindings }; body ]
+ }
+ | T.List
+ { T.value = [ T.Symbol { T.value = "let" }; T.List { T.value = bindings }; body ] }
+ ->
+ let sub_env = Env.make (Some env) in
+ let rec bind_pairs = function
+ | T.List { T.value = [ T.Symbol { T.value = sym }; expr ] } :: more ->
+ let value = eval expr env in
+ Env.set env (Types.symbol sym) value;
+ bind_pairs more
+ | _ -> ()
+ in
+ bind_pairs bindings;
+ eval body sub_env
+ | T.List { T.value = T.Symbol { T.value = "begin" } :: body } ->
+ List.fold_left (fun x expr -> eval expr env) T.Nil body
+ | T.List { T.value = [ T.Symbol { T.value = "if" }; cond; then_expr; else_expr ] } ->
+ if Types.to_bool (eval cond env) then eval then_expr env else eval else_expr env
+ | T.List { T.value = [ T.Symbol { T.value = "if" }; cond; then_expr ] } ->
+ if Types.to_bool (eval cond env) then eval then_expr env else T.Nil
+ | T.List { T.value = [ T.Symbol { T.value = "quote" }; ast ] } -> ast
+ | T.List { T.value = [ T.Symbol { T.value = "quasiquote" }; ast ] } ->
+ eval (quasiquote ast) env
+ | T.List _ ->
+ (match eval_ast ast env with
+ | T.List { T.value = T.Proc { T.value = f } :: args } -> f args
+ | _ as x ->
+ raise (Reader.Syntax_error ("'" ^ Printer.print x true ^ "' not a function")))
+ | _ -> eval_ast ast env
+;;
--- a/m9.ml
+++ b/m9.ml
@@ -10,150 +10,14 @@
make a lisp project (https://github.com/kanaka/mal - thanks
https://github.com/chouser for the fantastic implementation!)
*)
-
module T = Types.Types
let repl_env = Env.make (Some Core.base)
-let rec quasiquote ast =
- match ast with
- | T.List { T.value = [ T.Symbol { T.value = "unquote" }; ast ] } -> ast
- | T.Vector { T.value = [ T.Symbol { T.value = "unquote" }; ast ] } -> ast
- | T.List
- { T.value =
- T.List { T.value = [ T.Symbol { T.value = "unquote-splicing" }; head ] } :: tail
- }
- | T.Vector
- { T.value =
- T.List { T.value = [ T.Symbol { T.value = "unquote-splicing" }; head ] } :: tail
- } -> Types.list [ Types.symbol "concat"; head; quasiquote (Types.list tail) ]
- | T.List { T.value = head :: tail } | T.Vector { T.value = head :: tail } ->
- Types.list [ Types.symbol "cons"; quasiquote head; quasiquote (Types.list tail) ]
- | ast -> Types.list [ Types.symbol "quote"; ast ]
-;;
-
-let rec eval_ast ast env =
- match ast with
- | T.Symbol s -> Env.get env ast
- | T.List { T.value = xs; T.meta } ->
- T.List { T.value = List.map (fun x -> eval x env) xs; T.meta }
- | T.Vector { T.value = xs; T.meta } ->
- T.Vector { T.value = List.map (fun x -> eval x env) xs; T.meta }
- | _ -> ast
-
-and preparse ast env =
- match ast with
- | T.List { T.value = s :: args } ->
- (match
- try Env.get env s with
- | _ -> T.Nil
- with
- | T.Macro { T.value = sym; meta = meta } ->
- Macro.expand ast env args sym meta; ast
- | _ -> ast)
- | _ -> ast
-
-and eval ast env =
- match preparse ast env with
- | T.List { T.value = [] } -> ast
- (* Can this be replaced with a define-syntax thing? *)
- | T.List
- { T.value = [ T.Symbol { T.value = "define" }; T.List { T.value = arg_list }; body ]
- } ->
- let sym = List.hd arg_list in
- let rest = List.tl arg_list in
- let func =
- eval
- (Reader.read
- ("(lambda ("
- ^ Printer.stringify rest false
- ^ ") "
- ^ Printer.print body true
- ^ ")"))
- env
- in
- Env.set env sym func;
- func
- | T.List { T.value = [ T.Symbol { T.value = "define" }; key; expr ] } ->
- let value = eval expr env in
- Env.set env key value;
- value
- | T.List
- { T.value =
- [ T.Symbol { T.value = "define-syntax" }; keyword; T.List { T.value = macro } ]
- } ->
- print_endline ("define-syntax: " ^ Printer.print keyword true);
- (match macro with
- | _ :: literals :: groups ->
- let macro_entry =
- Types.macro (Printer.print keyword true) literals (Types.list groups)
- in
- print_endline (" macro_entry: " ^ Printer.print macro_entry true);
- print_endline (" literals: " ^ Printer.print literals true);
- print_endline (" groups: " ^ Printer.dump groups);
- Env.set env keyword macro_entry;
- macro_entry
- | _ -> T.Nil)
- | T.List
- { T.value =
- [ T.Symbol { T.value = "lambda" }; T.Vector { T.value = arg_names }; expr ]
- }
- | T.List
- { T.value =
- [ T.Symbol { T.value = "lambda" }; T.List { T.value = arg_names }; expr ]
- } ->
- Types.proc (function args ->
- let sub_env = Env.make (Some env) in
- let rec bind_args a b =
- match a, b with
- | [ T.Symbol { T.value = "." }; name ], args ->
- Env.set sub_env name (Types.list args)
- | name :: names, arg :: args ->
- Env.set sub_env name arg;
- bind_args names args
- | [], [] -> ()
- | _ -> raise (Reader.Syntax_error "wrong parameter count for lambda")
- in
- bind_args arg_names args;
- eval expr sub_env)
- (* Can these be replace with define-syntax stuff? *)
- | T.List
- { T.value = [ T.Symbol { T.value = "let" }; T.Vector { T.value = bindings }; body ]
- }
- | T.List
- { T.value = [ T.Symbol { T.value = "let" }; T.List { T.value = bindings }; body ] }
- ->
- let sub_env = Env.make (Some env) in
- let rec bind_pairs = function
- | T.List { T.value = [ T.Symbol { T.value = sym }; expr ] } :: more ->
- let value = eval expr env in
- Env.set env (Types.symbol sym) value;
- bind_pairs more
- | _ -> ()
- in
- bind_pairs bindings;
- eval body sub_env
- | T.List { T.value = T.Symbol { T.value = "begin" } :: body } ->
- List.fold_left (fun x expr -> eval expr env) T.Nil body
- | T.List { T.value = [ T.Symbol { T.value = "if" }; cond; then_expr; else_expr ] } ->
- if Types.to_bool (eval cond env) then eval then_expr env else eval else_expr env
- | T.List { T.value = [ T.Symbol { T.value = "if" }; cond; then_expr ] } ->
- if Types.to_bool (eval cond env) then eval then_expr env else T.Nil
- | T.List { T.value = [ T.Symbol { T.value = "quote" }; ast ] } -> ast
- | T.List { T.value = [ T.Symbol { T.value = "quasiquote" }; ast ] } ->
- eval (quasiquote ast) env
- | T.List _ ->
- (match eval_ast ast env with
- | T.List { T.value = T.Proc { T.value = f } :: args } -> f args
- | _ as x ->
- raise (Reader.Syntax_error ("'" ^ Printer.print x true ^ "' not a function")))
- | _ -> eval_ast ast env
-;;
-
let nameplate = "Martian9 Scheme v0.1"
let read str = Reader.read str
let print exp = Printer.print exp true
-let rep str env = print (eval (read str) env)
+let rep str env = print (Eval.eval (read str) env)
let rec main =
try
@@ -162,7 +26,7 @@
repl_env
(Types.symbol "eval")
(Types.proc (function
- | [ ast ] -> eval ast repl_env
+ | [ ast ] -> Eval.eval ast repl_env
| _ -> T.Nil));
ignore
(rep
--- a/macro.ml
+++ b/macro.ml
@@ -1,7 +1,16 @@
module T = Types.Types
+let rec is_matching_pattern sym pattern args matched =
+ match pattern, args with
+ (* literals not handled, yet *)
+ | ph :: pt, ah :: at -> print_endline " LIST <-> LIST";
+ if (ph = "_" || (ph = (Printer.print sym true) && ph = (Printer.print ah true))) then is_matching_pattern sym pt at matched && true else is_matching_pattern sym pt at matched
+ | ph :: pt, [] -> print_endline " LIST <-> []";
+ if (ph = "_" || ph = (Printer.print sym true)) then is_matching_pattern sym pt [] matched && true else false
+ | _, _ -> matched
+
let rec expand ast env args sym meta =
- print_endline (" THIS IS A MACRO: " ^ Printer.print sym true);
+ print_endline ("\n\nTHIS IS A MACRO: " ^ Printer.print sym true);
print_endline (" META: " ^ Printer.print meta true);
print_endline (" ARGS: " ^ Printer.dump args);
print_endline (" AST: " ^ Printer.print ast true);
@@ -21,38 +30,28 @@
let literals = Types.M9map.find Types.macro_literals m in
let transformers = Types.M9map.find Types.macro_transformers m in
print_endline
- ("--EVAL_MACRO: literals: "
+ (" -- EVAL_MACRO: literals: "
^ Printer.print literals true
- ^ " transformers: "
+ ^ " transformers: "
^ Printer.print transformers true);
let rec match_transform transforms =
match transforms with
| hd :: tl ->
- print_endline ("__ hd: " ^ Printer.print hd true);
- print_endline ("__ args: " ^ Printer.dump args);
+ print_endline (" __ hd: " ^ Printer.print hd true);
+ print_endline (" __ args: " ^ Printer.dump args);
(match hd with
| T.List
{ T.value = [ T.List { T.value = pattern }; T.List { T.value = template } ] }
->
- print_endline (" _ multi pattern: " ^ Printer.dump pattern)
+ print_endline (" _ multi pattern: " ^ Printer.dump pattern); match_transform tl
| T.List { T.value = [ T.List { T.value = pattern }; atom ] } ->
- let rec foobar p a pp =
- (match p, a with
- | ph :: pt, ah :: at ->
- print_endline "one"; foobar pt at (pp @ [T.Nil])
- | ph :: pt, [] ->
- print_endline "two"; foobar pt [] (pp @ [T.Nil])
- | _, _ -> print_endline ("three: " ^ Printer.dump pp); pp) in
- print_endline ("foobar: " ^ Printer.dump (foobar pattern args []));
- print_endline "out";
- (* let tweaked = Str.global_replace (Str.regexp "^_") (Printer.print sym true) (Printer.dump pattern) in
- * print_endline ("tweaked: " ^ tweaked); *)
- print_endline (" _ single pattern: " ^ Printer.dump pattern)
- | _ -> ());
- match_transform tl
- | [] -> ()
+ print_endline (" _ single pattern: " ^ Printer.dump pattern);
+ print_endline ("matched?: " ^ (if is_matching_pattern sym (List.map (fun x -> Printer.print x true) pattern) args true then "yes" else "no"));
+ if is_matching_pattern sym (List.map (fun x -> Printer.print x true) pattern) args true then atom else match_transform tl
+ | _ -> ast)
+ | [] -> ast
in
match_transform (Core.seq transformers)
with
- | Not_found -> ())
- | _ -> ()
+ | Not_found -> ast)
+ | _ -> ast
--- a/mkfile
+++ b/mkfile
@@ -8,7 +8,8 @@
reader.ml\
printer.ml\
core.ml\
- macro.ml
+ macro.ml\
+ eval.ml
$BIN:
ocamlc str.cma -g -o $target $FILES m9.ml