diff options
| author | Joel Martin <github@martintribe.org> | 2014-04-10 22:24:58 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-04-10 22:24:58 -0500 |
| commit | 8bf53bec72d27d7d895b39812ffae1e990425158 (patch) | |
| tree | a658f2900b9ceff44522780b3d5c28afb1abf0e2 | |
| parent | b5f469de182a3e95b2d968ddccf2e2f9b77a3dc2 (diff) | |
| download | mal-8bf53bec72d27d7d895b39812ffae1e990425158.tar.gz mal-8bf53bec72d27d7d895b39812ffae1e990425158.zip | |
Ruby: step4_if_fn_do with core functions.
| -rw-r--r-- | ruby/core.rb | 20 | ||||
| -rw-r--r-- | ruby/env.rb | 9 | ||||
| -rw-r--r-- | ruby/printer.rb | 4 | ||||
| -rw-r--r-- | ruby/reader.rb | 2 | ||||
| -rw-r--r-- | ruby/step3_env.rb | 7 | ||||
| -rw-r--r-- | ruby/step4_if_fn_do.rb | 89 | ||||
| -rw-r--r-- | ruby/types.rb | 1 |
7 files changed, 125 insertions, 7 deletions
diff --git a/ruby/core.rb b/ruby/core.rb new file mode 100644 index 0000000..268ebad --- /dev/null +++ b/ruby/core.rb @@ -0,0 +1,20 @@ +$core_ns = { + :"=" => lambda {|a,b| a == b}, + :"pr-str" => lambda {|*a| a.map {|e| _pr_str(e, true)}.join(" ")}, + :"str" => lambda {|*a| a.map {|e| _pr_str(e, false)}.join("")}, + :"prn" => lambda {|*a| puts(a.map {|e| _pr_str(e, true)}.join(" "))}, + :"println" => lambda {|*a| puts(a.map {|e| _pr_str(e, false)}.join(" "))}, + :< => lambda {|a,b| a < b}, + :<= => lambda {|a,b| a <= b}, + :> => lambda {|a,b| a > b}, + :>= => lambda {|a,b| a >= b}, + :+ => lambda {|a,b| a + b}, + :- => lambda {|a,b| a - b}, + :* => lambda {|a,b| a * b}, + :/ => lambda {|a,b| a / b}, + :list => lambda {|*a| List.new a}, + :list? => lambda {|*a| a[0].is_a? List}, + :empty? => lambda {|a| a.size == 0}, + :count => lambda {|a| a.size}, +} + diff --git a/ruby/env.rb b/ruby/env.rb index dfd5ec9..97dfa13 100644 --- a/ruby/env.rb +++ b/ruby/env.rb @@ -3,6 +3,15 @@ class Env def initialize(outer=nil, binds=[], exprs=[]) @data = {} @outer = outer + binds.each_index do |i| + if binds[i] == :"&" + data[binds[i+1]] = exprs.drop(i) + break + else + data[binds[i]] = exprs[i] + end + end + return self end def find(key) diff --git a/ruby/printer.rb b/ruby/printer.rb index 2d46e07..424ca23 100644 --- a/ruby/printer.rb +++ b/ruby/printer.rb @@ -9,9 +9,7 @@ def _pr_str(obj, print_readably=true) "[" + obj.map{|x| _pr_str(x, _r)}.join(" ") + "]" when String if _r - "\"" + obj.gsub(/\\/, "\\\\") \ - .gsub(/"/, "\\\\\"") \ - .gsub(/\n/, "\\\\n") + "\"" + obj.inspect # escape special characters else obj end diff --git a/ruby/reader.rb b/ruby/reader.rb index d224e9c..0c113e3 100644 --- a/ruby/reader.rb +++ b/ruby/reader.rb @@ -21,7 +21,7 @@ def tokenize(str) end def parse_str(t) - return t[1..-2].gsub(/\\"/, "\"").gsub(/\\n/, "\n") + return t[1..-2].gsub(/\\"/, '"').gsub(/\\n/, "\n") # unescape end def read_atom(rdr) diff --git a/ruby/step3_env.rb b/ruby/step3_env.rb index 97be81d..9d1c373 100644 --- a/ruby/step3_env.rb +++ b/ruby/step3_env.rb @@ -31,12 +31,13 @@ def EVAL(ast, env) # apply list a0,a1,a2,a3 = ast case a0 - when :"def!" + 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))} + a1.each_slice(2) do |a,e| + let_env.set(a, EVAL(e, let_env)) + end return EVAL(a2, let_env) else el = eval_ast(ast, env) diff --git a/ruby/step4_if_fn_do.rb b/ruby/step4_if_fn_do.rb new file mode 100644 index 0000000..e2e3e29 --- /dev/null +++ b/ruby/step4_if_fn_do.rb @@ -0,0 +1,89 @@ +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) + 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 + el = eval_ast(ast.drop(1), env) + return el.last + when :if + cond = EVAL(a1, env) + if not cond + return nil if a3 == nil + return EVAL(a3, env) + else + return EVAL(a2, env) + end + when :"fn*" + return lambda {|*args| + EVAL(a2, Env.new(env, a1, args)) + } + 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 +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 + +# Defined using the language itself +RE["(def! not (fn* (a) (if a false true)))"] + +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 diff --git a/ruby/types.rb b/ruby/types.rb index a7ce285..02ca7a6 100644 --- a/ruby/types.rb +++ b/ruby/types.rb @@ -3,3 +3,4 @@ end class Vector < Array end + |
