Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Separated operator table from suffle implementation.

  • Loading branch information...
commit 3377700beb87a48489f96fb6cd4074a6e8c679c7 1 parent 1e4f904
Victor Hugo Borja authored
1  lib/akin.rb
@@ -2,6 +2,7 @@
2 2
3 3 parser
4 4 grammar
  5 + operator
5 6 shuffle
6 7
7 8 }.each { |f| require File.expand_path("../akin/#{f}", __FILE__) }
195 lib/akin/operator.rb
... ... @@ -0,0 +1,195 @@
  1 +# -*- coding: utf-8 -*-
  2 +module Akin
  3 + class Operator < Struct.new(:name,
  4 + :precedence, :assoc,
  5 + :arity_l, :arity_r,
  6 + :node, :idx,
  7 + :inverted)
  8 +
  9 + def <=>(o)
  10 + prec = precedence <=> o.precedence
  11 + if prec.zero? && idx && assoc > 0
  12 + o.idx <=> idx
  13 + else
  14 + prec
  15 + end
  16 + end
  17 +
  18 + def at(node, idx)
  19 + self.class.new name, precedence, assoc, arity_l, arity_r, node, idx, inverted
  20 + end
  21 +
  22 + def self.build(ary)
  23 + ops = Hash.new
  24 + ary.each_slice(2) do |n, p|
  25 + ops[n] = Operator.new n, p.to_i, *DEFAULT[1..-1]
  26 + end
  27 + ops
  28 + end
  29 +
  30 + class Table
  31 + def initialize(operators = OPERATORS, prefix = PREFIX, default = DEFAULT)
  32 + @operators, @prefix, @default = operators, prefix, default
  33 + end
  34 +
  35 + def operator?(node)
  36 + !operator(node,0).nil?
  37 + end
  38 +
  39 + def operator(node, idx)
  40 + if [:oper, :name].include?(node.name) && @operators.key?(node.args.first)
  41 + @operators[node.args.first].at(node, idx)
  42 + elsif :oper == node.name && @prefix.key?(node.args.first[0,1])
  43 + op = @prefix[node.args.first[0,1]].at(node, idx)
  44 + op.name = node.args.first
  45 + op
  46 + elsif :oper == node.name
  47 + Operator.new(node.args.first, *@default).at(node, idx)
  48 + end
  49 + end
  50 + end
  51 +
  52 + # OPER PRECED ASOC ARY_L ARY_R
  53 + DEFAULT = [10, 0, 0.0, 0.1]
  54 + OPERATORS = Operator.build %w'
  55 + ! 0
  56 + ? 0
  57 + $ 0
  58 + ~ 0
  59 + # 0
  60 + -- 0
  61 + ++ 0
  62 + ** 1
  63 + * 2
  64 + / 2
  65 + % 2
  66 + + 3
  67 + - 3
  68 + ∩ 3
  69 + ∪ 3
  70 + << 4
  71 + >> 4
  72 + < 5
  73 + > 5
  74 + < 5
  75 + <= 5
  76 + ≤ 5
  77 + >= 5
  78 + ≥ 5
  79 + <> 5
  80 + <>> 5
  81 + <<>> 5
  82 + ⊂ 5
  83 + ⊃ 5
  84 + ⊆ 5
  85 + ⊇ 5
  86 + == 6
  87 + != 6
  88 + ≠ 6
  89 + === 6
  90 + =~ 6
  91 + !~ 6
  92 + & 7
  93 + ^ 8
  94 + | 9
  95 + && 10
  96 + ?& 10
  97 + || 11
  98 + ?| 11
  99 + .. 12
  100 + ... 12
  101 + ∈ 12
  102 + ∉ 12
  103 + ::: 12
  104 + => 12
  105 + <-> 12
  106 + -> 12
  107 + ∘ 12
  108 + +> 12
  109 + !> 12
  110 + &> 12
  111 + %> 12
  112 + #> 12
  113 + @> 12
  114 + /> 12
  115 + *> 12
  116 + ?> 12
  117 + |> 12
  118 + ^> 12
  119 + ~> 12
  120 + ->> 12
  121 + +>> 12
  122 + !>> 12
  123 + &>> 12
  124 + %>> 12
  125 + #>> 12
  126 + @>> 12
  127 + />> 12
  128 + *>> 12
  129 + ?>> 12
  130 + |>> 12
  131 + ^>> 12
  132 + ~>> 12
  133 + =>> 12
  134 + **> 12
  135 + **>> 12
  136 + &&> 12
  137 + &&>> 12
  138 + ||> 12
  139 + ||>> 12
  140 + $> 12
  141 + $>> 12
  142 + += 13
  143 + -= 13
  144 + **= 13
  145 + *= 13
  146 + /= 13
  147 + %= 13
  148 + and 13
  149 + nand 13
  150 + &= 13
  151 + &&= 13
  152 + ^= 13
  153 + or 13
  154 + xor 13
  155 + nor 13
  156 + |= 13
  157 + ||= 13
  158 + <<= 13
  159 + >>= 13
  160 + <- 14
  161 + return 14
  162 + ret 14
  163 + use 14
  164 + '
  165 + PREFIX = Operator.build %w'
  166 + / 2
  167 + * 2
  168 + % 2
  169 + + 3
  170 + - 3
  171 + $ 6
  172 + ~ 6
  173 + ? 6
  174 + ! 6
  175 + = 6
  176 + > 6
  177 + < 6
  178 + & 7
  179 + ^ 8
  180 + | 9
  181 + '
  182 +
  183 + %w[ * / % = ].each { |i| PREFIX[i].assoc = 1 }
  184 + %w[ * / % ** ].each { |i| OPERATORS[i].assoc = 1 }
  185 +
  186 + %w[ ++ -- ].each { |i| o = OPERATORS[i]; o.arity_l, o.arity_r = 1, 0 }
  187 +
  188 + %w[ = ].each { |i| o = PREFIX[i]; o.arity_l, o.arity_r = 0.1, 0.1 }
  189 + %w[ ? ].each { |i| o = OPERATORS[i]; o.arity_l, o.arity_r = 1, -1 }
  190 + %w[ $ ].each { |i| o = OPERATORS[i]; o.arity_l, o.arity_r = 0, -1 }
  191 +
  192 + %w[ ∈ ∉ ::: ].each { |i| o = OPERATORS[i]; o.inverted = o.assoc = 1 }
  193 +
  194 + end
  195 +end
