From 5f2a55a60cfd4c67b175fb1c93d3bc75fe942d3c Mon Sep 17 00:00:00 2001 From: rhysd Date: Thu, 4 Jun 2015 12:01:35 +0900 Subject: [PATCH] remove global variable and add Crisp::Interpreter class --- README.md | 2 +- src/crisp.cr | 83 ++++++++++++++++++++++++++++++++-------------------- src/main.cr | 7 +++++ 3 files changed, 59 insertions(+), 33 deletions(-) mode change 100755 => 100644 src/crisp.cr create mode 100644 src/main.cr diff --git a/README.md b/README.md index 2906a68..d30165f 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ This project is a toy box for my dynamic language ideas. ## Installation 1. Install `crystal` command -2. `$ crystal run /path/to/Crisp/src/crisp.cr` +2. `$ crystal run /path/to/Crisp/src/main.cr` ## Development Environment diff --git a/src/crisp.cr b/src/crisp.cr old mode 100755 new mode 100644 index d410480..80f8103 --- a/src/crisp.cr +++ b/src/crisp.cr @@ -1,5 +1,3 @@ -#! /usr/bin/env crystal run - require "colorize" require "readline" @@ -244,41 +242,62 @@ module Crisp def rep(str) print(eval(read(str), $repl_env)) end -end -$repl_env = Crisp::Env.new nil -Crisp::NS.each{|k,v| $repl_env.set(k, Crisp::Type.new(v))} -$repl_env.set("eval", Crisp::Type.new -> (args: Array(Crisp::Type)){ Crisp.eval(args[0], $repl_env) }) -Crisp.rep "(def! not (fn* (a) (if a false true)))" -Crisp.rep "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))" -Crisp.rep "(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)))))))" -Crisp.rep "(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))))))))" -Crisp.rep("(def! *host-language* \"crystal\")") - -$argv = Crisp::List.new -$repl_env.set("*ARGV*", Crisp::Type.new $argv) - -unless ARGV.empty? - if ARGV.size > 1 - ARGV[1..-1].each do |a| - $argv << Crisp::Type.new(a) + class ProgramState + def rep(str) + print(eval(read(str), @env)) end - end - begin - Crisp.rep "(load-file \"#{ARGV[0]}\")" - rescue e - STDERR.puts e - exit 1 + def initialize(args) + @env = Crisp::Env.new nil + + Crisp::NameSpace.each{|k,v| @curent_env.set(k, Crisp::Type.new(v))} + + @env.set("eval", Crisp::Type.new -> (args: Array(Crisp::Type)){ Crisp.eval(args[0], @env) }) + + rep "(def! not (fn* (a) (if a false true)))" + rep "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))" + rep "(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)))))))" + rep "(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))))))))" + rep "(def! *host-language* \"crystal\")" + + argv = Crisp::List.new + + if args + args.each do |a| + argv << Crisp::Type.new a + end + end + + @env.set("*ARGV*", Crisp::Type.new argv) + end end - exit -end + class Interpreter + def initialize(args) + @state = ProgramState.new args + end -while line = Readline.readline("Crisp> ", true) - begin - puts Crisp.rep(line) - rescue e - STDERR.puts e + def run(filename = nil) + if filename + begin + Crisp.rep "(load-file \"#{filename}\")" + rescue e + STDERR.puts e + exit 1 + end + + exit + end + + while line = Readline.readline("Crisp> ", true) + begin + puts @state.rep(line) + rescue e + STDERR.puts e + end + end + end end end + diff --git a/src/main.cr b/src/main.cr new file mode 100644 index 0000000..5f1dba7 --- /dev/null +++ b/src/main.cr @@ -0,0 +1,7 @@ +require "./crisp" + +if ARGV.empty? + Crisp::Interpreter.new.run +else + Crisp::Interpreter.new(ARGV[1..-1]).run(ARGV.first) +end