aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-04-10 23:08:42 -0500
committerJoel Martin <github@martintribe.org>2014-04-10 23:08:42 -0500
commit46dbc0d87a8ceee9255808ee28792d625bc317fc (patch)
treef9b311e4f71391d75ef4c79e27099c24f7e19461
parent7d2dad89d2af01e1ca457659b0261859633fbcd8 (diff)
downloadmal-46dbc0d87a8ceee9255808ee28792d625bc317fc.tar.gz
mal-46dbc0d87a8ceee9255808ee28792d625bc317fc.zip
Ruby: add step6_file
-rw-r--r--ruby/reader.rb5
-rw-r--r--ruby/step6_file.rb110
2 files changed, 114 insertions, 1 deletions
diff --git a/ruby/reader.rb b/ruby/reader.rb
index 0c113e3..eddb319 100644
--- a/ruby/reader.rb
+++ b/ruby/reader.rb
@@ -17,7 +17,9 @@ end
def tokenize(str)
re = /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/
- return str.scan(re).map{|m| m[0]}.select{|m| m != ""}
+ return str.scan(re).map{|m| m[0]}.select{ |t|
+ t != "" && t[0..0] != ";"
+ }
end
def parse_str(t)
@@ -69,6 +71,7 @@ end
def read_str(str)
tokens = tokenize(str)
+ return nil if tokens.size == 0
return read_form(Reader.new(tokens))
end
diff --git a/ruby/step6_file.rb b/ruby/step6_file.rb
new file mode 100644
index 0000000..9d0324f
--- /dev/null
+++ b/ruby/step6_file.rb
@@ -0,0 +1,110 @@
+require "readline"
+require "types"
+require "reader"
+require "printer"
+require "env"
+require "core"
+
+# 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)
+ while true
+
+ 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) do |a,e|
+ let_env.set(a, EVAL(e, let_env))
+ end
+ return EVAL(a2, let_env)
+ when :do
+ eval_ast(ast[1..-2], env)
+ ast = ast.last
+ when :if
+ cond = EVAL(a1, env)
+ if not cond
+ return nil if a3 == nil
+ ast = a3
+ else
+ ast = a2
+ end
+ when :"fn*"
+ return Function.new(a2, env, a1) {|*args|
+ EVAL(a2, Env.new(env, a1, args))
+ }
+ else
+ el = eval_ast(ast, env)
+ f = el[0]
+ if f.class == Function
+ ast = f.ast
+ env = f.gen_env(el.drop(1))
+ else
+ return f[*el.drop(1)]
+ end
+ end
+
+ end
+end
+
+# print
+def PRINT(exp)
+ return _pr_str(exp, true)
+end
+
+# repl
+repl_env = Env.new
+RE = lambda {|str| EVAL(READ(str), repl_env) }
+REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
+_ref = lambda {|k,v| repl_env.set(k, v) }
+
+# Import core functions
+$core_ns.each &_ref
+
+_ref[:"read-string", lambda {|str| read_str str}]
+_ref[:eval, lambda {|ast| EVAL(ast, repl_env)}]
+_ref[:slurp, lambda {|f| File.read(f) }]
+
+# Defined using the language itself
+RE["(def! not (fn* (a) (if a false true)))"]
+RE["(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"]
+
+p Dir.pwd
+if ARGV.size > 0
+ ARGV.each {|f|
+ RE["(load-file \"" + f + "\")"]
+ }
+ exit 0
+end
+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