diff --git a/schemer_app/visual_interpreter/environment.rb b/schemer_app/visual_interpreter/environment.rb index fc439a3..4f1f175 100644 --- a/schemer_app/visual_interpreter/environment.rb +++ b/schemer_app/visual_interpreter/environment.rb @@ -1,6 +1,8 @@ class Environment attr_reader :frame, :label, :outer_env, :children + class UnboundVariable < StandardError; end + def initialize(frame, outer_env=nil) @frame = frame @label = Hash.new @@ -9,45 +11,39 @@ def initialize(frame, outer_env=nil) if outer_env outer_env.children << self end - end def self.global_env - Environment.new({:car => lambda{|lat| lat[0]}, - :cdr => lambda{|lat| lat.drop(1)}, - :cons => lambda{|a, lat| [a] + lat}, - :+ => lambda{|x,y| x + y}, - :- => lambda{|x,y| x - y}, - :* => lambda{|x,y| x * y}, - :/ => lambda{|x,y| x / y}, - :** => lambda{|x,y| x ** y}, - :"=" => lambda{|x,y| x == y}, - :">" => lambda{|x,y| x > y}, - :"<" => lambda{|x,y| x < y} - - }) + Environment.new :car => lambda {|lat| lat[0]}, + :cdr => lambda {|lat| lat.drop(1)}, + :cons => lambda {|a, lat| [a] + lat}, + :+ => lambda {|x,y| x + y}, + :- => lambda {|x,y| x - y}, + :* => lambda {|x,y| x * y}, + :/ => lambda {|x,y| x / y}, + :** => lambda {|x,y| x ** y}, + :"=" => lambda {|x,y| x == y}, + :">" => lambda {|x,y| x > y}, + :"<" => lambda {|x,y| x < y} end def env_binding(var) # the environment that binds variable var if frame.has_key?(var) self - else outer_env.env_binding(var) + elsif outer_env + outer_env.env_binding(var) + else + raise UnboundVariable, "The variable `#{var}' has no value in this context!" end end def printable?(x) - (x[0] != :define) and (x[0] != :set!) and (x[0] != :lambda) + ![:define, :set!, :lambda].include?(x[0]) end def value(x) - if x.is_a? Symbol # x is a variable - return env_binding(x).frame[x] - else - end - if not x.is_a? Array # x is an atom - return x - else - end + return env_binding(x).frame[x] if x.is_a? Symbol # x is a variable + return x if not x.is_a? Array # x is an atom case x[0] when :define frame[x[1]] = value(x[2]) @@ -55,19 +51,20 @@ def value(x) when :lambda lambda{ |*args| Environment.new(Hash[x[1].zip(args)], self).value(x[2]) } when :if - value(x[1]) == true ? value(x[2]) : value(x[3]) + value(x[1]) ? value(x[2]) : value(x[3]) when :quote x[1] when :begin + ret = nil for exp in x.drop(1) do - value(exp) + ret = value(exp) end - return value(x.last) + ret when :set! begin env_binding(x[1]).frame[x[1]] = value(x[2]) env_bindings(x[1]).label[x[1]] = x[2] - rescue + rescue UnboundVariable ". . . oops, #{x[1]} can't be set as it isn't defined" end else @@ -76,4 +73,4 @@ def value(x) end end -end \ No newline at end of file +end diff --git a/schemer_app/visual_interpreter/tree.rb b/schemer_app/visual_interpreter/tree.rb index 70e9860..933aec1 100644 --- a/schemer_app/visual_interpreter/tree.rb +++ b/schemer_app/visual_interpreter/tree.rb @@ -7,13 +7,16 @@ def self.structure(root) def self.process_frame(frame, label) frame2 = frame.dup - string = frame2.each { |k,v| frame2[k] = schemify(label[k]) if v.class == Proc }.to_s - string.gsub('"', '').gsub(":", "").gsub("=>", ": ") + string = frame2.each { |k,v| frame2[k] = schemify(label[k]) if v.is_a? Proc }.to_s + string.delete('":').gsub("=>", ": ") end def self.schemify(array) - string = array.to_s - string.gsub("[", "(").gsub("]",")").gsub(":", "").gsub(",","") + if array.is_a? Array + "(#{array.map {|e| schemify e}.join ?\s})" + else + array.to_s + end end -end \ No newline at end of file +end