Permalink
Browse files

Various fixes, improvements and implementation of array

  • Loading branch information...
Josep M. Bach
Josep M. Bach committed Sep 20, 2011
1 parent 680d411 commit 82d2e6b710e0c1a008989db405b3c384dd6017c2
View
@@ -33,7 +33,7 @@ def compile(context)
class Identifier < Struct.new(:name, :deref)
def compile(context)
if deref
- context.current_receiver.slots[name]
+ context.current_receiver.send(name)
else
context.lookup_var(name)
end
@@ -86,15 +86,44 @@ def ==(other)
end
def to_s
- "#{val.to_s}"
+ eval("\"#{val}\"")
end
end
class Tuple < Struct.new(:body)
def compile(context)
- body.inject({}) do |a,e|
+ Tuple.new(body.inject({}) do |a,e|
a.update(e.first.to_s => e.last.compile(context))
- end
+ end)
+ end
+ end
+
+ class Array < Struct.new(:body)
+ def compile(context)
+ Array.new(body.map do |element|
+ element.compile(context)
+ end)
+ end
+
+ def send(message)
+ __send__ message.name
+ end
+
+ define_method('push') do
+ lambda {|context, *args|
+ element = args.first
+ body.push(element.compile(context))
+ }
+ end
+
+ define_method('each') do
+ lambda { |context, fun|
+ method = fun.compile(context)
+
+ body.each do |element|
+ method.call(context, element)
+ end
+ }
end
end
View
@@ -34,9 +34,10 @@ def initialize(parent_context = nil)
end
def lookup_var(symbol)
- result = @lvars[symbol.to_s] ||
- (@parent.lookup_var(symbol.to_s) if @parent)
- return result || raise("Undefined local variable: #{symbol}")
+ return @lvars[symbol.to_s] if !@lvars[symbol.to_s].nil?
+ return @parent.lookup_var(symbol.to_s) if @parent && !@parent.lookup_var(symbol.to_s).nil?
+
+ raise("Undefined local variable: #{symbol}")
end
def store_var(symbol, value)
View
@@ -6,11 +6,16 @@ def call(context, *args)
ctx = Context.new(context)
ctx.current_receiver = context.current_receiver
+
params.each_with_index do |param, idx|
- if passed_value = args[idx]
+ if !(passed_value = args[idx]).nil?
# Try to get the value from the context, or from the current receiver
- compiled_value = passed_value.compile(ctx) || ctx.current_receiver.send(passed_value)
+ if !passed_value.compile(ctx).nil?
+ compiled_value = passed_value.compile(ctx)
+ else
+ compiled_value = ctx.current_receiver.send(passed_value)
+ end
ctx.store_var(param.name, compiled_value)
elsif param.is_a?(AST::DefaultParameter)
View
@@ -19,7 +19,7 @@ def initialize
tuple = args.shift
if context && tuple
- tuple.compile(context).each do |k, v|
+ tuple.compile(context).body.each do |k, v|
child.slots[k] = v
end
end
@@ -33,7 +33,7 @@ def initialize
})
add_slot('each', lambda { |context, fun|
- yieldable = self.slots.delete_if do |k,v|
+ yieldable = self.slots.dup.delete_if do |k,v|
Object::PROTECTED_SLOTS.include?(k)
end
@@ -70,7 +70,7 @@ def lookup_traits(message)
trait = @traits.find do |trait|
trait.implements?(message)
end
- trait.slots[message] if trait
+ trait.slots.body[message] if trait
end
end
end
@@ -34,6 +34,7 @@ rule
digit : DIGIT { result = AST::Digit.new(val[0]) }
string : STRING { result = AST::String.new(val[0]) }
tuple : '{' tuple_elements '}' { result = AST::Tuple.new(val[1]) }
+ array : '[' array_elements ']' { result = AST::Array.new(val[1]) }
tuple_element : IDENTIFIER ':' argument { result = {val[0] => val[2]} }
| end_of_statement tuple_element { result = val[1] }
@@ -43,9 +44,18 @@ rule
| tuple_element { result.merge!(val[0]) }
| tuple_elements COMMA tuple_element { result.merge!(val[2]) }
+ array_element : argument { result = val[0] }
+ | end_of_statement array_element { result = val[1] }
+ | array_element end_of_statement { result = val[0]}
+
+ array_elements : { result = [] }
+ | array_element { result = [].push(val[0]) }
+ | array_elements COMMA array_element { result.push(val[2]) }
+
literal : digit
| string
| tuple
+ | array
| fun_definition
| boolean_literal
| operation

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -7,7 +7,7 @@ def initialize(tuple)
end
def implements?(message)
- @slots.key?(message)
+ @slots.body.key?(message)
end
end
end
View
@@ -29,9 +29,9 @@ def test_clone_with_tuple
end
def test_uses
- trait = Noscript::Trait.new({
+ trait = Noscript::Trait.new(Noscript::AST::Tuple.new({
'foo' => lambda { |*| Noscript::AST::Digit.new(3) }
- })
+ }))
@context.store_var('FooTrait', trait)
@object.send('uses').call(@context, Noscript::AST::Identifier.new('FooTrait'))
View
@@ -0,0 +1,55 @@
+require 'test_helper'
+
+class ArrayTest < MiniTest::Unit::TestCase
+
+ include Noscript::AST
+
+ def test_empty_array
+ parses "[]" do |nodes|
+ array = nodes.first
+
+ assert_kind_of Noscript::AST::Array, array
+ assert_equal([], array.body)
+ end
+ end
+
+ def test_array_with_one_element
+ parses "[1]" do |nodes|
+ array = nodes.first
+
+ assert_kind_of Noscript::AST::Array, array
+ assert_equal([Digit.new(1)], array.body)
+ end
+ end
+
+ def test_array_with_multiple_elements
+ parses "[1, 2]" do |nodes|
+ array = nodes.first
+
+ assert_kind_of Noscript::AST::Array, array
+ assert_equal([Digit.new(1), Digit.new(2)], array.body)
+ end
+ end
+
+ def test_array_with_multiple_identifiers
+ parses "[foo, bar]" do |nodes|
+ array = nodes.first
+
+ assert_kind_of Noscript::AST::Array, array
+ assert_equal([Identifier.new('foo'), Identifier.new('bar')], array.body)
+ end
+ end
+
+ def test_array_multiline
+ parses "[
+ foo,
+ bar
+ ]" do |nodes|
+ array = nodes.first
+
+ assert_kind_of Noscript::AST::Array, array
+ assert_equal([Identifier.new('foo'), Identifier.new('bar')], array.body)
+ end
+ end
+
+end
View
@@ -23,17 +23,17 @@ def setup
])
)
- @trait = Noscript::Trait.new({
+ @trait = Noscript::Trait.new(Noscript::AST::Tuple.new({
'foo' => @method_foo,
'bar' => @method_bar
- })
+ }))
end
def test_initialize
- assert_equal({
+ assert_equal(Noscript::AST::Tuple.new({
'foo' => @method_foo,
'bar' => @method_bar
- }, @trait.slots)
+ }), @trait.slots)
end
def test_implements

0 comments on commit 82d2e6b

Please sign in to comment.