Permalink
Browse files

Fix specs for op-shuffling on rb19

  • Loading branch information...
vic committed Sep 20, 2011
1 parent 7222cc1 commit 513bbef4f159a9452c6c6e40cd42f724594a004a
Showing with 94 additions and 64 deletions.
  1. +27 −27 lib/akin/shuffle.rb
  2. +4 −4 spec/operator_spec.rb
  3. +58 −32 spec/shuffle_spec.rb
  4. +5 −1 spec/spec_helper.rb
View
@@ -11,9 +11,9 @@ def operators(ary)
ops = []
ary.each_with_index do |node, idx|
op = @operators.operator(node, idx)
- ops << op if op
+ ops << op if op && !(ary[idx+1] && ary[idx+1].name == :send)
end
- ops.sort
+ ops
end
def shuffle(node)
@@ -32,18 +32,15 @@ def nothing(node)
alias_method :shuffle_text, :nothing
alias_method :shuffle_fixnum, :nothing
alias_method :shuffle_float, :nothing
+ alias_method :shuffle_oper, :nothing
def shuffle_block(node)
node.with(:block, *shuffle(node.args))
end
- def shuffle_oper(node)
- node.with(:name, *node.args)
- end
-
- def shuffle_act(node)
+ def shuffle_send(node)
a = node.args
- node.with(:act, a[0], a[1], *shuffle(a[2..-1]))
+ node.with(:send, a[0], *shuffle(a[1..-1]))
end
def shuffle_msg(node)
@@ -52,17 +49,20 @@ def shuffle_msg(node)
end
def shuffle_chain(node)
- ops = operators node.args
chain = node.args
- until ops.empty?
- chain = shuffle_op(ops.first, chain)
- ops.shift
+ ops = operators chain # sorted by position
+ ord = ops.sort # sorted by precedence
+ until ord.empty?
+ op = ord.first
+ chain = shuffle_op(op, chain, ops)
+ ord.shift
+ ops.delete op
end
chain = shuffle(chain)
chain.size == 1 && chain.first || node.with(:chain, *chain)
end
- def shuffle_op(op, chain)
+ def shuffle_op(op, chain, ops)
return chain if chain.empty? || chain == [op.node]
return chain unless idx = chain.index(op.node)
@@ -75,10 +75,12 @@ def shuffle_op(op, chain)
lhs, left = left, []
elsif op.arity_l >= 1
lhs = left.pop(op.arity_l)
+ elsif ops.first == op
+ lhs, left = left, []
else
- left.reverse!
- lhs = left.take_while { |n| !@operators.operator?(n) }.reverse
- left = left[lhs.size..-1].reverse
+ bwd = ops[ops.index(op) - 1]
+ from = left.index(bwd.node) + 1
+ lhs, left = left[from..-1], left[0...from]
end
end
@@ -87,22 +89,20 @@ def shuffle_op(op, chain)
rhs, right = right, []
elsif op.arity_r >= 1
rhs = right.shift(op.arity_r)
+ elsif ops.last == op
+ rhs, right = right, []
else
- rhs = right.take_while { |n| !@operators.operator?(n) }
- right = right[rhs.size..-1]
+ fwd = ops[ops.index(op) + 1]
+ to = right.index(fwd.node)
+ rhs, right = right[0...to], right[to..-1]
end
end
if lhs || rhs
- now = op.node.with(:act, op.name, nil)
- if lhs
- lhs = lhs.size == 1 && lhs.first || lhs.first.with(:chain, *lhs)
- now.args.push lhs
- end
- if rhs
- rhs = rhs.size == 1 && rhs.first || rhs.first.with(:chain, *rhs)
- now.args.push rhs
- end
+ lhs = lhs.size == 1 && lhs.first || lhs.first.with(:chain, *lhs) if lhs
+ rhs = rhs.size == 1 && rhs.first || rhs.first.with(:chain, *rhs) if rhs
+ now = [op.node.with(:oper, *op.node.args),
+ op.node.with(:send, nil, *(Array(lhs) + Array(rhs)))]
end
Array(left) + Array(now) + Array(right)
View
@@ -16,19 +16,19 @@
end
it 'with operators sorted by precedence' do
- subject.operators(c('+ *').args).map(&:name).should == ["*", "+"]
+ subject.operators(c('+ *').args).sort.map(&:name).should == ["*", "+"]
end
it 'with +,- operators sorted by fixity' do
- subject.operators(c('+ - +').args).map(&:name).should == ["+", "-", "+"]
+ subject.operators(c('+ - +').args).sort.map(&:name).should == ["+", "-", "+"]
end
it 'with +,-,* operators sorted by fixity' do
- subject.operators(c('+ - * +').args).map(&:name).should == ["*", "+", "-", "+"]
+ subject.operators(c('+ - * +').args).sort.map(&:name).should == ["*", "+", "-", "+"]
end
it 'with +,-,*,/ operators sorted by fixity' do
- subject.operators(c('+ - * + /').args).map(&:name).should ==
+ subject.operators(c('+ - * + /').args).sort.map(&:name).should ==
["/", "*", "+", "-", "+"]
end
View
@@ -6,84 +6,109 @@
describe 'basic math opers' do
it 'associates correctly + and *' do
- n('a + b * c - d').should ==
- [:chain,
- [:chain, [:name, "a"], [:oper, "+"],
- [:send, nil,
- [:chain, [:name, "b"], [:oper, "*"], [:send, nil, [:name, "c"]]]]],
+ n('a + b * c - d').should ==
+ [:chain,
+ [:name, "a"],
+ [:oper, "+"],
+ [:send, nil,
+ [:chain, [:name, "b"], [:oper, "*"], [:send, nil, [:name, "c"]]]],
[:oper, "-"],
[:send, nil, [:name, "d"]]]
end
+
+ it 'should not shuffle already shuffled operators' do
+ sexp = [:chain,
+ [:name, "a"],
+ [:oper, "+"],
+ [:send, nil,
+ [:chain, [:name, "b"], [:oper, "*"], [:send, nil, [:name, "c"]]]],
+ [:oper, "-"],
+ [:send, nil, [:name, "d"]]]
+ n = c('a + b * c - d')
+ s = shuffler.shuffle(n)
+ s.sexp.should == sexp
+ m = shuffler.shuffle(s)
+ m.sexp.should == sexp
+ end
end
-=begin
+
describe 'assignment' do
it 'takes lhs and rhs' do
n('a = b').should ==
- [:act, "=", nil, [:name, "a"], [:name, "b"]]
+ [:chain, [:oper, "="],
+ [:send, nil, [:name, "a"], [:name, "b"]]]
end
it 'has higher precedence than +' do
- n('a = b + c').should ==
- [:act, "=", nil,
- [:name, "a"],
- [:chain, [:name, "b"],
- [:act, "+", nil, [:name, "c"]]]]
+ [:chain, [:oper, "="],
+ [:send, nil, [:name, "a"],
+ [:chain, [:name, "b"], [:oper, "+"],
+ [:send, nil, [:name, "c"]]]]]
end
it 'has higher precedence than both + and *' do
n('a * d = b + c').should ==
- [:act, "=", nil,
- [:chain, [:name, "a"],
- [:act, "*", nil, [:name, "d"]]],
- [:chain, [:name, "b"],
- [:act, "+", nil, [:name, "c"]]]]
+ [:chain, [:oper, "="],
+ [:send, nil,
+ [:chain, [:name, "a"], [:oper, "*"], [:send, nil, [:name, "d"]]],
+ [:chain, [:name, "b"], [:oper, "+"], [:send, nil, [:name, "c"]]]]]
end
it 'is right associative' do
n('a = b = c').should ==
- [:act, "=", nil, [:name, "a"], [:act, "=", nil, [:name, "b"], [:name, "c"]]]
+ [:chain, [:oper, "="],
+ [:send, nil,
+ [:name, "a"], [:chain, [:oper, "="],
+ [:send, nil, [:name, "b"], [:name, "c"]]]]]
end
it 'is parsed correctly with &&' do
n('a && b = c').should ==
[:chain, [:name, "a"],
- [:act, "&&", nil, [:act, "=", nil, [:name, "b"], [:name, "c"]]]]
+ [:oper, "&&"],
+ [:send, nil,
+ [:chain, [:oper, "="], [:send, nil, [:name, "b"], [:name, "c"]]]]]
end
it 'is parsed correctly with and' do
n('a and b = c').should ==
[:chain, [:name, "a"],
- [:act, "and", nil, [:act, "=", nil, [:name, "b"], [:name, "c"]]]]
+ [:oper, "and"],
+ [:send, nil,
+ [:chain, [:oper, "="], [:send, nil, [:name, "b"], [:name, "c"]]]]]
end
it 'shuffles correctly with or' do
n('a = b = c or d').should ==
- [:chain, [:act, "=", nil,
- [:name, "a"],
- [:act, "=", nil, [:name, "b"], [:name, "c"]]],
- [:act, "or", nil, [:name, "d"]]]
- end
+ [:chain,
+ [:oper, "="],
+ [:send, nil, [:name, "a"],
+ [:chain, [:oper, "="],
+ [:send, nil, [:name, "b"], [:name, "c"]]]],
+ [:oper, "or"], [:send, nil, [:name, "d"]]]
+ end
end
describe 'unary negation' do
it 'binds to right' do
- n('!b').should ==
- [:act, "!", nil, [:name, "b"]]
+ n('!b').should == [:chain, [:oper, "!"], [:send, nil, [:name, "b"]]]
end
it 'binds chain to right' do
n('!b c d').should ==
- [:act, "!", nil,
- [:chain, [:name, "b"], [:name, "c"], [:name, "d"]]]
+ [:chain, [:oper, "!"], [:send, nil,
+ [:chain, [:name, "b"], [:name, "c"], [:name, "d"]]]]
end
it 'binds chain to right till oper' do
n('!b c + d').should ==
- [:chain,
- [:act, "!", nil, [:chain, [:name, "b"], [:name, "c"]]],
- [:act, "+", nil, [:name, "d"]]]
+ [:chain,
+ [:oper, "!"],
+ [:send, nil, [:chain, [:name, "b"], [:name, "c"]]],
+ [:oper, "+"],
+ [:send, nil, [:chain, [:name, "d"]]]]
end
it 'binds chain to right till end' do
@@ -108,6 +133,7 @@
[:act, "&&", nil, [:name, "d"]]]]]
end
end
+=begin
describe 'logical operator &&' do
it 'associates correctly with logical opers' do
View
@@ -20,6 +20,10 @@ def s(code, rule = :root, *args)
def n(code, rule = :root, *args)
n = c(code, rule, true, *args)
- Akin::Shuffle.new(Akin::Operator::Table.new).shuffle(n).sexp if n
+ shuffler.shuffle(n).sexp if n
+ end
+
+ def shuffler
+ Akin::Shuffle.new(Akin::Operator::Table.new)
end
end

0 comments on commit 513bbef

Please sign in to comment.