shithub: martian9

Download patch

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