keisan 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +49 -1
- data/keisan.gemspec +1 -0
- data/lib/keisan.rb +30 -0
- data/lib/keisan/ast/assignment.rb +44 -17
- data/lib/keisan/ast/block.rb +60 -0
- data/lib/keisan/ast/boolean.rb +5 -5
- data/lib/keisan/ast/builder.rb +10 -207
- data/lib/keisan/ast/cell.rb +60 -0
- data/lib/keisan/ast/constant_literal.rb +9 -0
- data/lib/keisan/ast/exponent.rb +6 -6
- data/lib/keisan/ast/function.rb +12 -8
- data/lib/keisan/ast/indexing.rb +25 -15
- data/lib/keisan/ast/line_builder.rb +230 -0
- data/lib/keisan/ast/list.rb +28 -1
- data/lib/keisan/ast/literal.rb +0 -8
- data/lib/keisan/ast/logical_and.rb +1 -1
- data/lib/keisan/ast/logical_or.rb +1 -1
- data/lib/keisan/ast/multi_line.rb +28 -0
- data/lib/keisan/ast/node.rb +32 -24
- data/lib/keisan/ast/number.rb +31 -31
- data/lib/keisan/ast/operator.rb +12 -4
- data/lib/keisan/ast/parent.rb +4 -4
- data/lib/keisan/ast/plus.rb +10 -10
- data/lib/keisan/ast/string.rb +3 -3
- data/lib/keisan/ast/times.rb +8 -8
- data/lib/keisan/ast/unary_identity.rb +1 -1
- data/lib/keisan/ast/unary_inverse.rb +7 -7
- data/lib/keisan/ast/unary_minus.rb +5 -5
- data/lib/keisan/ast/unary_operator.rb +2 -2
- data/lib/keisan/ast/unary_plus.rb +2 -2
- data/lib/keisan/ast/variable.rb +26 -10
- data/lib/keisan/context.rb +5 -5
- data/lib/keisan/evaluator.rb +15 -8
- data/lib/keisan/function.rb +24 -6
- data/lib/keisan/functions/cbrt.rb +1 -1
- data/lib/keisan/functions/cos.rb +1 -1
- data/lib/keisan/functions/cosh.rb +1 -1
- data/lib/keisan/functions/cot.rb +1 -1
- data/lib/keisan/functions/coth.rb +1 -1
- data/lib/keisan/functions/csc.rb +1 -1
- data/lib/keisan/functions/csch.rb +1 -1
- data/lib/keisan/functions/default_registry.rb +53 -74
- data/lib/keisan/functions/diff.rb +18 -14
- data/lib/keisan/functions/erf.rb +15 -0
- data/lib/keisan/functions/exp.rb +1 -1
- data/lib/keisan/functions/expression_function.rb +15 -21
- data/lib/keisan/functions/filter.rb +13 -15
- data/lib/keisan/functions/if.rb +14 -20
- data/lib/keisan/functions/let.rb +36 -0
- data/lib/keisan/functions/map.rb +11 -13
- data/lib/keisan/functions/math_function.rb +2 -2
- data/lib/keisan/functions/proc_function.rb +10 -6
- data/lib/keisan/functions/rand.rb +2 -1
- data/lib/keisan/functions/range.rb +74 -0
- data/lib/keisan/functions/reduce.rb +12 -14
- data/lib/keisan/functions/registry.rb +7 -7
- data/lib/keisan/functions/replace.rb +8 -8
- data/lib/keisan/functions/sample.rb +2 -1
- data/lib/keisan/functions/sec.rb +1 -1
- data/lib/keisan/functions/sech.rb +1 -1
- data/lib/keisan/functions/sin.rb +1 -1
- data/lib/keisan/functions/sinh.rb +1 -1
- data/lib/keisan/functions/sqrt.rb +1 -1
- data/lib/keisan/functions/tan.rb +1 -1
- data/lib/keisan/functions/tanh.rb +1 -1
- data/lib/keisan/functions/while.rb +46 -0
- data/lib/keisan/parser.rb +121 -79
- data/lib/keisan/parsing/assignment.rb +1 -1
- data/lib/keisan/parsing/bitwise_and.rb +1 -1
- data/lib/keisan/parsing/bitwise_not.rb +1 -1
- data/lib/keisan/parsing/bitwise_not_not.rb +1 -1
- data/lib/keisan/parsing/bitwise_or.rb +1 -1
- data/lib/keisan/parsing/bitwise_xor.rb +1 -1
- data/lib/keisan/parsing/curly_group.rb +6 -0
- data/lib/keisan/parsing/divide.rb +1 -1
- data/lib/keisan/parsing/exponent.rb +1 -1
- data/lib/keisan/parsing/function.rb +1 -1
- data/lib/keisan/parsing/group.rb +1 -1
- data/lib/keisan/parsing/indexing.rb +1 -1
- data/lib/keisan/parsing/line_separator.rb +6 -0
- data/lib/keisan/parsing/logical_and.rb +1 -1
- data/lib/keisan/parsing/logical_equal.rb +1 -1
- data/lib/keisan/parsing/logical_greater_than.rb +1 -1
- data/lib/keisan/parsing/logical_greater_than_or_equal_to.rb +1 -1
- data/lib/keisan/parsing/logical_less_than.rb +1 -1
- data/lib/keisan/parsing/logical_less_than_or_equal_to.rb +1 -1
- data/lib/keisan/parsing/logical_not.rb +1 -1
- data/lib/keisan/parsing/logical_not_equal.rb +1 -1
- data/lib/keisan/parsing/logical_not_not.rb +1 -1
- data/lib/keisan/parsing/logical_or.rb +1 -1
- data/lib/keisan/parsing/minus.rb +1 -1
- data/lib/keisan/parsing/modulo.rb +1 -1
- data/lib/keisan/parsing/operator.rb +1 -1
- data/lib/keisan/parsing/plus.rb +1 -1
- data/lib/keisan/parsing/times.rb +1 -1
- data/lib/keisan/parsing/unary_minus.rb +1 -1
- data/lib/keisan/parsing/unary_operator.rb +1 -1
- data/lib/keisan/parsing/unary_plus.rb +1 -1
- data/lib/keisan/repl.rb +1 -1
- data/lib/keisan/tokenizer.rb +4 -9
- data/lib/keisan/tokens/group.rb +3 -1
- data/lib/keisan/tokens/line_separator.rb +11 -0
- data/lib/keisan/variables/default_registry.rb +0 -5
- data/lib/keisan/variables/registry.rb +7 -7
- data/lib/keisan/version.rb +1 -1
- metadata +27 -2
@@ -19,7 +19,7 @@ module Keisan
|
|
19
19
|
end
|
20
20
|
|
21
21
|
return default_registry[name] if @use_defaults && default_registry.has_name?(name)
|
22
|
-
raise
|
22
|
+
raise Exceptions::UndefinedFunctionError.new name
|
23
23
|
end
|
24
24
|
|
25
25
|
def locals
|
@@ -28,25 +28,25 @@ module Keisan
|
|
28
28
|
|
29
29
|
def has?(name)
|
30
30
|
!!self[name]
|
31
|
-
rescue
|
31
|
+
rescue Exceptions::UndefinedFunctionError
|
32
32
|
false
|
33
33
|
end
|
34
34
|
|
35
35
|
def register!(name, function, force: false)
|
36
|
-
raise
|
36
|
+
raise Exceptions::UnmodifiableError.new("Cannot modify frozen functions registry") if frozen?
|
37
37
|
name = name.to_s
|
38
38
|
|
39
39
|
if !force && @use_defaults && default_registry.has_name?(name)
|
40
|
-
raise
|
40
|
+
raise Exceptions::UnmodifiableError.new("Cannot overwrite default function")
|
41
41
|
end
|
42
42
|
|
43
43
|
case function
|
44
44
|
when Proc
|
45
|
-
self[name] =
|
46
|
-
when
|
45
|
+
self[name] = ProcFunction.new(name, function)
|
46
|
+
when Function
|
47
47
|
self[name] = function
|
48
48
|
else
|
49
|
-
raise
|
49
|
+
raise Exceptions::InvalidFunctionError.new
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -1,17 +1,17 @@
|
|
1
1
|
module Keisan
|
2
2
|
module Functions
|
3
|
-
class Replace <
|
3
|
+
class Replace < Function
|
4
4
|
def initialize
|
5
5
|
@name = "replace"
|
6
6
|
end
|
7
7
|
|
8
8
|
def value(ast_function, context = nil)
|
9
|
-
context ||=
|
9
|
+
context ||= Context.new
|
10
10
|
evaluate(ast_function, context).value(context)
|
11
11
|
end
|
12
12
|
|
13
13
|
def evaluate(ast_function, context = nil)
|
14
|
-
context ||=
|
14
|
+
context ||= Context.new
|
15
15
|
expression, variable, replacement = expression_variable_replacement(ast_function)
|
16
16
|
|
17
17
|
expression = expression.evaluate(context)
|
@@ -28,18 +28,18 @@ module Keisan
|
|
28
28
|
private
|
29
29
|
|
30
30
|
def expression_variable_replacement(ast_function)
|
31
|
-
unless ast_function.is_a?(
|
32
|
-
raise
|
31
|
+
unless ast_function.is_a?(AST::Function) && ast_function.name == name
|
32
|
+
raise Exceptions::InvalidFunctionError.new("Must receive replace function")
|
33
33
|
end
|
34
34
|
|
35
35
|
unless ast_function.children.size == 3
|
36
|
-
raise
|
36
|
+
raise Exceptions::InvalidFunctionError.new("Require 3 arguments to replace")
|
37
37
|
end
|
38
38
|
|
39
39
|
expression, variable, replacement = *ast_function.children.map(&:deep_dup)
|
40
40
|
|
41
|
-
unless variable.is_a?(
|
42
|
-
raise
|
41
|
+
unless variable.is_a?(AST::Variable)
|
42
|
+
raise Exceptions::InvalidFunctionError.new("Replace must replace a variable")
|
43
43
|
end
|
44
44
|
|
45
45
|
[expression, variable, replacement]
|
@@ -3,6 +3,7 @@ module Keisan
|
|
3
3
|
class Sample < ProcFunction
|
4
4
|
def initialize
|
5
5
|
@name = "sample"
|
6
|
+
@arity = 1
|
6
7
|
end
|
7
8
|
|
8
9
|
# Single argument: integer in range [0, max)
|
@@ -12,7 +13,7 @@ module Keisan
|
|
12
13
|
when 1
|
13
14
|
args.first.sample(random: context.random)
|
14
15
|
else
|
15
|
-
raise
|
16
|
+
raise Exceptions::InvalidFunctionError.new
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
data/lib/keisan/functions/sec.rb
CHANGED
@@ -8,7 +8,7 @@ module Keisan
|
|
8
8
|
protected
|
9
9
|
|
10
10
|
def self.derivative(argument)
|
11
|
-
|
11
|
+
AST::Function.new([argument], "sin") * AST::Exponent.new([AST::Function.new([argument], "cos"), -2])
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -8,7 +8,7 @@ module Keisan
|
|
8
8
|
protected
|
9
9
|
|
10
10
|
def self.derivative(argument)
|
11
|
-
-
|
11
|
+
-AST::Function.new([argument], "sinh") * AST::Exponent.new([AST::Function.new([argument], "cosh"), -2])
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
data/lib/keisan/functions/sin.rb
CHANGED
data/lib/keisan/functions/tan.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
module Keisan
|
2
|
+
module Functions
|
3
|
+
class While < Keisan::Function
|
4
|
+
def initialize
|
5
|
+
super("while", 2)
|
6
|
+
end
|
7
|
+
|
8
|
+
def value(ast_function, context = nil)
|
9
|
+
validate_arguments!(ast_function.children.count)
|
10
|
+
evaluate(ast_function, context)
|
11
|
+
end
|
12
|
+
|
13
|
+
def evaluate(ast_function, context = nil)
|
14
|
+
validate_arguments!(ast_function.children.count)
|
15
|
+
context ||= Keisan::Context.new
|
16
|
+
simplify(ast_function, context)
|
17
|
+
end
|
18
|
+
|
19
|
+
def simplify(ast_function, context = nil)
|
20
|
+
validate_arguments!(ast_function.children.count)
|
21
|
+
context ||= Context.new
|
22
|
+
while_loop(ast_function.children[0], ast_function.children[1], context)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def while_loop(logical_node, body_node, context)
|
28
|
+
current = Keisan::AST::Null.new
|
29
|
+
|
30
|
+
while logical_node_evaluates_to_true(logical_node, context)
|
31
|
+
current = body_node.evaluated(context)
|
32
|
+
end
|
33
|
+
|
34
|
+
current
|
35
|
+
end
|
36
|
+
|
37
|
+
def logical_node_evaluates_to_true(logical_node, context)
|
38
|
+
bool = logical_node.evaluated(context)
|
39
|
+
unless bool.is_a?(AST::Boolean)
|
40
|
+
raise Keisan::Exceptions::InvalidFunctionError.new("while condition must evaluate to a boolean")
|
41
|
+
end
|
42
|
+
bool.value(context)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/keisan/parser.rb
CHANGED
@@ -1,31 +1,68 @@
|
|
1
1
|
module Keisan
|
2
2
|
class Parser
|
3
|
+
KEYWORDS = %w(let).freeze
|
4
|
+
|
3
5
|
attr_reader :tokens, :components
|
4
6
|
|
5
7
|
def initialize(string: nil, tokens: nil)
|
6
8
|
if string.nil? && tokens.nil?
|
7
|
-
raise
|
9
|
+
raise Exceptions::InternalError.new("Invalid arguments")
|
8
10
|
end
|
9
11
|
|
10
12
|
if !string.nil?
|
11
13
|
@tokens = Tokenizer.new(string).tokens
|
12
14
|
else
|
13
|
-
raise
|
15
|
+
raise Exceptions::InternalError.new("Invalid argument: tokens = #{tokens}") if tokens.nil? || !tokens.is_a?(Array)
|
14
16
|
@tokens = tokens
|
15
17
|
end
|
16
18
|
|
17
19
|
@components = []
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
+
if multi_line?
|
22
|
+
parse_multi_line!
|
23
|
+
elsif @tokens.first&.is_a?(Tokens::Word) && KEYWORDS.include?(@tokens.first.string)
|
24
|
+
parse_keyword!
|
25
|
+
else
|
26
|
+
parse_components!
|
27
|
+
remove_unary_identity!
|
28
|
+
end
|
21
29
|
end
|
22
30
|
|
23
31
|
def ast
|
24
|
-
@ast ||=
|
32
|
+
@ast ||= AST::Builder.new(parser: self).ast
|
25
33
|
end
|
26
34
|
|
27
35
|
private
|
28
36
|
|
37
|
+
def multi_line?
|
38
|
+
@tokens.any? {|token| token.is_a?(Tokens::LineSeparator)}
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse_multi_line!
|
42
|
+
line_parsers = @tokens.split {|token| token.is_a?(Tokens::LineSeparator)}.map {|tokens| self.class.new(tokens: tokens)}
|
43
|
+
@components = []
|
44
|
+
line_parsers.each.with_index do |line_parser, i|
|
45
|
+
@components += line_parser.components
|
46
|
+
if i < line_parsers.count - 1
|
47
|
+
@components << Parsing::LineSeparator.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def parse_keyword!
|
53
|
+
keyword = tokens.first.string
|
54
|
+
arguments = if tokens[1].is_a?(Tokens::Group)
|
55
|
+
tokens[1].sub_tokens.split {|token| token.is_a?(Tokens::Comma)}.map {|argument_tokens|
|
56
|
+
Parsing::Argument.new(argument_tokens)
|
57
|
+
}
|
58
|
+
else
|
59
|
+
Parsing::Argument.new(tokens[1..-1])
|
60
|
+
end
|
61
|
+
@components = [
|
62
|
+
Parsing::Function.new(keyword, arguments)
|
63
|
+
]
|
64
|
+
end
|
65
|
+
|
29
66
|
def parse_components!
|
30
67
|
@unparsed_tokens = tokens.dup
|
31
68
|
|
@@ -39,10 +76,14 @@ module Keisan
|
|
39
76
|
|
40
77
|
def remove_unary_identity!
|
41
78
|
@components = @components.select do |component|
|
42
|
-
!component.is_a?(
|
79
|
+
!component.is_a?(Parsing::Operator) || !(component.node_class <= AST::UnaryIdentity)
|
43
80
|
end
|
44
81
|
end
|
45
82
|
|
83
|
+
def is_start_of_line?
|
84
|
+
@components.empty? || @components.last.is_a?(Parsing::LineSeparator)
|
85
|
+
end
|
86
|
+
|
46
87
|
# Elements are groups of tokens separated by (non-unary) operators
|
47
88
|
# The following are basic elements:
|
48
89
|
# number
|
@@ -54,7 +95,9 @@ module Keisan
|
|
54
95
|
# and any number of indexing groups (square groups) at the back
|
55
96
|
#
|
56
97
|
def add_token_to_components!(token)
|
57
|
-
if
|
98
|
+
if token.is_a?(Tokens::LineSeparator)
|
99
|
+
@components << Parsing::LineSeparator.new
|
100
|
+
elsif is_start_of_line? || @components[-1].is_a?(Parsing::Operator)
|
58
101
|
# Expect an element or a unary operator
|
59
102
|
if token.type == :operator
|
60
103
|
# Here it must be a unary operator
|
@@ -64,17 +107,6 @@ module Keisan
|
|
64
107
|
add_element_to_components!(token)
|
65
108
|
end
|
66
109
|
|
67
|
-
elsif @components[-1].is_a?(Parsing::UnaryOperator)
|
68
|
-
# Expect an element or another unary operator
|
69
|
-
case token.type
|
70
|
-
when :operator
|
71
|
-
add_unary_operator_to_components!(token)
|
72
|
-
when :number, :string, :word, :group, :null, :boolean
|
73
|
-
add_element_to_components!(token)
|
74
|
-
else
|
75
|
-
raise Keisan::Exceptions::ParseError.new("Expected an element, received #{token.string}")
|
76
|
-
end
|
77
|
-
|
78
110
|
elsif @components[-1].is_a?(Parsing::Element)
|
79
111
|
# A word followed by a "round group" is actually a function: e.g. sin(x)
|
80
112
|
if @components[-1].is_a?(Parsing::Variable) && token.type == :group && token.group_type == :round
|
@@ -83,11 +115,11 @@ module Keisan
|
|
83
115
|
elsif token.type == :group && token.group_type == :square
|
84
116
|
add_indexing_to_components!(token)
|
85
117
|
elsif token.type == :dot
|
86
|
-
@components <<
|
87
|
-
|
88
|
-
# Expect an operator
|
89
|
-
raise Keisan::Exceptions::ParseError.new("Expected an operator, received #{token.string}") unless token.type == :operator
|
118
|
+
@components << Parsing::Dot.new
|
119
|
+
elsif token.type == :operator
|
90
120
|
add_operator_to_components!(token)
|
121
|
+
else
|
122
|
+
raise Exceptions::ParseError.new("Expected an operator, received #{token.string}")
|
91
123
|
end
|
92
124
|
|
93
125
|
elsif @components[-1].is_a?(Parsing::Dot)
|
@@ -96,68 +128,86 @@ module Keisan
|
|
96
128
|
when :word
|
97
129
|
@components[-1] = Parsing::DotWord.new(token.string)
|
98
130
|
else
|
99
|
-
raise
|
131
|
+
raise Exceptions::ParseError.new("A word must follow a dot, received #{token.string}")
|
100
132
|
end
|
101
133
|
|
102
134
|
elsif @components[-1].is_a?(Parsing::DotWord)
|
103
|
-
|
104
|
-
|
135
|
+
add_token_after_dot_word!(token)
|
136
|
+
|
137
|
+
else
|
138
|
+
raise Exceptions::ParseError.new("Token cannot be parsed, #{token.string}")
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def add_token_after_dot_word!(token)
|
143
|
+
case token.type
|
144
|
+
when :group
|
145
|
+
case token.group_type
|
146
|
+
when :round
|
147
|
+
# Here it is a method call
|
105
148
|
name = @components[-1].name
|
106
149
|
@components[-1] = Parsing::DotOperator.new(name, arguments_from_group(token))
|
107
|
-
|
108
|
-
|
109
|
-
elsif token.type == :group && token.group_type == :square
|
150
|
+
when :square
|
151
|
+
# Here we are indexing after method call
|
110
152
|
add_indexing_to_components!(token)
|
111
153
|
else
|
112
|
-
raise
|
154
|
+
raise Exceptions::ParseError.new("Cannot take curly braces after function call")
|
113
155
|
end
|
156
|
+
when :dot
|
157
|
+
# Chaining method calls
|
158
|
+
@components << Parsing::Dot.new
|
159
|
+
when :operator
|
160
|
+
# End of method call, move on to operator
|
161
|
+
add_operator_to_components!(token)
|
114
162
|
else
|
115
|
-
raise
|
163
|
+
raise Exceptions::ParseError.new("Expected arguments to dot operator, received #{token.string}")
|
116
164
|
end
|
117
165
|
end
|
118
166
|
|
119
167
|
def add_unary_operator_to_components!(token)
|
120
168
|
case token.operator_type
|
121
169
|
when :+
|
122
|
-
@components <<
|
170
|
+
@components << Parsing::UnaryPlus.new
|
123
171
|
when :-
|
124
|
-
@components <<
|
172
|
+
@components << Parsing::UnaryMinus.new
|
125
173
|
when :"~"
|
126
|
-
@components <<
|
174
|
+
@components << Parsing::BitwiseNot.new
|
127
175
|
when :"~~"
|
128
|
-
@components <<
|
176
|
+
@components << Parsing::BitwiseNotNot.new
|
129
177
|
when :"!"
|
130
|
-
@components <<
|
178
|
+
@components << Parsing::LogicalNot.new
|
131
179
|
when :"!!"
|
132
|
-
@components <<
|
180
|
+
@components << Parsing::LogicalNotNot.new
|
133
181
|
else
|
134
|
-
raise
|
182
|
+
raise Exceptions::ParseError.new("Unhandled unary operator type #{token.operator_type}")
|
135
183
|
end
|
136
184
|
end
|
137
185
|
|
138
186
|
def add_element_to_components!(token)
|
139
187
|
case token
|
140
|
-
when
|
141
|
-
@components <<
|
142
|
-
when
|
143
|
-
@components <<
|
144
|
-
when
|
145
|
-
@components <<
|
146
|
-
when
|
147
|
-
@components <<
|
148
|
-
when
|
149
|
-
@components <<
|
150
|
-
when
|
188
|
+
when Tokens::Number
|
189
|
+
@components << Parsing::Number.new(token.value)
|
190
|
+
when Tokens::String
|
191
|
+
@components << Parsing::String.new(token.value)
|
192
|
+
when Tokens::Null
|
193
|
+
@components << Parsing::Null.new
|
194
|
+
when Tokens::Word
|
195
|
+
@components << Parsing::Variable.new(token.string)
|
196
|
+
when Tokens::Boolean
|
197
|
+
@components << Parsing::Boolean.new(token.value)
|
198
|
+
when Tokens::Group
|
151
199
|
case token.group_type
|
152
200
|
when :round
|
153
|
-
@components <<
|
201
|
+
@components << Parsing::RoundGroup.new(token.sub_tokens)
|
154
202
|
when :square
|
155
203
|
@components << Parsing::List.new(arguments_from_group(token))
|
204
|
+
when :curly
|
205
|
+
@components << Parsing::CurlyGroup.new(token.sub_tokens)
|
156
206
|
else
|
157
|
-
raise
|
207
|
+
raise Exceptions::ParseError.new("Unhandled group type #{token.group_type}")
|
158
208
|
end
|
159
209
|
else
|
160
|
-
raise
|
210
|
+
raise Exceptions::ParseError.new("Unhandled operator type #{token.operator_type}")
|
161
211
|
end
|
162
212
|
end
|
163
213
|
|
@@ -165,54 +215,46 @@ module Keisan
|
|
165
215
|
case token.operator_type
|
166
216
|
# Assignment
|
167
217
|
when :"="
|
168
|
-
@components <<
|
218
|
+
@components << Parsing::Assignment.new
|
169
219
|
# Arithmetic
|
170
220
|
when :+
|
171
|
-
@components <<
|
221
|
+
@components << Parsing::Plus.new
|
172
222
|
when :-
|
173
|
-
@components <<
|
223
|
+
@components << Parsing::Minus.new
|
174
224
|
when :*
|
175
|
-
@components <<
|
225
|
+
@components << Parsing::Times.new
|
176
226
|
when :/
|
177
|
-
@components <<
|
227
|
+
@components << Parsing::Divide.new
|
178
228
|
when :**
|
179
|
-
@components <<
|
229
|
+
@components << Parsing::Exponent.new
|
180
230
|
when :%
|
181
|
-
@components <<
|
231
|
+
@components << Parsing::Modulo.new
|
182
232
|
# Bitwise
|
183
233
|
when :"&"
|
184
|
-
@components <<
|
234
|
+
@components << Parsing::BitwiseAnd.new
|
185
235
|
when :"|"
|
186
|
-
@components <<
|
236
|
+
@components << Parsing::BitwiseOr.new
|
187
237
|
when :"^"
|
188
|
-
@components <<
|
189
|
-
when :"~"
|
190
|
-
@components << Keisan::Parsing::BitwiseNot.new
|
191
|
-
when :"~~"
|
192
|
-
@components << Keisan::Parsing::BitwiseNotNot.new
|
238
|
+
@components << Parsing::BitwiseXor.new
|
193
239
|
# Logical
|
194
240
|
when :"=="
|
195
|
-
@components <<
|
241
|
+
@components << Parsing::LogicalEqual.new
|
196
242
|
when :"!="
|
197
|
-
@components <<
|
243
|
+
@components << Parsing::LogicalNotEqual.new
|
198
244
|
when :"&&"
|
199
|
-
@components <<
|
245
|
+
@components << Parsing::LogicalAnd.new
|
200
246
|
when :"||"
|
201
|
-
@components <<
|
202
|
-
when :"!"
|
203
|
-
@components << Keisan::Parsing::LogicalNot.new
|
204
|
-
when :"!!"
|
205
|
-
@components << Keisan::Parsing::LogicalNotNot.new
|
247
|
+
@components << Parsing::LogicalOr.new
|
206
248
|
when :">"
|
207
|
-
@components <<
|
249
|
+
@components << Parsing::LogicalGreaterThan.new
|
208
250
|
when :"<"
|
209
|
-
@components <<
|
251
|
+
@components << Parsing::LogicalLessThan.new
|
210
252
|
when :">="
|
211
|
-
@components <<
|
253
|
+
@components << Parsing::LogicalGreaterThanOrEqualTo.new
|
212
254
|
when :"<="
|
213
|
-
@components <<
|
255
|
+
@components << Parsing::LogicalLessThanOrEqualTo.new
|
214
256
|
else
|
215
|
-
raise
|
257
|
+
raise Exceptions::ParseError.new("Unhandled operator type #{token.operator_type}")
|
216
258
|
end
|
217
259
|
end
|
218
260
|
|
@@ -229,7 +271,7 @@ module Keisan
|
|
229
271
|
if token.sub_tokens.empty?
|
230
272
|
[]
|
231
273
|
else
|
232
|
-
token.sub_tokens.split {|sub_token| sub_token.is_a?(
|
274
|
+
token.sub_tokens.split {|sub_token| sub_token.is_a?(Tokens::Comma)}.map do |sub_tokens|
|
233
275
|
Parsing::Argument.new(sub_tokens)
|
234
276
|
end
|
235
277
|
end
|