diff options
| author | Joel Martin <github@martintribe.org> | 2014-04-10 22:52:26 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-04-10 22:52:26 -0500 |
| commit | 7d2dad89d2af01e1ca457659b0261859633fbcd8 (patch) | |
| tree | 527eb02bc588d23206d9c8c5985025640179eecb | |
| parent | 8bf53bec72d27d7d895b39812ffae1e990425158 (diff) | |
| download | mal-7d2dad89d2af01e1ca457659b0261859633fbcd8.tar.gz mal-7d2dad89d2af01e1ca457659b0261859633fbcd8.zip | |
Ruby: add step5_tco
Function type in types extends Proc.
| -rw-r--r-- | ruby/step5_tco.rb | 98 | ||||
| -rw-r--r-- | ruby/types.rb | 18 |
2 files changed, 116 insertions, 0 deletions
diff --git a/ruby/step5_tco.rb b/ruby/step5_tco.rb new file mode 100644 index 0000000..8eb73c8 --- /dev/null +++ b/ruby/step5_tco.rb @@ -0,0 +1,98 @@ +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 + +# 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 02ca7a6..16d8d1e 100644 --- a/ruby/types.rb +++ b/ruby/types.rb @@ -1,6 +1,24 @@ +require "env" + class List < Array end class Vector < Array end +class Function < Proc + attr_accessor :ast + attr_accessor :env + attr_accessor :params + + def initialize(ast=nil, env=nil, params=nil, &block) + super() + @ast = ast + @env = env + @params = params + end + + def gen_env(args) + return Env.new(@env, @params, args) + end +end |
