From e6621de92a817559ca0b94bdce80a47916d5ccac Mon Sep 17 00:00:00 2001 From: Victor Hugo Borja Date: Fri, 17 Dec 2010 01:34:31 -0600 Subject: [PATCH 1/4] More specs for table objects. Reimplemented Table. --- lib/poison/bootstrap/compiler/compiler.rb | 52 +++++++++-------------- lib/poison/bootstrap/library/table.rb | 52 ++++++++++++++++++++--- spec/library/table_spec.rb | 40 +++++++++++++++++ 3 files changed, 105 insertions(+), 39 deletions(-) diff --git a/lib/poison/bootstrap/compiler/compiler.rb b/lib/poison/bootstrap/compiler/compiler.rb index bc40039..bbd552f 100644 --- a/lib/poison/bootstrap/compiler/compiler.rb +++ b/lib/poison/bootstrap/compiler/compiler.rb @@ -113,42 +113,30 @@ def imaginary(node) # backed by a ruby Hash, otherwise its backed by a ruby List. # def table(node) - if node.entries.any? { |e| e.kind_of?(Syntax::Assign) } - # A hash, all entries not being an assign, get a value of nil - - g.push_cpath_top - g.find_const :Hash - g.push node.entries.size - g.send :new_from_literal, 1 - - node.entries.each do |entry| - g.dup - if entry.kind_of? Syntax::Assign - # if key is a single name, we use its string value as key - if entry.name.expressions.size == 1 && - entry.name.expressions.first.kind_of?(Syntax::Message) - g.push_literal entry.name.expressions.first.name - else - entry.name.visit self - end - entry.value.visit self + g.push_cpath_top + g.find_const :Table + g.send :new, 0 + + node.entries.each_with_index do |entry, index| + g.dup + g.push_literal index + + if entry.kind_of?(Syntax::Assign) + if entry.name.kind_of?(Syntax::Expression) && + entry.name.expressions.first.kind_of?(Syntax::Message) + g.push_literal entry.name.expressions.first.name.to_sym else - entry.visit self - g.push_nil + entry.name.visit self end - g.send :[]=, 2 - g.pop + entry.value.visit self + + g.send :put_key, 3 + else + entry.visit self + g.send :put_val, 2 end - else - # A list - node.entries.each { |entry| entry.visit self } - g.make_array node.entries.size + g.pop end - - g.push_cpath_top - g.find_const :Table - g.swap - g.send :new, 1 end end end diff --git a/lib/poison/bootstrap/library/table.rb b/lib/poison/bootstrap/library/table.rb index 1c9a1c6..dd2d4a9 100644 --- a/lib/poison/bootstrap/library/table.rb +++ b/lib/poison/bootstrap/library/table.rb @@ -1,20 +1,58 @@ -# A Table object is created using Poison table literals: +# Poison Table is inspired by Lua's but not necessarily having the +# same exact behaviour. +# +# A table can be used as a list of objects or as a map of key-values +# +# table objects are created using Poison table literals: # # Creates a "list" like object: -# (foo, bar) +# table = ("foo", "bar") +# table at(0) #=> "foo" +# table at(1) #=> "bar" # # Creates a "dictionary" like object: -# (foo, bar) +# table = (foo = "bar") +# table at(0) #=> "bar" +# table foo #=> "bar" +# # class Table - def initialize(collection) - @collection = collection + Slot = Struct.new(:index, :key, :value) + + def initialize + @ary = Array.new + @map = Hash.new + end + + def delete_at(index) + slot = @ary[index] + @map.delete @ary[index].key if slot && slot.key + @ary.delete_at index + end + + def put_val(index, value) + delete_at index + @ary[index] = Slot.new(index, nil, value) + value + end + + def key_accessor(key) + metaclass.send :define_method, "pn:#{key}", lambda { at(key) } + end + + def put_key(index, key, value) + delete_at index + @map[key] = @ary[index] = Slot.new(index, key, value) + key_accessor key if key.kind_of?(Symbol) + value end - def pn_at(key) - @collection[key] + def at(key) + return @map[key].value if @map.key?(key) + @ary[key].value if @ary[key] end + alias_method :pn_at, :at poison_methods diff --git a/spec/library/table_spec.rb b/spec/library/table_spec.rb index caea658..f7afb4d 100644 --- a/spec/library/table_spec.rb +++ b/spec/library/table_spec.rb @@ -11,3 +11,43 @@ table.should be_kind_of(Table) end end + +describe "Table#at" do + it "is access values by index" do + table = Poison::CodeLoader.execute "(9, 8, 7)" + table.poison(:at, 0).should == 9 + table.poison(:at, 1).should == 8 + table.poison(:at, 2).should == 7 + end + + it "is access values by key" do + table = Poison::CodeLoader.execute "(a = 1, b = 2, c = 3)" + table.poison(:at, :b).should == 2 + end + + it "is access value by key or index" do + table = Poison::CodeLoader.execute "(9, b = 2, 7)" + table.poison(:at, 0).should == 9 + table.poison(:at, :b).should == 2 + table.poison(:at, 1).should == 2 + table.poison(:at, 2).should == 7 + end + + it "is access value by key or index" do + table = Poison::CodeLoader.execute "('bar' = 90, 'foo' = 2)" + table.poison(:at, 1).should == 2 + table.poison(:at, "foo").should == 2 + end +end + +describe "Table accessor" do + it "is generated for an assign having a name as left hand side" do + table = Poison::CodeLoader.execute "(9, foo = 42, 'bar' = 7)" + table.poison(:foo).should == 42 + end + + it "is not generated for an assign having an expression as left hand side" do + table = Poison::CodeLoader.execute "(9, foo = 42, 'bar' = 7)" + table.should_not respond_to("pn:bar") + end +end From ad9a18c489857eb93d76062658fc9bb7dd148161 Mon Sep 17 00:00:00 2001 From: Victor Hugo Borja Date: Fri, 17 Dec 2010 01:36:10 -0600 Subject: [PATCH 2/4] Fixed some specs description. --- spec/library/table_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/library/table_spec.rb b/spec/library/table_spec.rb index f7afb4d..cee2a97 100644 --- a/spec/library/table_spec.rb +++ b/spec/library/table_spec.rb @@ -4,7 +4,7 @@ it "is created by a sequence of values in paretheses" do table = Poison::CodeLoader.execute "(1, 2, 3)" table.should be_kind_of(Table) - end + end it "is created by sequence of assignments in parentheses" do table = Poison::CodeLoader.execute "(a = 1, b = 2, c = 3)" @@ -13,19 +13,19 @@ end describe "Table#at" do - it "is access values by index" do + it "can access values by index" do table = Poison::CodeLoader.execute "(9, 8, 7)" table.poison(:at, 0).should == 9 table.poison(:at, 1).should == 8 table.poison(:at, 2).should == 7 end - it "is access values by key" do + it "can access values by key" do table = Poison::CodeLoader.execute "(a = 1, b = 2, c = 3)" table.poison(:at, :b).should == 2 end - it "is access value by key or index" do + it "can access value by named key or index" do table = Poison::CodeLoader.execute "(9, b = 2, 7)" table.poison(:at, 0).should == 9 table.poison(:at, :b).should == 2 @@ -33,7 +33,7 @@ table.poison(:at, 2).should == 7 end - it "is access value by key or index" do + it "can access value by expression key or index" do table = Poison::CodeLoader.execute "('bar' = 90, 'foo' = 2)" table.poison(:at, 1).should == 2 table.poison(:at, "foo").should == 2 From 58bdc5f33ac44c5286d191eafe17ba4d3c0d55a3 Mon Sep 17 00:00:00 2001 From: Victor Hugo Borja Date: Fri, 17 Dec 2010 01:43:31 -0600 Subject: [PATCH 3/4] Fixed indentation --- spec/library/table_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/library/table_spec.rb b/spec/library/table_spec.rb index cee2a97..3832f2f 100644 --- a/spec/library/table_spec.rb +++ b/spec/library/table_spec.rb @@ -4,7 +4,7 @@ it "is created by a sequence of values in paretheses" do table = Poison::CodeLoader.execute "(1, 2, 3)" table.should be_kind_of(Table) - end + end it "is created by sequence of assignments in parentheses" do table = Poison::CodeLoader.execute "(a = 1, b = 2, c = 3)" From 5c0de1c4896cf6d23d053d4d83d3265ca6c5730b Mon Sep 17 00:00:00 2001 From: Victor Hugo Borja Date: Fri, 17 Dec 2010 01:52:48 -0600 Subject: [PATCH 4/4] Removed obsolete comments. --- lib/poison/bootstrap/compiler/compiler.rb | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/lib/poison/bootstrap/compiler/compiler.rb b/lib/poison/bootstrap/compiler/compiler.rb index bbd552f..ee02f2b 100644 --- a/lib/poison/bootstrap/compiler/compiler.rb +++ b/lib/poison/bootstrap/compiler/compiler.rb @@ -91,27 +91,6 @@ def imaginary(node) end # Creates a Table object. - # - # A table is a container with index-access or key-access - # - # foo = ("bar", "baz") # a list - # foo at(0) # => "bar" - # - # foo = (bar = "baz") # a dict - # foo at("bar") # => "baz" - # - # From _why's Potion, it's unclear what the behaviour should - # be for a table created with a mix of assign and values - # - # foo = (bar = "baz", "bat") - # foo at(0) # => nil - # foo at('bar') # => "baz" - # foo at(1) # => nil - # - # So what we do for Poison is this: if we find any of the - # table expressions to be an assignment, then the table is - # backed by a ruby Hash, otherwise its backed by a ruby List. - # def table(node) g.push_cpath_top g.find_const :Table