diff options
| author | Joel Martin <github@martintribe.org> | 2014-04-10 23:08:42 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-04-10 23:08:42 -0500 |
| commit | 46dbc0d87a8ceee9255808ee28792d625bc317fc (patch) | |
| tree | f9b311e4f71391d75ef4c79e27099c24f7e19461 | |
| parent | 7d2dad89d2af01e1ca457659b0261859633fbcd8 (diff) | |
| download | mal-46dbc0d87a8ceee9255808ee28792d625bc317fc.tar.gz mal-46dbc0d87a8ceee9255808ee28792d625bc317fc.zip | |
Ruby: add step6_file
| -rw-r--r-- | ruby/reader.rb | 5 | ||||
| -rw-r--r-- | ruby/step6_file.rb | 110 |
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 |