190 lib/akin/shuffle.rb
@@ -2,197 +2,15 @@
2 2 module Akin
3 3
4 4 class Shuffle
5   -
6   - class Operator < Struct.new(:name,
7   - :precedence, :assoc,
8   - :arity_l, :arity_r,
9   - :node, :idx,
10   - :inverted)
11   -
12   - def <=>(o)
13   - prec = precedence <=> o.precedence
14   - if prec.zero? && idx && assoc > 0
15   - o.idx <=> idx
16   - else
17   - prec
18   - end
19   - end
20   -
21   - def at(node, idx)
22   - self.class.new name, precedence, assoc, arity_l, arity_r, node, idx, inverted
23   - end
24   -
25   - def self.build(ary)
26   - ops = Hash.new
27   - ary.each_slice(2) do |n, p|
28   - ops[n] = Operator.new n, p.to_i, *DEFAULT[1..-1]
29   - end
30   - ops
31   - end
32   - end
33 5
34   - # OPER PRECED ASOC ARY_L ARY_R
35   - DEFAULT = [10, 0, 0.0, 0.1]
36   - OPERATORS = Operator.build %w'
37   - ! 0
38   - ? 0
39   - $ 0
40   - ~ 0
41   - # 0
42   - -- 0
43   - ++ 0
44   - ** 1
45   - * 2
46   - / 2
47   - % 2
48   - + 3
49   - - 3
50   - ∩ 3
51   - ∪ 3
52   - << 4
53   - >> 4
54   - < 5
55   - > 5
56   - < 5
57   - <= 5
58   - ≤ 5
59   - >= 5
60   - ≥ 5
61   - <> 5
62   - <>> 5
63   - <<>> 5
64   - ⊂ 5
65   - ⊃ 5
66   - ⊆ 5
67   - ⊇ 5
68   - == 6
69   - != 6
70   - ≠ 6
71   - === 6
72   - =~ 6
73   - !~ 6
74   - & 7
75   - ^ 8
76   - | 9
77   - && 10
78   - ?& 10
79   - || 11
80   - ?| 11
81   - .. 12
82   - ... 12
83   - ∈ 12
84   - ∉ 12
85   - ::: 12
86   - => 12
87   - <-> 12
88   - -> 12
89   - ∘ 12
90   - +> 12
91   - !> 12
92   - &> 12
93   - %> 12
94   - #> 12
95   - @> 12
96   - /> 12
97   - *> 12
98   - ?> 12
99   - |> 12
100   - ^> 12
101   - ~> 12
102   - ->> 12
103   - +>> 12
104   - !>> 12
105   - &>> 12
106   - %>> 12
107   - #>> 12
108   - @>> 12
109   - />> 12
110   - *>> 12
111   - ?>> 12
112   - |>> 12
113   - ^>> 12
114   - ~>> 12
115   - =>> 12
116   - **> 12
117   - **>> 12
118   - &&> 12
119   - &&>> 12
120   - ||> 12
121   - ||>> 12
122   - $> 12
123   - $>> 12
124   - += 13
125   - -= 13
126   - **= 13
127   - *= 13
128   - /= 13
129   - %= 13
130   - and 13
131   - nand 13
132   - &= 13
133   - &&= 13
134   - ^= 13
135   - or 13
136   - xor 13
137   - nor 13
138   - |= 13
139   - ||= 13
140   - <<= 13
141   - >>= 13
142   - <- 14
143   - return 14
144   - ret 14
145   - use 14
146   - '
147   - PREFIX = Operator.build %w'
148   - / 2
149   - * 2
150   - % 2
151   - + 3
152   - - 3
153   - $ 6
154   - ~ 6
155   - ? 6
156   - ! 6
157   - = 6
158   - > 6
159   - < 6
160   - & 7
161   - ^ 8
162   - | 9
163   - '
164   -
165   - %w[ * / % = ].each { |i| PREFIX[i].assoc = 1 }
166   - %w[ * / % ** ].each { |i| OPERATORS[i].assoc = 1 }
167   -
168   - %w[ ++ -- ].each { |i| o = OPERATORS[i]; o.arity_l, o.arity_r = 1, 0 }
169   -
170   - %w[ = ].each { |i| o = PREFIX[i]; o.arity_l, o.arity_r = 0.1, 0.1 }
171   - %w[ ? ].each { |i| o = OPERATORS[i]; o.arity_l, o.arity_r = 1, -1 }
172   - %w[ $ ].each { |i| o = OPERATORS[i]; o.arity_l, o.arity_r = 0, -1 }
173   -
174   - %w[ ∈ ∉ ::: ].each { |i| o = OPERATORS[i]; o.inverted = o.assoc = 1 }
175   -
176   - def initialize(operators = OPERATORS)
  6 + def initialize(operators)
