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)
#####################
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+,)
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 ()
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 ]
--- /dev/null
+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 ()