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.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +49 -1
  3. data/keisan.gemspec +1 -0
  4. data/lib/keisan.rb +30 -0
  5. data/lib/keisan/ast/assignment.rb +44 -17
  6. data/lib/keisan/ast/block.rb +60 -0
  7. data/lib/keisan/ast/boolean.rb +5 -5
  8. data/lib/keisan/ast/builder.rb +10 -207
  9. data/lib/keisan/ast/cell.rb +60 -0
  10. data/lib/keisan/ast/constant_literal.rb +9 -0
  11. data/lib/keisan/ast/exponent.rb +6 -6
  12. data/lib/keisan/ast/function.rb +12 -8
  13. data/lib/keisan/ast/indexing.rb +25 -15
  14. data/lib/keisan/ast/line_builder.rb +230 -0
  15. data/lib/keisan/ast/list.rb +28 -1
  16. data/lib/keisan/ast/literal.rb +0 -8
  17. data/lib/keisan/ast/logical_and.rb +1 -1
  18. data/lib/keisan/ast/logical_or.rb +1 -1
  19. data/lib/keisan/ast/multi_line.rb +28 -0
  20. data/lib/keisan/ast/node.rb +32 -24
  21. data/lib/keisan/ast/number.rb +31 -31
  22. data/lib/keisan/ast/operator.rb +12 -4
  23. data/lib/keisan/ast/parent.rb +4 -4
  24. data/lib/keisan/ast/plus.rb +10 -10
  25. data/lib/keisan/ast/string.rb +3 -3
  26. data/lib/keisan/ast/times.rb +8 -8
  27. data/lib/keisan/ast/unary_identity.rb +1 -1
  28. data/lib/keisan/ast/unary_inverse.rb +7 -7
  29. data/lib/keisan/ast/unary_minus.rb +5 -5
  30. data/lib/keisan/ast/unary_operator.rb +2 -2
  31. data/lib/keisan/ast/unary_plus.rb +2 -2
  32. data/lib/keisan/ast/variable.rb +26 -10
  33. data/lib/keisan/context.rb +5 -5
  34. data/lib/keisan/evaluator.rb +15 -8
  35. data/lib/keisan/function.rb +24 -6
  36. data/lib/keisan/functions/cbrt.rb +1 -1
  37. data/lib/keisan/functions/cos.rb +1 -1
  38. data/lib/keisan/functions/cosh.rb +1 -1
  39. data/lib/keisan/functions/cot.rb +1 -1
  40. data/lib/keisan/functions/coth.rb +1 -1
  41. data/lib/keisan/functions/csc.rb +1 -1
  42. data/lib/keisan/functions/csch.rb +1 -1
  43. data/lib/keisan/functions/default_registry.rb +53 -74
  44. data/lib/keisan/functions/diff.rb +18 -14
  45. data/lib/keisan/functions/erf.rb +15 -0
  46. data/lib/keisan/functions/exp.rb +1 -1
  47. data/lib/keisan/functions/expression_function.rb +15 -21
  48. data/lib/keisan/functions/filter.rb +13 -15
  49. data/lib/keisan/functions/if.rb +14 -20
  50. data/lib/keisan/functions/let.rb +36 -0
  51. data/lib/keisan/functions/map.rb +11 -13
  52. data/lib/keisan/functions/math_function.rb +2 -2
  53. data/lib/keisan/functions/proc_function.rb +10 -6
  54. data/lib/keisan/functions/rand.rb +2 -1
  55. data/lib/keisan/functions/range.rb +74 -0
  56. data/lib/keisan/functions/reduce.rb +12 -14
  57. data/lib/keisan/functions/registry.rb +7 -7
  58. data/lib/keisan/functions/replace.rb +8 -8
  59. data/lib/keisan/functions/sample.rb +2 -1
  60. data/lib/keisan/functions/sec.rb +1 -1
  61. data/lib/keisan/functions/sech.rb +1 -1
  62. data/lib/keisan/functions/sin.rb +1 -1
  63. data/lib/keisan/functions/sinh.rb +1 -1
  64. data/lib/keisan/functions/sqrt.rb +1 -1
  65. data/lib/keisan/functions/tan.rb +1 -1
  66. data/lib/keisan/functions/tanh.rb +1 -1
  67. data/lib/keisan/functions/while.rb +46 -0
  68. data/lib/keisan/parser.rb +121 -79
  69. data/lib/keisan/parsing/assignment.rb +1 -1
  70. data/lib/keisan/parsing/bitwise_and.rb +1 -1
  71. data/lib/keisan/parsing/bitwise_not.rb +1 -1
  72. data/lib/keisan/parsing/bitwise_not_not.rb +1 -1
  73. data/lib/keisan/parsing/bitwise_or.rb +1 -1
  74. data/lib/keisan/parsing/bitwise_xor.rb +1 -1
  75. data/lib/keisan/parsing/curly_group.rb +6 -0
  76. data/lib/keisan/parsing/divide.rb +1 -1
  77. data/lib/keisan/parsing/exponent.rb +1 -1
  78. data/lib/keisan/parsing/function.rb +1 -1
  79. data/lib/keisan/parsing/group.rb +1 -1
  80. data/lib/keisan/parsing/indexing.rb +1 -1
  81. data/lib/keisan/parsing/line_separator.rb +6 -0
  82. data/lib/keisan/parsing/logical_and.rb +1 -1
  83. data/lib/keisan/parsing/logical_equal.rb +1 -1
  84. data/lib/keisan/parsing/logical_greater_than.rb +1 -1
  85. data/lib/keisan/parsing/logical_greater_than_or_equal_to.rb +1 -1
  86. data/lib/keisan/parsing/logical_less_than.rb +1 -1
  87. data/lib/keisan/parsing/logical_less_than_or_equal_to.rb +1 -1
  88. data/lib/keisan/parsing/logical_not.rb +1 -1
  89. data/lib/keisan/parsing/logical_not_equal.rb +1 -1
  90. data/lib/keisan/parsing/logical_not_not.rb +1 -1
  91. data/lib/keisan/parsing/logical_or.rb +1 -1
  92. data/lib/keisan/parsing/minus.rb +1 -1
  93. data/lib/keisan/parsing/modulo.rb +1 -1
  94. data/lib/keisan/parsing/operator.rb +1 -1
  95. data/lib/keisan/parsing/plus.rb +1 -1
  96. data/lib/keisan/parsing/times.rb +1 -1
  97. data/lib/keisan/parsing/unary_minus.rb +1 -1
  98. data/lib/keisan/parsing/unary_operator.rb +1 -1
  99. data/lib/keisan/parsing/unary_plus.rb +1 -1
  100. data/lib/keisan/repl.rb +1 -1
  101. data/lib/keisan/tokenizer.rb +4 -9
  102. data/lib/keisan/tokens/group.rb +3 -1
  103. data/lib/keisan/tokens/line_separator.rb +11 -0
  104. data/lib/keisan/variables/default_registry.rb +0 -5
  105. data/lib/keisan/variables/registry.rb +7 -7
  106. data/lib/keisan/version.rb +1 -1
  107. 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 Keisan::Exceptions::UndefinedFunctionError.new name
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 Keisan::Exceptions::UndefinedFunctionError
31
+ rescue Exceptions::UndefinedFunctionError
32
32
  false