177 7 @operators = operators
178 8 end
179 9
180   - def at(node, idx)
181   - if [:oper, :name].include?(node.name) && @operators.key?(node.args.first)
182   - @operators[node.args.first].at(node, idx)
183   - elsif :oper == node.name && PREFIX.key?(node.args.first[0,1])
184   - op = PREFIX[node.args.first[0,1]].at(node, idx)
185   - op.name = node.args.first
186   - op
187   - elsif :oper == node.name
188   - Operator.new(node.args.first, *DEFAULT).at(node, idx)
189   - end
190   - end
191   -
192 10 def operators(ary)
193 11 ops = []
194 12 ary.each_with_index do |node, idx|
195   - op = at(node, idx)
  13 + op = @operators.operator(node, idx)
196 14 ops << op if op
197 15 end
198 16 ops.sort
@@ -259,7 +77,7 @@ def shuffle_op(op, chain)
259 77 lhs = left.pop(op.arity_l)
260 78 else
261 79 left.reverse!
262   - lhs = left.take_while { |n| at(n,0).nil? }.reverse
  80 + lhs = left.take_while { |n| !@operators.operator?(n) }.reverse
263 81 left = left[lhs.size..-1].reverse
264 82 end
265 83 end
@@ -270,7 +88,7 @@ def shuffle_op(op, chain)
270 88 elsif op.arity_r >= 1
271 89 rhs = right.shift(op.arity_r)
272 90 else
273   - rhs = right.take_while { |n| at(n,0).nil? }
  91 + rhs = right.take_while { |n| !@operators.operator?(n) }
