fsharp: step6: Added eval & file io.
authorPeter Stephens <code@diligentsoftware.com>
Sun, 5 Apr 2015 05:20:42 +0000 (00:20 -0500)
committerPeter Stephens <code@diligentsoftware.com>
Sun, 5 Apr 2015 05:20:42 +0000 (00:20 -0500)
fsharp/Makefile
fsharp/core.fs
fsharp/env.fs
fsharp/step6_file.fs [new file with mode: 0644]

index c49ccda..6316b26 100644 (file)
@@ -4,7 +4,7 @@ DEBUG =
 
 TESTS =
 
-SOURCES_BASE = types.fs printer.fs core.fs tokenizer.fs reader.fs env.fs \
+SOURCES_BASE = types.fs printer.fs tokenizer.fs reader.fs core.fs env.fs \
                eval.fs readline.fs
 SOURCES_LISP =
 SOURCES = $(SOURCES_BASE) $(SOURCES_LISP)
@@ -14,7 +14,7 @@ TERMINAL_SOURCES = terminal.cs
 #####################
 
 SRCS = step0_repl.fs step1_read_print.fs step2_eval.fs step3_env.fs \
-       step4_if_fn_do.fs step5_tco.fs
+       step4_if_fn_do.fs step5_tco.fs step6_file.fs
 
 FSFLAGS = $(if $(strip $(DEBUG)),--debug+,--debug- --optimize+ --tailcalls+)
 CSFLAGS = $(if $(strip $(DEBUG)),-debug+,)
index 607a115..2961f6c 100644 (file)
@@ -48,3 +48,16 @@ module Core
     let str nodes = nodes |> Printer.str |> String
     let prn nodes = nodes |> Printer.prn |> printfn "%s"; Nil
     let println nodes = nodes |> Printer.println |> printfn "%s"; Nil
+
+    let read_str = function
+        | [String(s)] ->
+            match Reader.read_str s with
+            | [node] -> node
+            | nodes -> List(Symbol("do")::nodes)
+        | [_] -> raise <| errArgMismatch ()
+        | _ -> raise <| errArity ()
+
+    let slurp = function
+        | [String(s)] -> System.IO.File.ReadAllText s |> String
+        | [_] -> raise <| errArgMismatch ()
+        | _ -> raise <| errArity ()
index 790b8f2..725aaf0 100644 (file)
@@ -63,7 +63,9 @@ module Env
               wrap "pr-str" Core.pr_str;
               wrap "str" Core.str;
               wrap "prn" Core.prn;
-              wrap "println" Core.println ]
+              wrap "println" Core.println;
+              wrap "read-string" Core.read_str;
+              wrap "slurp" Core.slurp ]
             |> ofList
         [ env ]
 
diff --git a/fsharp/step6_file.fs b/fsharp/step6_file.fs
new file mode 100644 (file)
index 0000000..6ca70ee
--- /dev/null
@@ -0,0 +1,81 @@
+module REPL
+    open System
+
+    let read input =
+        try
+            Reader.read_str input
+        with
+        | Types.ReaderError(msg) ->
+            printfn "%s" msg
+            []
+
+    let eval env ast =
+        try
+            Some(Eval.eval env ast)
+        with
+        | Types.EvalError(msg) ->
+            printfn "%s" msg
+            None
+
+    let print v =
+        v
+        |> Seq.singleton
+        |> Printer.pr_str
+        |> printfn "%s"
+
+    let re env input =
+        read input
+        |> Seq.ofList
+        |> Seq.choose (fun form -> eval env form)
+
+    let rep env input =
+        input
+        |> re env
+        |> Seq.iter (fun value -> print value)
+
+    let getReadlineMode args =
+        if args |> Array.exists (fun e -> e = "--raw") then
+            Readline.Mode.Raw
+        else
+            Readline.Mode.Terminal
+
+    let eval_func env = function
+        | [ast] -> Eval.eval env ast
+        | _ -> raise <| Core.errArity ()
+
+    let argv_func = function
+        | file::rest -> rest |> List.map Types.String |> Types.List
+        | [] -> Types.List([])
+
+    let configureEnv args =
+        let env = Env.makeRootEnv ()
+
+        Env.set env "eval" <| Env.makeBuiltInFunc (fun nodes -> eval_func env nodes)
+        Env.set env "*ARGV*" <| argv_func args
+
+        re env """
+            (def! not (fn* (a) (if a false true)))
+            (def! load-file (fn* (f) (eval (read-string (slurp f)))))
+            """ |> Seq.iter ignore
+
+        env
+
+    [<EntryPoint>]
+    let main args =
+        let mode = getReadlineMode args
+        let args = Seq.ofArray args |> Seq.filter (fun e -> e <> "--raw") |> List.ofSeq
+        let env = configureEnv args
+
+        match args with
+        | file::_ ->
+            System.IO.File.ReadAllText file
+            |> rep env
+            0
+        | _ ->
+            let rec loop () =
+                match Readline.read "user> " mode with
+                | null -> 0
+                | input ->
+                    rep env input
+                    loop ()
+            loop ()