aboutsummaryrefslogtreecommitdiff
path: root/ruby
diff options
context:
space:
mode:
Diffstat (limited to 'ruby')
-rw-r--r--ruby/env.rb28
-rw-r--r--ruby/step3_env.rb70
2 files changed, 98 insertions, 0 deletions
diff --git a/ruby/env.rb b/ruby/env.rb
new file mode 100644
index 0000000..dfd5ec9
--- /dev/null
+++ b/ruby/env.rb
@@ -0,0 +1,28 @@
+class Env
+ attr_accessor :data
+ def initialize(outer=nil, binds=[], exprs=[])
+ @data = {}
+ @outer = outer
+ end
+
+ def find(key)
+ if @data.key? key
+ return self
+ elsif @outer
+ return @outer.find(key)
+ else
+ return nil
+ end
+ end
+
+ def set(key, value)
+ @data[key] = value
+ return value
+ end
+
+ def get(key)
+ env = find(key)
+ raise "'" + key.to_s + "' not found" if not env
+ env.data[key]
+ end
+end
diff --git a/ruby/step3_env.rb b/ruby/step3_env.rb
new file mode 100644
index 0000000..97be81d
--- /dev/null
+++ b/ruby/step3_env.rb
@@ -0,0 +1,70 @@
+require "readline"
+require "types"
+require "reader"
+require "printer"
+require "env"
+
+# read
+def READ(str)
+ return read_str(str)
+end
+
+# eval
+def eval_ast(ast, env)
+ return case ast
+ when Symbol
+ env.get(ast)
+ when List
+ List.new ast.map{|a| EVAL(a, env)}
+ when Vector
+ Vector.new ast.map{|a| EVAL(a, env)}
+ else
+ ast
+ end
+end
+
+def EVAL(ast, env)
+ if not ast.is_a? List
+ return eval_ast(ast, env)
+ end
+
+ # apply list
+ a0,a1,a2,a3 = ast
+ case a0
+ when :"def!"
+ return env.set(a1, EVAL(a2, env))
+ when :"let*"
+ let_env = Env.new(env)
+
+ a1.each_slice(2) {|a,e| let_env.set(a, EVAL(e, let_env))}
+ return EVAL(a2, let_env)
+ else
+ el = eval_ast(ast, env)
+ f = el[0]
+ return f[*el.drop(1)]
+ end
+end
+
+# print
+def PRINT(exp)
+ return _pr_str(exp, true)
+end
+
+# repl
+repl_env = Env.new
+REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
+_ref = lambda {|k,v| repl_env.set(k, v) }
+
+_ref[:+, lambda {|a,b| a + b}]
+_ref[:-, lambda {|a,b| a - b}]
+_ref[:*, lambda {|a,b| a * b}]
+_ref[:/, lambda {|a,b| a / b}]
+
+while line = Readline.readline("user> ", true)
+ begin
+ puts REP[line]
+ rescue Exception => e
+ puts "Error: #{e}"
+ puts "\t#{e.backtrace.join("\n\t")}"
+ end
+end