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