33
33
  end
34
34
 
35
35
  def register!(name, function, force: false)
36
- raise Keisan::Exceptions::UnmodifiableError.new("Cannot modify frozen functions registry") if frozen?
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 Keisan::Exceptions::UnmodifiableError.new("Cannot overwrite default function")
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] = Keisan::Functions::ProcFunction.new(name, function)
46
- when Keisan::Function
45
+ self[name] = ProcFunction.new(name, function)
46
+ when Function
47
47
  self[name] = function
48
48
  else
49
- raise Keisan::Exceptions::InvalidFunctionError.new
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 < Keisan::Function
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 ||= Keisan::Context.new
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 ||= Keisan::Context.new
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?(Keisan::AST::Function) && ast_function.name == name
32
- raise Keisan::Exceptions::InvalidFunctionError.new("Must receive replace function")
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 Keisan::Exceptions::InvalidFunctionError.new("Require 3 arguments to replace")
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?(Keisan::AST::Variable)
42
- raise Keisan::Exceptions::InvalidFunctionError.new("Replace must replace a variable")
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 Keisan::Exceptions::InvalidFunctionError.new
16
+ raise Exceptions::InvalidFunctionError.new
16
17
  end
17
18
  end
18
19
  end
@@ -8,7 +8,7 @@ module Keisan
8
8
  protected
