shithub: martian9

Download patch

ref: d7be189053b324fd57d4ca0ad2cbfa560d4c7876
parent: 778e0a846e76d2118f2917637eef1b7580331727
author: smazga <smazga@greymanlabs.com>
date: Wed Aug 5 12:32:11 EDT 2020

added some eval

--- a/mars9.ml
+++ b/mars9.ml
@@ -1,5 +1,5 @@
 (*
-  Martian Scheme9
+  Martian Scheme
   Copyright 2020, McKay Marston
 
   This is a project for me to
@@ -6,22 +6,73 @@
     1) Get more familiar with OCaml.
     2) Try to provide a natively supported scheme for Plan9.
 
-  It is heavily inspired by s9fes (http://www.t3x.org/s9fes), and the 
+  It is heavily inspired by s9fes (http://www.t3x.org/s9fes), and the
   make a lisp project (https://github.com/kanaka/mal)
  *)
-let nameplate = "Martian Scheme9 v0.1"
 
-let read str = str
-let eval ast any = ast
-let print exp = exp
-let rep str = print (eval (read str) "")
+module T = Types.Types
 
+module Env = Map.Make (String
+(*(struct
+  type t = Types.Symbol
+  let compare (Types.Symbol a) (Types.Symbol b) = compare a b
+  end)*))
+
+(* replace me *)
+let num_fun f =
+  Types.proc (function
+      | [ T.Number a; T.Number b ] -> T.Number (f a b)
+      | _ -> raise (Invalid_argument "Expected numeric argument"))
+;;
+
+(* replace me *)
+let repl_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
+  | T.Symbol { T.value = s } ->
+    (try Env.find s !env with
+    | Not_found -> raise (Invalid_argument ("Symbol '" ^ s ^ "' not found")))
+  | 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 eval ast env =
+  let result = eval_ast ast env in
+  match result with
+  | T.List { T.value = T.Proc { T.value = f } :: args } -> f args
+  | _ -> result
+;;
+
+let nameplate = "Martian9 Scheme v0.1"
+let read str = Reader.read_str str
+let print exp = Printer.print exp true
+let rep str env = print (eval (read str) env)
+
 let rec main =
   try
     print_endline nameplate;
     while true do
       print_string "m9> ";
-      print_endline (rep (read_line ()));
+      let line = read_line () in
+      try print_endline (rep line repl_env) with
+      | End_of_file -> ()
+      | Invalid_argument x ->
+        output_string stderr ("Invalid argument: " ^ x ^ "\n");
+        flush stderr
     done
-  with End_of_file -> ()
-
+  with
+  | End_of_file -> ()
+;;
--- a/mkfile
+++ b/mkfile
@@ -1,7 +1,7 @@
-BIN=mars9
+BIN=m9
 
-$BIN: $BIN.cmx
-	ocamlopt -o $target $prereq
+$BIN: types.cmx printer.cmx reader.cmx $BIN.cmx
+	ocamlopt -o $target str.cmxa $prereq
 
 %.cmx : %.ml
 	ocamlopt -c $stem.ml
--- a/reader.ml
+++ b/reader.ml
@@ -1,1 +1,54 @@
-let read_str str = (read_form 
+module T = Types.Types
+
+let token_re = Str.regexp "~@\\|[][{}()'`~^@]\\|\"\\(\\\\.\\|[^\"]\\)*\"?\\|;.*\\|[^][  \n{}('\"`,;)]*"
+let string_re = Str.regexp "\"\\(\\\\.\\|[^\\\\\"]\\)*\""
+
+type reader = { form : Types.m9type; tokens : string list }
+type list_reader = { list_form : Types.m9type list; tokens : string list }
+
+let tokenize str =
+  List.map
+    (function Str.Delim x -> x | Str.Text x -> "botch")
+    (List.filter (function Str.Delim x -> true | Str.Text x -> false) (Str.full_split token_re str))
+
+let read_atom token =
+  match token with
+  | "null"  -> T.Nil
+  | "true"  -> T.Bool true
+  | "false" -> T.Bool false
+  | _       -> (
+      match token.[0] with
+      | '0' .. '9' -> T.Number (int_of_string token)
+      | '-'        -> (
+          match String.length token with
+          | 1 -> Types.symbol token
+          | _ -> ( match token.[1] with '0' .. '9' -> T.Number (int_of_string token) | _ -> Types.symbol token ) )
+      | '"'        -> T.String token (* TODO: unescape *)
+      | _          -> Types.symbol token )
+
+let rec read_list eol list_reader =
+  match list_reader.tokens with
+  | []              ->
+      print_endline "unexpected EOF";
+      raise End_of_file
+  | token :: tokens ->
+      if Str.string_match (Str.regexp eol) token 0 then
+        { list_form = list_reader.list_form; tokens }
+      else
+        let reader = read_form list_reader.tokens in
+        read_list eol { list_form = list_reader.list_form @ [ reader.form ]; tokens = reader.tokens }
+
+and read_form all_tokens =
+  match all_tokens with
+  | []              -> raise End_of_file
+  | token :: tokens -> (
+      match token with
+      | "("  ->
+          let list_reader = read_list ")" { list_form = []; tokens } in
+          { form = Types.list list_reader.list_form; tokens = list_reader.tokens }
+      | "#|" ->
+          let list_reader = read_list "|#" { list_form = []; tokens } in
+          { form = T.Comment; tokens = list_reader.tokens }
+      | _    -> if token.[0] = ';' then read_form tokens else { form = read_atom token; tokens } )
+
+let read_str str = (read_form (tokenize str)).form