hesabu 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -3
- data/README.md +2 -11
- data/bin/hesabucli +0 -0
- data/hesabu.gemspec +0 -2
- data/lib/hesabu/equation_cleaner.rb +11 -0
- data/lib/hesabu/errors.rb +8 -10
- data/lib/hesabu/solver.rb +26 -104
- data/lib/hesabu/version.rb +1 -1
- data/lib/hesabu.rb +4 -9
- metadata +4 -24
- data/lib/hesabu/interpreter.rb +0 -25
- data/lib/hesabu/parser.rb +0 -75
- data/lib/hesabu/types/float_lit.rb +0 -9
- data/lib/hesabu/types/fun_call.rb +0 -123
- data/lib/hesabu/types/indentifier_lit.rb +0 -9
- data/lib/hesabu/types/int_lit.rb +0 -9
- data/lib/hesabu/types/operation.rb +0 -42
- data/lib/hesabu/types/string_lit.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 431f06d479e890cf49a1cf8fb1f9a166b66a88aee4b6200be1c540996fecf4fd
|
4
|
+
data.tar.gz: e6d8a83f61a8e986658b6c574c0b51c5365787819f0fb2bff9331b7cdf3ba07b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c22ea9e78df743ee0ea74d8fb3fc22291fe12fdd1cd7235d94e608c72627c665d9982c2e803eede67320cf42e453741682313d8a4aa87f59a449638d37187e8d
|
7
|
+
data.tar.gz: 96761de748fed74701bc6aa799ec99ff309c77da03521111cd0a4960874552d7018bd5998c883cb2a41a6d826d2ec8fa3415b0ad70ff419c41c93f373370ddcd
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
hesabu (0.1.
|
5
|
-
parslet
|
4
|
+
hesabu (0.1.5)
|
6
5
|
|
7
6
|
GEM
|
8
7
|
remote: https://rubygems.org/
|
@@ -34,7 +33,6 @@ GEM
|
|
34
33
|
parallel (1.12.1)
|
35
34
|
parser (2.5.1.0)
|
36
35
|
ast (~> 2.4.0)
|
37
|
-
parslet (1.8.2)
|
38
36
|
path_expander (1.0.2)
|
39
37
|
powerpack (0.1.1)
|
40
38
|
pronto (0.9.5)
|
data/README.md
CHANGED
@@ -25,13 +25,7 @@ The expressions can be more complex (excel like), see the supported functions [h
|
|
25
25
|
|
26
26
|
Currently the solver is case sensitive (except function names)
|
27
27
|
|
28
|
-
Nb: Hesabu is swahili word for
|
29
|
-
|
30
|
-
## Technical background
|
31
|
-
|
32
|
-
* https://tomassetti.me/guide-parsing-algorithms-terminology/
|
33
|
-
* https://github.com/PhilippeSigaud/Pegged/wiki/PEG-Basics
|
34
|
-
* https://github.com/kschiess/parslet
|
28
|
+
Nb: Hesabu is swahili word for arithmetic.
|
35
29
|
|
36
30
|
## Alternatives
|
37
31
|
|
@@ -62,10 +56,7 @@ chmod 0600 ~/.gem/credentials
|
|
62
56
|
|
63
57
|
|
64
58
|
```
|
65
|
-
gem bump
|
66
|
-
gem build hesabu.gemspec
|
67
|
-
gem push hesabu-x.x.x.gem
|
68
|
-
|
59
|
+
gem bump --tag --release
|
69
60
|
```
|
70
61
|
|
71
62
|
|
data/bin/hesabucli
ADDED
Binary file
|
data/hesabu.gemspec
CHANGED
@@ -23,8 +23,6 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
24
|
spec.require_paths = ["lib"]
|
25
25
|
|
26
|
-
spec.add_dependency "parslet"
|
27
|
-
|
28
26
|
spec.add_development_dependency "bundler", "~> 1.16"
|
29
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
30
28
|
spec.add_development_dependency "rspec", "~> 3.0"
|
data/lib/hesabu/errors.rb
CHANGED
@@ -1,17 +1,15 @@
|
|
1
1
|
|
2
2
|
module Hesabu
|
3
3
|
class Error < StandardError
|
4
|
+
attr_accessor :errors
|
5
|
+
def iniatialize(message)
|
6
|
+
super(message)
|
7
|
+
@errors = errors
|
8
|
+
end
|
4
9
|
end
|
5
10
|
class ArgumentError < Error
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
class CalculationError < Error
|
10
|
-
end
|
11
|
-
class DivideByZeroError < Error
|
12
|
-
end
|
13
|
-
class CyclicError < Error
|
14
|
-
end
|
15
|
-
class UnboundVariableError < Error
|
11
|
+
def iniatialize(message)
|
12
|
+
super(message)
|
13
|
+
end
|
16
14
|
end
|
17
15
|
end
|
data/lib/hesabu/solver.rb
CHANGED
@@ -1,127 +1,49 @@
|
|
1
|
-
module Hesabu
|
2
|
-
class Solver
|
3
|
-
include TSort
|
4
1
|
|
5
|
-
Equation = Struct.new(:name, :evaluable, :dependencies, :raw_expression)
|
6
|
-
EMPTY_DEPENDENCIES = [].freeze
|
7
|
-
FakeEvaluable = Struct.new(:eval)
|
8
2
|
|
3
|
+
module Hesabu
|
4
|
+
class Solver
|
9
5
|
def initialize
|
10
|
-
@parser = ::Hesabu::Parser.new
|
11
|
-
@interpreter = ::Hesabu::Interpreter.new
|
12
6
|
@equations = {}
|
13
|
-
@bindings = {}
|
14
7
|
end
|
15
8
|
|
16
9
|
def add(name, raw_expression)
|
17
10
|
if raw_expression.nil? || name.nil?
|
18
11
|
raise Hesabu::ArgumentError, "name or expression can't be nil : '#{name}', '#{raw_expression}'"
|
19
12
|
end
|
20
|
-
|
21
|
-
if ::Hesabu::Types.as_numeric(raw_expression)
|
22
|
-
add_numeric(name, raw_expression)
|
23
|
-
else
|
24
|
-
add_equation(name, raw_expression)
|
25
|
-
end
|
13
|
+
@equations[name] = EquationCleaner.clean(raw_expression.to_s)
|
26
14
|
end
|
27
15
|
|
28
16
|
def solve!
|
29
|
-
|
30
|
-
|
17
|
+
result = nil
|
18
|
+
IO.popen(HESABUCLI, mode = "r+") do |io|
|
19
|
+
io.write @equations.to_json
|
20
|
+
io.close_write # let the process know you've given it all the data
|
21
|
+
result = io.read
|
31
22
|
end
|
32
|
-
solution =
|
33
|
-
|
34
|
-
to_numerics(solution)
|
35
|
-
rescue StandardError => e
|
36
|
-
log_and_raise(e)
|
37
|
-
end
|
23
|
+
solution = JSON.parse(result)
|
24
|
+
exit_status = $CHILD_STATUS.exitstatus
|
38
25
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
raise Hesabu::CyclicError, "There's a cycle between the variables : " + e.message[25..-1]
|
43
|
-
end
|
44
|
-
|
45
|
-
def tsort_each_node(&block)
|
46
|
-
@equations.each_key(&block)
|
47
|
-
end
|
48
|
-
|
49
|
-
def tsort_each_child(node, &block)
|
50
|
-
equation = @equations[node]
|
51
|
-
raise UnboundVariableError, unbound_message(node) unless equation
|
52
|
-
equation.dependencies.each(&block)
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def to_numerics(solution)
|
58
|
-
solution.each_with_object({}) do |kv, hash|
|
59
|
-
hash[kv.first] = Hesabu::Types.as_numeric(kv.last) || kv.last
|
60
|
-
end
|
26
|
+
log_everything(exit_status, result) if ENV["HESABU_DEBUG"] || exit_status != 0
|
27
|
+
handle_error(solution) if exit_status != 0
|
28
|
+
solution
|
61
29
|
end
|
62
30
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
def log_error(e)
|
69
|
-
log "Error during processing: #{$ERROR_INFO}"
|
70
|
-
log "Error : #{e.class} #{e.message}"
|
71
|
-
log "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
|
72
|
-
end
|
73
|
-
|
74
|
-
def evaluate_equation(equation)
|
75
|
-
raise "not evaluable #{equation.evaluable} #{equation}" unless equation.evaluable.respond_to?(:eval, false)
|
76
|
-
begin
|
77
|
-
@bindings[equation.name] = equation.evaluable.eval
|
78
|
-
rescue StandardError => e
|
79
|
-
raise CalculationError, "Failed to evaluate #{equation.name} due to #{e.message} in formula #{equation.raw_expression}"
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def log(message)
|
84
|
-
puts message
|
85
|
-
end
|
86
|
-
|
87
|
-
def add_numeric(name, raw_expression)
|
88
|
-
@equations[name] = Equation.new(
|
89
|
-
name,
|
90
|
-
FakeEvaluable.new(::Hesabu::Types.as_bigdecimal(raw_expression)),
|
91
|
-
EMPTY_DEPENDENCIES,
|
92
|
-
raw_expression
|
93
|
-
)
|
94
|
-
end
|
95
|
-
|
96
|
-
def add_equation(name, raw_expression)
|
97
|
-
expression = raw_expression.gsub(/\r\n?/, "")
|
98
|
-
ast_tree = begin
|
99
|
-
@parser.parse(expression)
|
100
|
-
rescue Parslet::ParseFailed => e
|
101
|
-
log(raw_expression)
|
102
|
-
log_error(e)
|
103
|
-
raise ParseError, "failed to parse #{name} := #{expression} : #{e.message}"
|
104
|
-
end
|
105
|
-
var_identifiers = Set.new
|
106
|
-
interpretation = @interpreter.apply(
|
107
|
-
ast_tree,
|
108
|
-
doc: @bindings,
|
109
|
-
var_identifiers: var_identifiers
|
110
|
-
)
|
111
|
-
if ENV["HESABU_DEBUG"]
|
112
|
-
log expression
|
113
|
-
log JSON.pretty_generate(ast_tree)
|
114
|
-
end
|
115
|
-
@equations[name] = Equation.new(name, interpretation, var_identifiers, raw_expression)
|
116
|
-
end
|
31
|
+
def handle_error(solution)
|
32
|
+
puts
|
33
|
+
error = solution["errors"].first
|
34
|
+
message = "In equation #{error['source']} " + error["message"] + " #{error['source']} := #{error['expression']}"
|
117
35
|
|
118
|
-
|
119
|
-
|
120
|
-
|
36
|
+
err = Hesabu::Error.new(message)
|
37
|
+
err.errors = solution["errors"]
|
38
|
+
raise err
|
121
39
|
end
|
122
40
|
|
123
|
-
def
|
124
|
-
|
41
|
+
def log_everything(exit_status, result)
|
42
|
+
puts ["**************",
|
43
|
+
"exit_status:#{exit_status}",
|
44
|
+
@equations.to_json,
|
45
|
+
"=> ",
|
46
|
+
result].join("\n")
|
125
47
|
end
|
126
48
|
end
|
127
49
|
end
|
data/lib/hesabu/version.rb
CHANGED
data/lib/hesabu.rb
CHANGED
@@ -1,17 +1,12 @@
|
|
1
1
|
require "hesabu/version"
|
2
|
-
|
2
|
+
|
3
3
|
require_relative "./hesabu/errors"
|
4
|
-
require_relative "./hesabu/parser"
|
5
4
|
require_relative "./hesabu/types/numeric"
|
6
|
-
require_relative "./hesabu/types/float_lit"
|
7
|
-
require_relative "./hesabu/types/fun_call"
|
8
|
-
require_relative "./hesabu/types/indentifier_lit"
|
9
|
-
require_relative "./hesabu/types/int_lit"
|
10
|
-
require_relative "./hesabu/types/string_lit"
|
11
|
-
require_relative "./hesabu/types/operation"
|
12
5
|
|
13
|
-
require_relative "./hesabu/
|
6
|
+
require_relative "./hesabu/equation_cleaner"
|
14
7
|
require_relative "./hesabu/solver"
|
15
8
|
|
16
9
|
module Hesabu
|
10
|
+
HESABUCLI = File.expand_path("../bin/hesabucli", File.dirname(__FILE__))
|
11
|
+
puts "************** HESABU cli location : " + HESABUCLI
|
17
12
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hesabu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stéphan Mestach
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: parslet
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: bundler
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -171,20 +157,14 @@ files:
|
|
171
157
|
- Rakefile
|
172
158
|
- bin/console
|
173
159
|
- bin/fast
|
160
|
+
- bin/hesabucli
|
174
161
|
- bin/setup
|
175
162
|
- hesabu.gemspec
|
176
163
|
- lib/hesabu.rb
|
164
|
+
- lib/hesabu/equation_cleaner.rb
|
177
165
|
- lib/hesabu/errors.rb
|
178
|
-
- lib/hesabu/interpreter.rb
|
179
|
-
- lib/hesabu/parser.rb
|
180
166
|
- lib/hesabu/solver.rb
|
181
|
-
- lib/hesabu/types/float_lit.rb
|
182
|
-
- lib/hesabu/types/fun_call.rb
|
183
|
-
- lib/hesabu/types/indentifier_lit.rb
|
184
|
-
- lib/hesabu/types/int_lit.rb
|
185
167
|
- lib/hesabu/types/numeric.rb
|
186
|
-
- lib/hesabu/types/operation.rb
|
187
|
-
- lib/hesabu/types/string_lit.rb
|
188
168
|
- lib/hesabu/version.rb
|
189
169
|
homepage: https://github.com/BLSQ/hesabu
|
190
170
|
licenses:
|
data/lib/hesabu/interpreter.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
module Hesabu
|
2
|
-
class Interpreter < Parslet::Transform
|
3
|
-
rule(plist: sequence(:arr)) { arr }
|
4
|
-
rule(plist: "()") { [] }
|
5
|
-
rule(l: simple(:left),
|
6
|
-
r: simple(:right),
|
7
|
-
o: simple(:op)) do
|
8
|
-
Hesabu::Types::Operation.new(left, op, right)
|
9
|
-
end
|
10
|
-
rule(identifier: simple(:id)) { id.to_s }
|
11
|
-
rule(variable: simple(:variable)) do |d|
|
12
|
-
d[:var_identifiers]&.add(d[:variable])
|
13
|
-
Hesabu::Types::IdentifierLit.new(d[:variable], d[:doc])
|
14
|
-
end
|
15
|
-
rule(fcall: { name: simple(:name), varlist: sequence(:vars) }) do
|
16
|
-
Hesabu::Types::FunCall.new(name, vars)
|
17
|
-
end
|
18
|
-
rule(str: subtree(:str)) do
|
19
|
-
Hesabu::Types::StringLit.new(str.map { |char| char.values.first.str }.join)
|
20
|
-
end
|
21
|
-
|
22
|
-
rule(integer: simple(:integer)) { Hesabu::Types::IntLit.new(integer) }
|
23
|
-
rule(float: simple(:float)) { Hesabu::Types::FloatLit.new(float) }
|
24
|
-
end
|
25
|
-
end
|
data/lib/hesabu/parser.rb
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
module Hesabu
|
2
|
-
class Parser < Parslet::Parser
|
3
|
-
def cts(atom_arg)
|
4
|
-
atom_arg >> space?
|
5
|
-
end
|
6
|
-
|
7
|
-
# simple things
|
8
|
-
rule(:lparen) { str("(") >> space? }
|
9
|
-
rule(:rparen) { str(")") >> space? }
|
10
|
-
rule(:comma) { str(",") >> space? }
|
11
|
-
rule(:space) { match["\s"] | match["\t"] | match["\n"] }
|
12
|
-
rule(:spaces) { space.repeat }
|
13
|
-
rule(:space?) { spaces.maybe }
|
14
|
-
|
15
|
-
rule(:nonquote) { str("'").absnt? >> any }
|
16
|
-
rule(:quote) { str("'") }
|
17
|
-
rule(:string) { quote >> nonquote.as(:char).repeat(1).as(:str) >> quote >> space? }
|
18
|
-
|
19
|
-
rule(:identifier) do
|
20
|
-
cts((match["a-zA-Z"] >> match["a-zA-Z0-9_"].repeat).as(:identifier))
|
21
|
-
end
|
22
|
-
|
23
|
-
rule(:separator) { str(";") }
|
24
|
-
|
25
|
-
rule(:digit) { match["0-9"] }
|
26
|
-
|
27
|
-
rule(:integer) do
|
28
|
-
cts((str("-").maybe >> match["1-9"] >> digit.repeat).as(:integer) | str("0").as(:integer))
|
29
|
-
end
|
30
|
-
|
31
|
-
rule(:float) do
|
32
|
-
cts((str("-").maybe >> digit.repeat(1) >> str(".") >> digit.repeat(1)).as(:float)) |
|
33
|
-
cts((str(".") >> digit.repeat(1)).as(:float))
|
34
|
-
end
|
35
|
-
|
36
|
-
# arithmetic
|
37
|
-
|
38
|
-
rule(:expression) { iexpression | variable | pexpression }
|
39
|
-
rule(:pexpression) { lparen >> expression >> rparen }
|
40
|
-
|
41
|
-
rule(:variable) { identifier.as(:variable) }
|
42
|
-
rule(:sum_op) { match("[+-]") >> space? }
|
43
|
-
rule(:mul_op) { match("[*/]") >> space? }
|
44
|
-
rule(:comparison_op) do
|
45
|
-
(
|
46
|
-
str("<=") | str(">=") | str("==") |
|
47
|
-
str("!=") | str("<") | str("=") |
|
48
|
-
str(">") | str("AND")
|
49
|
-
) >> space?
|
50
|
-
end
|
51
|
-
|
52
|
-
rule(:atom) { string | pexpression | float | integer | fcall.as(:fcall) | variable }
|
53
|
-
|
54
|
-
rule(:iexpression) do
|
55
|
-
infix_expression(atom,
|
56
|
-
[mul_op, 3, :left],
|
57
|
-
[sum_op, 2, :left],
|
58
|
-
[comparison_op, 1, :left])
|
59
|
-
end
|
60
|
-
|
61
|
-
# lists
|
62
|
-
rule(:varlist) { expression >> (comma >> expression).repeat }
|
63
|
-
rule(:pvarlist) { (lparen >> varlist.repeat >> rparen).as(:plist) }
|
64
|
-
|
65
|
-
# functions
|
66
|
-
rule(:fcall) { identifier.as(:name) >> pvarlist.as(:varlist) }
|
67
|
-
|
68
|
-
# root
|
69
|
-
rule(:command) do
|
70
|
-
iexpression | expression | atom
|
71
|
-
end
|
72
|
-
rule(:commands) { commands.repeat }
|
73
|
-
root :command
|
74
|
-
end
|
75
|
-
end
|
@@ -1,123 +0,0 @@
|
|
1
|
-
module Hesabu
|
2
|
-
module Types
|
3
|
-
class Function
|
4
|
-
def divide(num, denum)
|
5
|
-
num / denum
|
6
|
-
end
|
7
|
-
end
|
8
|
-
class IfFunction < Function
|
9
|
-
def call(args)
|
10
|
-
raise "expected args #{name} : #{args}" unless args.size != 2
|
11
|
-
condition_expression = args[0]
|
12
|
-
condition = condition_expression.eval
|
13
|
-
condition ? args[1].eval : args[2].eval
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class SumFunction < Function
|
18
|
-
def call(args)
|
19
|
-
values = args.map(&:eval)
|
20
|
-
values.reduce(0, :+)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class ScoreTableFunction < Function
|
25
|
-
def call(args)
|
26
|
-
values = args.map(&:eval)
|
27
|
-
target = values.shift
|
28
|
-
matching_rules = values.each_slice(3).find do |lower, greater, result|
|
29
|
-
greater.nil? || result.nil? ? true : lower <= target && target < greater
|
30
|
-
end
|
31
|
-
matching_rules.last
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class AvgFunction < Function
|
36
|
-
def call(args)
|
37
|
-
values = args.map(&:eval)
|
38
|
-
values.inject(0.0) { |acc, elem| acc + elem } / values.size
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
class SafeDivFunction < Function
|
43
|
-
def call(args)
|
44
|
-
eval_denom = args[1].eval
|
45
|
-
if eval_denom == 0
|
46
|
-
0
|
47
|
-
else
|
48
|
-
eval_num = args[0].eval
|
49
|
-
eval_denom.zero? ? 0 : (eval_num / eval_denom)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
class MinFunction
|
55
|
-
def call(args)
|
56
|
-
values = args.map(&:eval)
|
57
|
-
values.min
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
class MaxFunction
|
62
|
-
def call(args)
|
63
|
-
values = args.map(&:eval)
|
64
|
-
values.max
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
class RandbetweenFunction
|
69
|
-
def call(args)
|
70
|
-
values = args.map(&:eval)
|
71
|
-
rand(values.first..values.last)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
class AbsFunction
|
76
|
-
def call(args)
|
77
|
-
raise "expected args #{self.class.name} : #{args}" if args.size != 1
|
78
|
-
args.first.eval.abs
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
class AccessFunction
|
83
|
-
def call(args)
|
84
|
-
values = args.map(&:eval)
|
85
|
-
array = values[0..-2]
|
86
|
-
index = values[-1]
|
87
|
-
array[index]
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
class RoundFunction
|
92
|
-
def call(args)
|
93
|
-
raise "expected args #{self.class.name} : #{args}" if args.size > 2 || args.empty?
|
94
|
-
values = args.map(&:eval)
|
95
|
-
decimals = args.size == 2 ? values[1] : 0
|
96
|
-
values.first.round(decimals)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
FUNCTIONS = {
|
101
|
-
"if" => IfFunction.new,
|
102
|
-
"sum" => SumFunction.new,
|
103
|
-
"avg" => AvgFunction.new,
|
104
|
-
"min" => MinFunction.new,
|
105
|
-
"max" => MaxFunction.new,
|
106
|
-
"safe_div" => SafeDivFunction.new,
|
107
|
-
"randbetween" => RandbetweenFunction.new,
|
108
|
-
"score_table" => ScoreTableFunction.new,
|
109
|
-
"abs" => AbsFunction.new,
|
110
|
-
"access" => AccessFunction.new,
|
111
|
-
"round" => RoundFunction.new
|
112
|
-
}.freeze
|
113
|
-
|
114
|
-
FunCall = Struct.new(:name, :args) do
|
115
|
-
def eval
|
116
|
-
function_name = name.strip.downcase
|
117
|
-
function = FUNCTIONS[function_name]
|
118
|
-
raise "unsupported function call : #{function_name} only knows #{FUNCTIONS.keys.join(', ')}" unless function
|
119
|
-
function.call(args)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
data/lib/hesabu/types/int_lit.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
module Hesabu
|
2
|
-
module Types
|
3
|
-
Operation = Struct.new(:left, :operator, :right) do
|
4
|
-
def eval
|
5
|
-
op = operator.str.strip
|
6
|
-
result(op, left.eval, right.eval)
|
7
|
-
end
|
8
|
-
|
9
|
-
private
|
10
|
-
|
11
|
-
def result(op, leftval, rightval)
|
12
|
-
case op
|
13
|
-
when "+"
|
14
|
-
leftval + rightval
|
15
|
-
when "-"
|
16
|
-
leftval - rightval
|
17
|
-
when "*"
|
18
|
-
leftval * rightval
|
19
|
-
when "/"
|
20
|
-
raise DivideByZeroError, "division by 0 : #{leftval}/0" if rightval.zero?
|
21
|
-
leftval / rightval
|
22
|
-
when ">"
|
23
|
-
leftval > rightval
|
24
|
-
when "<"
|
25
|
-
leftval < rightval
|
26
|
-
when ">="
|
27
|
-
leftval >= rightval
|
28
|
-
when "<="
|
29
|
-
leftval <= rightval
|
30
|
-
when "=", "=="
|
31
|
-
leftval == rightval
|
32
|
-
when "!="
|
33
|
-
leftval != rightval
|
34
|
-
when "AND"
|
35
|
-
leftval && rightval
|
36
|
-
else
|
37
|
-
raise "unsupported operand : #{op} : #{left} #{operator} #{right}"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|