require "colorize" require "readline" require "./reader" require "./printer" require "./expr" require "./env" require "./core" require "./error" require "./evaluator" module Crisp class Interpreter def initialize(args = nil) @printer = Printer.new @evaluator = Evaluator.new @env = Crisp::Env.new Crisp::NameSpace.each { |k, v| @env.set(k, Crisp::Expr.new(v)) } @env.set("eval", Crisp::Expr.new ->(args : Array(Crisp::Expr)) { @evaluator.eval(args[0], @env) }) eval_string "(def! not (fn* (a) (if a false true)))" eval_string "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))" eval_string "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))" eval_string "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))" eval_string "(def! *host-language* \"crystal\")" argv = Crisp::List.new if args args.each do |a| argv << Crisp::Expr.new a end end @env.set("*ARGV*", Crisp::Expr.new argv) end def read(str) Crisp.read_str str end def print(result) @printer.print(result) end def eval_string(str) @evaluator.eval(read(str), @env) end def eval(t : Crisp::Expr) @evaluator.eval(t, @env) end def eval(val) @evaluator.eval(Crisp::Expr.new val, @env) end def run(filename = nil) if filename eval_string "(load-file \"#{filename}\")" return end while line = Readline.readline("Crisp> ", true) begin puts self.print(eval_string(line)) rescue e puts e.message end end end end end