Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Separated operator table from suffle implementation.

  • Loading branch information...
commit 3377700beb87a48489f96fb6cd4074a6e8c679c7 1 parent 1e4f904
@vic authored
View
1  lib/akin.rb
@@ -2,6 +2,7 @@
parser
grammar
+ operator
shuffle
}.each { |f| require File.expand_path("../akin/#{f}", __FILE__) }
View
195 lib/akin/operator.rb
@@ -0,0 +1,195 @@
+# -*- coding: utf-8 -*-
+module Akin
+ class Operator < Struct.new(:name,
+ :precedence, :assoc,
+ :arity_l, :arity_r,
+ :node, :idx,
+ :inverted)
+
+ def <=>(o)
+ prec = precedence <=> o.precedence
+ if prec.zero? && idx && assoc > 0
+ o.idx <=> idx
+ else
+ prec
+ end
+ end
+
+ def at(node, idx)
+ self.class.new name, precedence, assoc, arity_l, arity_r, node, idx, inverted
+ end
+
+ def self.build(ary)
+ ops = Hash.new
+ ary.each_slice(2) do |n, p|
+ ops[n] = Operator.new n, p.to_i, *DEFAULT[1..-1]
+ end
+ ops
+ end
+
+ class Table
+ def initialize(operators = OPERATORS, prefix = PREFIX, default = DEFAULT)
+ @operators, @prefix, @default = operators, prefix, default
+ end
+
+ def operator?(node)
+ !operator(node,0).nil?
+ end
+
+ def operator(node, idx)
+ if [:oper, :name].include?(node.name) && @operators.key?(node.args.first)
+ @operators[node.args.first].at(node, idx)
+ elsif :oper == node.name && @prefix.key?(node.args.first[0,1])
+ op = @prefix[node.args.first[0,1]].at(node, idx)
+ op.name = node.args.first
+ op
+ elsif :oper == node.name
+ Operator.new(node.args.first, *@default).at(node, idx)
+ end
+ end
+ end
+
+ # OPER PRECED ASOC ARY_L ARY_R
+ DEFAULT = [10, 0, 0.0, 0.1]
+ OPERATORS = Operator.build %w'
+ ! 0
+ ? 0
+ $ 0
+ ~ 0
+ # 0
+ -- 0
+ ++ 0
+ ** 1
+ * 2
+ / 2
+ % 2
+ + 3
+ - 3
+ ∩ 3
+ ∪ 3
+ << 4
+ >> 4
+ < 5
+ > 5
+ < 5
+ <= 5
+ ≤ 5
+ >= 5
+ ≥ 5
+ <> 5
+ <>> 5
+ <<>> 5
+ ⊂ 5
+ ⊃ 5
+ ⊆ 5
+ ⊇ 5
+ == 6
+ != 6
+ ≠ 6
+ === 6
+ =~ 6
+ !~ 6
+ & 7
+ ^ 8
+ | 9
+ && 10
+ ?& 10
+ || 11
+ ?| 11
+ .. 12
+ ... 12
+ ∈ 12
+ ∉ 12
+ ::: 12
+ => 12
+ <-> 12
+ -> 12
+ ∘ 12
+ +> 12
+ !> 12
+ &> 12
+ %> 12
+ #> 12
+ @> 12
+ /> 12
+ *> 12
+ ?> 12
+ |> 12
+ ^> 12
+ ~> 12
+ ->> 12
+ +>> 12
+ !>> 12
+ &>> 12
+ %>> 12
+ #>> 12
+ @>> 12
+ />> 12
+ *>> 12
+ ?>> 12
+ |>> 12
+ ^>> 12
+ ~>> 12
+ =>> 12
+ **> 12
+ **>> 12
+ &&> 12
+ &&>> 12
+ ||> 12
+ ||>> 12
+ $> 12
+ $>> 12
+ += 13
+ -= 13
+ **= 13
+ *= 13
+ /= 13
+ %= 13
+ and 13
+ nand 13
+ &= 13
+ &&= 13
+ ^= 13
+ or 13
+ xor 13
+ nor 13
+ |= 13
+ ||= 13
+ <<= 13
+ >>= 13
+ <- 14
+ return 14
+ ret 14
+ use 14
+ '
+ PREFIX = Operator.build %w'
+ / 2
+ * 2
+ % 2
+ + 3
+ - 3
+ $ 6
+ ~ 6
+ ? 6
+ ! 6
+ = 6
+ > 6
+ < 6
+ & 7
+ ^ 8
+ | 9
+ '
+
+ %w[ * / % = ].each { |i| PREFIX[i].assoc = 1 }
+ %w[ * / % ** ].each { |i| OPERATORS[i].assoc = 1 }
+
+ %w[ ++ -- ].each { |i| o = OPERATORS[i]; o.arity_l, o.arity_r = 1, 0 }
+
+ %w[ = ].each { |i| o = PREFIX[i]; o.arity_l, o.arity_r = 0.1, 0.1 }
+ %w[ ? ].each { |i| o = OPERATORS[i]; o.arity_l, o.arity_r = 1, -1 }
+ %w[ $ ].each { |i| o = OPERATORS[i]; o.arity_l, o.arity_r = 0, -1 }
+
+ %w[ ∈ ∉ ::: ].each { |i| o = OPERATORS[i]; o.inverted = o.assoc = 1 }
+
+ end
+end
View
190 lib/akin/shuffle.rb
@@ -2,197 +2,15 @@
module Akin
class Shuffle
-
- class Operator < Struct.new(:name,
- :precedence, :assoc,
- :arity_l, :arity_r,
- :node, :idx,
- :inverted)
-
- def <=>(o)
- prec = precedence <=> o.precedence
- if prec.zero? && idx && assoc > 0
- o.idx <=> idx
- else
- prec
- end
- end
-
- def at(node, idx)
- self.class.new name, precedence, assoc, arity_l, arity_r, node, idx, inverted
- end
-
- def self.build(ary)
- ops = Hash.new
- ary.each_slice(2) do |n, p|
- ops[n] = Operator.new n, p.to_i, *DEFAULT[1..-1]
- end
- ops
- end
- end
- # OPER PRECED ASOC ARY_L ARY_R
- DEFAULT = [10, 0, 0.0, 0.1]
- OPERATORS = Operator.build %w'
- ! 0
- ? 0
- $ 0
- ~ 0
- # 0
- -- 0
- ++ 0
- ** 1
- * 2
- / 2
- % 2
- + 3
- - 3
- ∩ 3
- ∪ 3
- << 4
- >> 4
- < 5
- > 5
- < 5
- <= 5
- ≤ 5
- >= 5
- ≥ 5
- <> 5
- <>> 5
- <<>> 5
- ⊂ 5
- ⊃ 5
- ⊆ 5
- ⊇ 5
- == 6
- != 6
- ≠ 6
- === 6
- =~ 6
- !~ 6
- & 7
- ^ 8
- | 9
- && 10
- ?& 10
- || 11
- ?| 11
- .. 12
- ... 12
- ∈ 12
- ∉ 12
- ::: 12
- => 12
- <-> 12
- -> 12
- ∘ 12
- +> 12
- !> 12
- &> 12
- %> 12
- #> 12
- @> 12
- /> 12
- *> 12
- ?> 12
- |> 12
- ^> 12
- ~> 12
- ->> 12
- +>> 12
- !>> 12
- &>> 12
- %>> 12
- #>> 12
- @>> 12
- />> 12
- *>> 12
- ?>> 12
- |>> 12
- ^>> 12
- ~>> 12
- =>> 12
- **> 12
- **>> 12
- &&> 12
- &&>> 12
- ||> 12
- ||>> 12
- $> 12
- $>> 12
- += 13
- -= 13
- **= 13
- *= 13
- /= 13
- %= 13
- and 13
- nand 13
- &= 13
- &&= 13
- ^= 13
- or 13
- xor 13
- nor 13
- |= 13
- ||= 13
- <<= 13
- >>= 13
- <- 14
- return 14
- ret 14
- use 14
- '
- PREFIX = Operator.build %w'
- / 2
- * 2
- % 2
- + 3
- - 3
- $ 6
- ~ 6
- ? 6
- ! 6
- = 6
- > 6
- < 6
- & 7
- ^ 8
- | 9
- '
-
- %w[ * / % = ].each { |i| PREFIX[i].assoc = 1 }
- %w[ * / % ** ].each { |i| OPERATORS[i].assoc = 1 }
-
- %w[ ++ -- ].each { |i| o = OPERATORS[i]; o.arity_l, o.arity_r = 1, 0 }
-
- %w[ = ].each { |i| o = PREFIX[i]; o.arity_l, o.arity_r = 0.1, 0.1 }
- %w[ ? ].each { |i| o = OPERATORS[i]; o.arity_l, o.arity_r = 1, -1 }
- %w[ $ ].each { |i| o = OPERATORS[i]; o.arity_l, o.arity_r = 0, -1 }
-
- %w[ ∈ ∉ ::: ].each { |i| o = OPERATORS[i]; o.inverted = o.assoc = 1 }
-
- def initialize(operators = OPERATORS)
+ def initialize(operators)
@operators = operators
end
- def at(node, idx)
- if [:oper, :name].include?(node.name) && @operators.key?(node.args.first)
- @operators[node.args.first].at(node, idx)
- elsif :oper == node.name && PREFIX.key?(node.args.first[0,1])
- op = PREFIX[node.args.first[0,1]].at(node, idx)
- op.name = node.args.first
- op
- elsif :oper == node.name
- Operator.new(node.args.first, *DEFAULT).at(node, idx)
- end
- end
-
def operators(ary)
ops = []
ary.each_with_index do |node, idx|
- op = at(node, idx)
+ op = @operators.operator(node, idx)
ops << op if op
end
ops.sort
@@ -259,7 +77,7 @@ def shuffle_op(op, chain)
lhs = left.pop(op.arity_l)
else
left.reverse!
- lhs = left.take_while { |n| at(n,0).nil? }.reverse
+ lhs = left.take_while { |n| !@operators.operator?(n) }.reverse
left = left[lhs.size..-1].reverse
end
end
@@ -270,7 +88,7 @@ def shuffle_op(op, chain)
elsif op.arity_r >= 1
rhs = right.shift(op.arity_r)
else
- rhs = right.take_while { |n| at(n,0).nil? }
+ rhs = right.take_while { |n| !@operators.operator?(n) }
right = right[rhs.size..-1]
end
end
View
44 spec/operator_spec.rb
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+require File.expand_path('../spec_helper', __FILE__)
+
+describe Akin::Shuffle do
+ include_context 'grammar'
+
+ subject { Akin::Shuffle.new(Akin::Operator::Table.new) }
+
+ describe '#operators returns an ary' do
+ it 'non empty if found operators in chain' do
+ subject.operators(c('+ * -').args).should_not be_empty
+ end
+
+ it 'including only operators' do
+ subject.operators(c('+ b * c -').args).size.should == 3
+ end
+
+ it 'with operators sorted by precedence' do
+ subject.operators(c('+ *').args).map(&:name).should == ["*", "+"]
+ end
+
+ it 'with +,- operators sorted by fixity' do
+ subject.operators(c('+ - +').args).map(&:name).should == ["+", "-", "+"]
+ end
+
+ it 'with +,-,* operators sorted by fixity' do
+ subject.operators(c('+ - * +').args).map(&:name).should == ["*", "+", "-", "+"]
+ end
+
+ it 'with +,-,*,/ operators sorted by fixity' do
+ subject.operators(c('+ - * + /').args).map(&:name).should ==
+ ["/", "*", "+", "-", "+"]
+ end
+
+ it 'detects and as an operator' do
+ subject.operators(c('you and me').args).size.should == 1
+ end
+
+ it 'detects ∈ as an operator' do
+ subject.operators(c('a ∈ b').args).size.should == 1
+ end
+ end
+end
+
View
39 spec/shuffle_spec.rb
@@ -1,44 +1,9 @@
# -*- coding: utf-8 -*-
require File.expand_path('../spec_helper', __FILE__)
-describe Akin::Shuffle do
+describe 'Akin operator shuffle' do
include_context 'grammar'
-
- describe '#operators returns an ary' do
- it 'non empty if found operators in chain' do
- subject.operators(c('+ * -').args).should_not be_empty
- end
-
- it 'including only operators' do
- subject.operators(c('+ b * c -').args).size.should == 3
- end
-
- it 'with operators sorted by precedence' do
- subject.operators(c('+ *').args).map(&:name).should == ["*", "+"]
- end
-
- it 'with +,- operators sorted by fixity' do
- subject.operators(c('+ - +').args).map(&:name).should == ["+", "-", "+"]
- end
-
- it 'with +,-,* operators sorted by fixity' do
- subject.operators(c('+ - * +').args).map(&:name).should == ["*", "+", "-", "+"]
- end
-
- it 'with +,-,*,/ operators sorted by fixity' do
- subject.operators(c('+ - * + /').args).map(&:name).should ==
- ["/", "*", "+", "-", "+"]
- end
-
- it 'detects and as an operator' do
- subject.operators(c('you and me').args).size.should == 1
- end
-
- it 'detects ∈ as an operator' do
- subject.operators(c('a ∈ b').args).size.should == 1
- end
- end
-
+
describe 'basic math opers' do
it 'associates correctly + and *' do
n('a + b * c - d').should ==
View
2  spec/spec_helper.rb
@@ -22,6 +22,6 @@ def s(code, rule = :root, *args)
def n(code, rule = :root, *args)
n = c(code, rule, true, *args)
- Akin::Shuffle.new.shuffle(n).sexp if n
+ Akin::Shuffle.new(Akin::Operator::Table.new).shuffle(n).sexp if n
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.