Class: Dentaku::Evaluator
- Inherits:
-
Object
- Object
- Dentaku::Evaluator
- Defined in:
- lib/dentaku/evaluator.rb
Instance Attribute Summary collapse
-
#rule_set ⇒ Object
readonly
Returns the value of attribute rule_set.
Instance Method Summary collapse
- #apply(lvalue, operator, rvalue) ⇒ Object
- #evaluate(tokens) ⇒ Object
- #evaluate_group(*args) ⇒ Object
- #evaluate_step(token_stream, start, length, evaluator) ⇒ Object
- #evaluate_token_stream(tokens) ⇒ Object
- #expand_range(left, oper1, middle, oper2, right) ⇒ Object
- #extract_arguments_from_function_call(tokens) ⇒ Object
- #find_rule_match(pattern, token_stream) ⇒ Object
- #if(*args) ⇒ Object
-
#initialize(rule_set) ⇒ Evaluator
constructor
A new instance of Evaluator.
- #inspect_tokens(tokens) ⇒ Object
- #match_rule_pattern(tokens) ⇒ Object
- #mul_negate(val1, _, _, val2) ⇒ Object
- #negate(_, token) ⇒ Object
- #not(*args) ⇒ Object
- #percentage(token, _) ⇒ Object
- #pow_negate(base, _, _, exp) ⇒ Object
- #round(*args) ⇒ Object
- #round_int(*args) ⇒ Object
- #user_defined_function(evaluator, tokens) ⇒ Object
Constructor Details
#initialize(rule_set) ⇒ Evaluator
Returns a new instance of Evaluator.
8 9 10 |
# File 'lib/dentaku/evaluator.rb', line 8 def initialize(rule_set) @rule_set = rule_set end |
Instance Attribute Details
#rule_set ⇒ Object (readonly)
Returns the value of attribute rule_set.
6 7 8 |
# File 'lib/dentaku/evaluator.rb', line 6 def rule_set @rule_set end |
Instance Method Details
#apply(lvalue, operator, rvalue) ⇒ Object
98 99 100 101 102 |
# File 'lib/dentaku/evaluator.rb', line 98 def apply(lvalue, operator, rvalue) operation = BinaryOperation.new(lvalue.value, rvalue.value) raise "unknown operation #{ operator.value }" unless operation.respond_to?(operator.value) Token.new(*operation.send(operator.value)) end |
#evaluate(tokens) ⇒ Object
12 13 14 |
# File 'lib/dentaku/evaluator.rb', line 12 def evaluate(tokens) evaluate_token_stream(tokens).value end |
#evaluate_group(*args) ⇒ Object
94 95 96 |
# File 'lib/dentaku/evaluator.rb', line 94 def evaluate_group(*args) evaluate_token_stream(args[1..-2]) end |
#evaluate_step(token_stream, start, length, evaluator) ⇒ Object
69 70 71 72 73 74 75 76 77 78 |
# File 'lib/dentaku/evaluator.rb', line 69 def evaluate_step(token_stream, start, length, evaluator) substream = token_stream.slice!(start, length) if self.respond_to?(evaluator) token_stream.insert start, *self.send(evaluator, *substream) else result = user_defined_function(evaluator, substream) token_stream.insert start, result end end |
#evaluate_token_stream(tokens) ⇒ Object
16 17 18 19 20 21 22 23 24 25 |
# File 'lib/dentaku/evaluator.rb', line 16 def evaluate_token_stream(tokens) while tokens.length > 1 matched, tokens = match_rule_pattern(tokens) raise "no rule matched {{#{ inspect_tokens(tokens) }}}" unless matched end tokens << Token.new(:numeric, 0) if tokens.empty? tokens.first end |
#expand_range(left, oper1, middle, oper2, right) ⇒ Object
120 121 122 |
# File 'lib/dentaku/evaluator.rb', line 120 def (left, oper1, middle, oper2, right) [left, oper1, middle, Token.new(:combinator, :and), middle, oper2, right] end |
#extract_arguments_from_function_call(tokens) ⇒ Object
89 90 91 92 |
# File 'lib/dentaku/evaluator.rb', line 89 def extract_arguments_from_function_call(tokens) _function_name, _open, *args_and_commas, _close = tokens args_and_commas.reject { |token| token.is?(:grouping) } end |
#find_rule_match(pattern, token_stream) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/dentaku/evaluator.rb', line 47 def find_rule_match(pattern, token_stream) position = 0 while position <= token_stream.length matches = [] matched = true pattern.each do |matcher| _matched, match = matcher.match(token_stream, position + matches.length) matched &&= _matched break unless matched matches += match end return position, matches if matched return if pattern.first.caret? position += 1 end nil end |
#if(*args) ⇒ Object
124 125 126 127 128 129 130 131 132 |
# File 'lib/dentaku/evaluator.rb', line 124 def if(*args) _if, _open, condition, _, true_value, _, false_value, _close = args if condition.value true_value else false_value end end |
#inspect_tokens(tokens) ⇒ Object
27 28 29 |
# File 'lib/dentaku/evaluator.rb', line 27 def inspect_tokens(tokens) tokens.map { |t| t.to_s }.join(' ') end |
#match_rule_pattern(tokens) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/dentaku/evaluator.rb', line 31 def match_rule_pattern(tokens) matched = false rule_set.filter(tokens).each do |pattern, evaluator| pos, match = find_rule_match(pattern, tokens) if pos tokens = evaluate_step(tokens, pos, match.length, evaluator) matched = true break end end [matched, tokens] end |
#mul_negate(val1, _, _, val2) ⇒ Object
112 113 114 |
# File 'lib/dentaku/evaluator.rb', line 112 def mul_negate(val1, _, _, val2) Token.new(val1.category, val1.value * val2.value * -1) end |
#negate(_, token) ⇒ Object
104 105 106 |
# File 'lib/dentaku/evaluator.rb', line 104 def negate(_, token) Token.new(token.category, token.value * -1) end |
#not(*args) ⇒ Object
162 163 164 |
# File 'lib/dentaku/evaluator.rb', line 162 def not(*args) Token.new(:logical, ! evaluate_token_stream(args[2..-2]).value) end |
#percentage(token, _) ⇒ Object
116 117 118 |
# File 'lib/dentaku/evaluator.rb', line 116 def percentage(token, _) Token.new(token.category, token.value / 100.0) end |
#pow_negate(base, _, _, exp) ⇒ Object
108 109 110 |
# File 'lib/dentaku/evaluator.rb', line 108 def pow_negate(base, _, _, exp) Token.new(base.category, base.value ** (exp.value * -1)) end |
#round(*args) ⇒ Object
134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/dentaku/evaluator.rb', line 134 def round(*args) _, _, *tokens, _ = args input_tokens, places_tokens = tokens.chunk { |t| t.category == :grouping }. reject { |flag, tokens| flag }. map { |flag, tokens| tokens } input_value = evaluate_token_stream(input_tokens).value places = places_tokens ? evaluate_token_stream(places_tokens).value : 0 value = input_value.round(places) Token.new(:numeric, value) end |
#round_int(*args) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/dentaku/evaluator.rb', line 149 def round_int(*args) function, _, *tokens, _ = args value = evaluate_token_stream(tokens).value rounded = if function.value == :roundup value.ceil else value.floor end Token.new(:numeric, rounded) end |
#user_defined_function(evaluator, tokens) ⇒ Object
80 81 82 83 84 85 86 87 |
# File 'lib/dentaku/evaluator.rb', line 80 def user_defined_function(evaluator, tokens) function = rule_set.function(evaluator) raise "unknown function '#{ evaluator }'" unless function arguments = extract_arguments_from_function_call(tokens).map { |t| t.value } return_value = function.body.call(*arguments) Token.new(function.type, return_value) end |