shithub: martian9

Download patch

ref: 78448532a8c1c72d3220a9289cf1bb9f872a8886
parent: 4853f4341f2d0fa254630faf24e8a0eed55d8b63
author: smazga <smazga@greymanlabs.com>
date: Wed Aug 12 13:15:54 EDT 2020

initial macro work, added (define (x y z)) syntax

--- a/core.ml
+++ b/core.ml
@@ -24,6 +24,15 @@
   | _ -> []
 ;;
 
+(* this is 'assoc' from mal, but it's not what assoc is in scheme *)
+let rec link = function
+  | c :: k :: v :: (_ :: _ as xs) -> link (link [ c; k; v ] :: xs)
+  | [ T.Nil; k; v ] -> Types.map (Types.M9map.add k v Types.M9map.empty)
+  | [ T.Map { T.value = m; T.meta }; k; v ] ->
+    T.Map { T.value = Types.M9map.add k v m; T.meta }
+  | _ -> T.Nil
+;;
+
 let init env =
   Env.set
     env
--- a/m9.ml
+++ b/m9.ml
@@ -4,10 +4,11 @@
 
   This is a project for me to
     1) Get more familiar with OCaml.
-    2) Try to provide a natively supported scheme for Plan9.
+    2) Try to provide a natively supported r7rs-small scheme for Plan9.
 
   It is heavily inspired by s9fes (http://www.t3x.org/s9fes), and the
-  make a lisp project (https://github.com/kanaka/mal)
+  make a lisp project (https://github.com/kanaka/mal - thanks
+  https://github.com/chouser for the fantastic implementation!)
  *)
 
 module T = Types.Types
@@ -72,26 +73,25 @@
 and eval ast env =
   match ast with
   | T.List { T.value = [] } -> ast
+  | 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 (" ^ String.concat " " (List.map (fun x -> Printer.print x false) rest) ^ ") " ^ 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 = "let" }; T.Vector { T.value = bindings }; body ]
-      }
-  | T.List
-      { T.value = [ T.Symbol { T.value = "let" }; T.List { T.value = bindings }; body ] }
+  | T.List { T.value = [ T.Symbol { T.value = "define-syntax" }; keyword; transformer ] }
     ->
-    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
+    (match eval transformer env with
+    | T.Proc { T.value = p; T.meta } ->
+      let proc =
+        T.Proc { T.value = p; meta = Core.link [ meta; Core.kw_macro; T.Bool true ] }
+      in
+      Env.set env keyword proc;
+      proc
+    | _ -> raise (Reader.Syntax_error "transformer value must be syntax-rules"))
   | T.List
       { T.value =
           [ T.Symbol { T.value = "lambda" }; T.Vector { T.value = arg_names }; expr ]
@@ -104,7 +104,7 @@
         let sub_env = Env.make (Some env) in
         let rec bind_args a b =
           match a, b with
-          | [ T.Symbol { T.value = "&" }; name ], args ->
+          | [ T.Symbol { T.value = "." }; name ], args ->
             Env.set sub_env name (Types.list args)
           | name :: names, arg :: args ->
             Env.set sub_env name arg;
@@ -114,6 +114,22 @@
         in
         bind_args arg_names args;
         eval expr sub_env)
+  | 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 ] } ->