9
9
 
10
10
  def self.derivative(argument)
11
- Keisan::AST::Function.new([argument], "sin") * Keisan::AST::Exponent.new([Keisan::AST::Function.new([argument], "cos"), -2])
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
- -Keisan::AST::Function.new([argument], "sinh") * Keisan::AST::Exponent.new([Keisan::AST::Function.new([argument], "cosh"), -2])
11
+ -AST::Function.new([argument], "sinh") * AST::Exponent.new([AST::Function.new([argument], "cosh"), -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
- Keisan::AST::Function.new([argument], "cos")
11
+ AST::Function.new([argument], "cos")
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
- Keisan::AST::Function.new([argument], "cosh")
11
+ AST::Function.new([argument], "cosh")
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
- Keisan::AST::Exponent.new([argument, Rational(-1,2)]) / 2
11
+ AST::Exponent.new([argument, Rational(-1,2)]) / 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
- Keisan::AST::Exponent.new([Keisan::AST::Function.new([argument], "cos"), -2])
11
+ 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
- Keisan::AST::Exponent.new([Keisan::AST::Function.new([argument], "cosh"), -2])
11
+ AST::Exponent.new([AST::Function.new([argument], "cosh"), -2])
12
12
  end
13
13
  end
14
14
  end
@@ -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
@@ -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 Keisan::Exceptions::InternalError.new("Invalid arguments")
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 Keisan::Exceptions::InternalError.new("Invalid argument: tokens = #{tokens}") if tokens.nil? || !tokens.is_a?(Array)
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
- parse_components!
20
- remove_unary_identity!
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 ||= Keisan::AST::Builder.new(parser: self).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?(Keisan::Parsing::Operator) || !(component.node_class <= Keisan::AST::UnaryIdentity)
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 @components.empty? || @components[-1].is_a?(Parsing::Operator)
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 << Keisan::Parsing::Dot.new
87
- else
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 Keisan::Exceptions::ParseError.new("A word must follow a dot, received #{token.string}")
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
- # Expect a round group
104
- if token.type == :group && token.group_type == :round
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
- elsif token.type == :dot
108
- @components << Keisan::Parsing::Dot.new
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 Keisan::Exceptions::ParseError.new("Expected arguments to dot operator, received #{token.string}")
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 Keisan::Exceptions::ParseError.new("Token cannot be parsed, #{token.string}")
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 << Keisan::Parsing::UnaryPlus.new
170
+ @components << Parsing::UnaryPlus.new
123
171
  when :-
124
- @components << Keisan::Parsing::UnaryMinus.new
172
+ @components << Parsing::UnaryMinus.new
125
173
  when :"~"
126
- @components << Keisan::Parsing::BitwiseNot.new
174
+ @components << Parsing::BitwiseNot.new
127
175
  when :"~~"
128
- @components << Keisan::Parsing::BitwiseNotNot.new
176
+ @components << Parsing::BitwiseNotNot.new
129
177
  when :"!"
130
- @components << Keisan::Parsing::LogicalNot.new
178
+ @components << Parsing::LogicalNot.new
131
179
  when :"!!"
132
- @components << Keisan::Parsing::LogicalNotNot.new
180
+ @components << Parsing::LogicalNotNot.new
133
181
  else
134
- raise Keisan::Exceptions::ParseError.new("Unhandled unary operator type #{token.operator_type}")
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 Keisan::Tokens::Number
141
- @components << Keisan::Parsing::Number.new(token.value)
142
- when Keisan::Tokens::String
143
- @components << Keisan::Parsing::String.new(token.value)
144
- when Keisan::Tokens::Null
145
- @components << Keisan::Parsing::Null.new
146
- when Keisan::Tokens::Word
147
- @components << Keisan::Parsing::Variable.new(token.string)
148
- when Keisan::Tokens::Boolean
149
- @components << Keisan::Parsing::Boolean.new(token.value)
150
- when Keisan::Tokens::Group
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 << Keisan::Parsing::RoundGroup.new(token.sub_tokens)
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 Keisan::Exceptions::ParseError.new("Unhandled group type #{token.group_type}")
207
+ raise Exceptions::ParseError.new("Unhandled group type #{token.group_type}")
158
208
  end
159
209
  else
160
- raise Keisan::Exceptions::ParseError.new("Unhandled operator type #{token.operator_type}")
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 << Keisan::Parsing::Assignment.new
218
+ @components << Parsing::Assignment.new
169
219
  # Arithmetic
170
220
  when :+
171
- @components << Keisan::Parsing::Plus.new
221
+ @components << Parsing::Plus.new
172
222
  when :-
173
- @components << Keisan::Parsing::Minus.new
223
+ @components << Parsing::Minus.new
174
224
  when :*
175
- @components << Keisan::Parsing::Times.new
225
+ @components << Parsing::Times.new
176
226
  when :/
177
- @components << Keisan::Parsing::Divide.new
227
+ @components << Parsing::Divide.new
178
228
  when :**
179
- @components << Keisan::Parsing::Exponent.new
229
+ @components << Parsing::Exponent.new
180
230
  when :%
181
- @components << Keisan::Parsing::Modulo.new
231
+ @components << Parsing::Modulo.new
182
232
  # Bitwise
183
233
  when :"&"
184
- @components << Keisan::Parsing::BitwiseAnd.new
234
+ @components << Parsing::BitwiseAnd.new
185
235
  when :"|"
186
- @components << Keisan::Parsing::BitwiseOr.new
236
+ @components << Parsing::BitwiseOr.new
187
237
  when :"^"
188
- @components << Keisan::Parsing::BitwiseXor.new
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 << Keisan::Parsing::LogicalEqual.new
241
+ @components << Parsing::LogicalEqual.new
196
242
  when :"!="
197
- @components << Keisan::Parsing::LogicalNotEqual.new
243
+ @components << Parsing::LogicalNotEqual.new
198
244
  when :"&&"
199
- @components << Keisan::Parsing::LogicalAnd.new
245
+ @components << Parsing::LogicalAnd.new
200
246
  when :"||"
201
- @components << Keisan::Parsing::LogicalOr.new
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 << Keisan::Parsing::LogicalGreaterThan.new
249
+ @components << Parsing::LogicalGreaterThan.new
208
250
  when :"<"
209
- @components << Keisan::Parsing::LogicalLessThan.new
251
+ @components << Parsing::LogicalLessThan.new
210
252
  when :">="
211
- @components << Keisan::Parsing::LogicalGreaterThanOrEqualTo.new
253
+ @components << Parsing::LogicalGreaterThanOrEqualTo.new
212
254
  when :"<="
213
- @components << Keisan::Parsing::LogicalLessThanOrEqualTo.new
255
+ @components << Parsing::LogicalLessThanOrEqualTo.new
214
256
  else
215
- raise Keisan::Exceptions::ParseError.new("Unhandled operator type #{token.operator_type}")
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?(Keisan::Tokens::Comma)}.map do |sub_tokens|
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