274 92 right = right[rhs.size..-1]
275 93 end
276 94 end
44 spec/operator_spec.rb
... ... @@ -0,0 +1,44 @@
  1 +# -*- coding: utf-8 -*-
  2 +require File.expand_path('../spec_helper', __FILE__)
  3 +
  4 +describe Akin::Shuffle do
  5 + include_context 'grammar'
  6 +
  7 + subject { Akin::Shuffle.new(Akin::Operator::Table.new) }
  8 +
  9 + describe '#operators returns an ary' do
  10 + it 'non empty if found operators in chain' do
  11 + subject.operators(c('+ * -').args).should_not be_empty
  12 + end
  13 +
  14 + it 'including only operators' do
  15 + subject.operators(c('+ b * c -').args).size.should == 3
  16 + end
  17 +
  18 + it 'with operators sorted by precedence' do
  19 + subject.operators(c('+ *').args).map(&:name).should == ["*", "+"]
  20 + end
  21 +
  22 + it 'with +,- operators sorted by fixity' do
  23 + subject.operators(c('+ - +').args).map(&:name).should == ["+", "-", "+"]
  24 + end
  25 +
  26 + it 'with +,-,* operators sorted by fixity' do
  27 + subject.operators(c('+ - * +').args).map(&:name).should == ["*", "+", "-", "+"]
  28 + end
  29 +
  30 + it 'with +,-,*,/ operators sorted by fixity' do
  31 + subject.operators(c('+ - * + /').args).map(&:name).should ==
  32 + ["/", "*", "+", "-", "+"]
  33 + end
  34 +
  35 + it 'detects and as an operator' do
  36 + subject.operators(c('you and me').args).size.should == 1
  37 + end
  38 +
  39 + it 'detects ∈ as an operator' do
  40 + subject.operators(c('a ∈ b').args).size.should == 1
  41 + end
  42 + end
  43 +end
  44 +
39 spec/shuffle_spec.rb
... ... @@ -1,44 +1,9 @@
1 1 # -*- coding: utf-8 -*-
2 2 require File.expand_path('../spec_helper', __FILE__)
3 3
4   -describe Akin::Shuffle do
  4 +describe 'Akin operator shuffle' do
5 5 include_context 'grammar'
6   -
7   - describe '#operators returns an ary' do
8   - it 'non empty if found operators in chain' do
9   - subject.operators(c('+ * -').args).should_not be_empty
10   - end
11   -
12   - it 'including only operators' do
13   - subject.operators(c('+ b * c -').args).size.should == 3
14   - end
15   -
16   - it 'with operators sorted by precedence' do
17   - subject.operators(c('+ *').args).map(&:name).should == ["*", "+"]
18   - end
19   -
20   - it 'with +,- operators sorted by fixity' do
21   - subject.operators(c('+ - +').args).map(&:name).should == ["+", "-", "+"]
22   - end
23   -
24   - it 'with +,-,* operators sorted by fixity' do
25   - subject.operators(c('+ - * +').args).map(&:name).should == ["*", "+", "-", "+"]
26   - end
27   -
28   - it 'with +,-,*,/ operators sorted by fixity' do
29   - subject.operators(c('+ - * + /').args).map(&:name).should ==
30   - ["/", "*", "+", "-", "+"]
31   - end
32   -
33   - it 'detects and as an operator' do
34   - subject.operators(c('you and me').args).size.should == 1
35   - end
36   -
37   - it 'detects ∈ as an operator' do
38   - subject.operators(c('a ∈ b').args).size.should == 1
39   - end
40   - end
41   -
  6 +
42 7 describe 'basic math opers' do
43 8 it 'associates correctly + and *' do
44 9 n('a + b * c - d').should ==
2  spec/spec_helper.rb
@@ -22,6 +22,6 @@ def s(code, rule = :root, *args)
22 22
23 23 def n(code, rule = :root, *args)
24 24 n = c(code, rule, true, *args)
25   - Akin::Shuffle.new.shuffle(n).sexp if n
  25 + Akin::Shuffle.new(Akin::Operator::Table.new).shuffle(n).sexp if n
26 26 end
27 27 end

0 comments on commit 3377700

Please sign in to comment.
Something went wrong with that request. Please try again.