keisan 0.6.0 → 0.7.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 +90 -132
- data/bin/keisan +13 -2
- data/lib/keisan.rb +5 -0
- data/lib/keisan/ast.rb +11 -0
- data/lib/keisan/ast/assignment.rb +20 -55
- data/lib/keisan/ast/boolean.rb +16 -12
- data/lib/keisan/ast/cell.rb +17 -0
- data/lib/keisan/ast/cell_assignment.rb +70 -0
- data/lib/keisan/ast/function_assignment.rb +52 -0
- data/lib/keisan/ast/hash.rb +82 -0
- data/lib/keisan/ast/indexing.rb +26 -15
- data/lib/keisan/ast/line_builder.rb +22 -4
- data/lib/keisan/ast/list.rb +14 -7
- data/lib/keisan/ast/node.rb +13 -0
- data/lib/keisan/ast/null.rb +14 -0
- data/lib/keisan/ast/parent.rb +8 -3
- data/lib/keisan/ast/string.rb +10 -0
- data/lib/keisan/ast/variable.rb +4 -0
- data/lib/keisan/ast/variable_assignment.rb +62 -0
- data/lib/keisan/context.rb +16 -2
- data/lib/keisan/functions/default_registry.rb +4 -0
- data/lib/keisan/functions/enumerable_function.rb +56 -0
- data/lib/keisan/functions/filter.rb +34 -32
- data/lib/keisan/functions/map.rb +25 -31
- data/lib/keisan/functions/puts.rb +23 -0
- data/lib/keisan/functions/reduce.rb +29 -29
- data/lib/keisan/functions/registry.rb +4 -4
- data/lib/keisan/functions/sample.rb +5 -3
- data/lib/keisan/functions/to_h.rb +34 -0
- data/lib/keisan/interpreter.rb +42 -0
- data/lib/keisan/parser.rb +59 -50
- data/lib/keisan/parsing/compound_assignment.rb +15 -0
- data/lib/keisan/parsing/hash.rb +36 -0
- data/lib/keisan/repl.rb +1 -1
- data/lib/keisan/token.rb +1 -0
- data/lib/keisan/tokenizer.rb +23 -19
- data/lib/keisan/tokens/assignment.rb +21 -1
- data/lib/keisan/tokens/colon.rb +11 -0
- data/lib/keisan/tokens/unknown.rb +11 -0
- data/lib/keisan/variables/registry.rb +11 -6
- data/lib/keisan/version.rb +1 -1
- metadata +14 -2
@@ -0,0 +1,36 @@
|
|
1
|
+
module Keisan
|
2
|
+
module Parsing
|
3
|
+
class Hash < Element
|
4
|
+
attr_reader :key_value_pairs
|
5
|
+
|
6
|
+
def initialize(key_value_pairs)
|
7
|
+
@key_value_pairs = Array.wrap(key_value_pairs).map {|key_value_pair|
|
8
|
+
validate_and_extract_key_value_pair(key_value_pair)
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def validate_and_extract_key_value_pair(key_value_pair)
|
15
|
+
key, value = key_value_pair.split {|token| token.is_a?(Tokens::Colon)}
|
16
|
+
raise Exceptions::ParseError.new("Invalid hash") unless key.size == 1 && value.size >= 1
|
17
|
+
|
18
|
+
key = key.first
|
19
|
+
if allowed_key?(key)
|
20
|
+
[Parsing::String.new(key.value), Parsing::RoundGroup.new(value)]
|
21
|
+
else
|
22
|
+
raise Exceptions::ParseError.new("Invalid hash (keys must be constants)")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def allowed_key?(key)
|
27
|
+
case key
|
28
|
+
when Tokens::String, Tokens::Boolean, Tokens::Null, Tokens::Number
|
29
|
+
true
|
30
|
+
else
|
31
|
+
false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/keisan/repl.rb
CHANGED
data/lib/keisan/token.rb
CHANGED
data/lib/keisan/tokenizer.rb
CHANGED
@@ -7,13 +7,15 @@ module Keisan
|
|
7
7
|
Tokens::Boolean,
|
8
8
|
Tokens::Word,
|
9
9
|
Tokens::Number,
|
10
|
-
Tokens::
|
10
|
+
Tokens::Assignment,
|
11
11
|
Tokens::LogicalOperator,
|
12
|
+
Tokens::ArithmeticOperator,
|
12
13
|
Tokens::BitwiseOperator,
|
13
|
-
Tokens::Assignment,
|
14
14
|
Tokens::Comma,
|
15
|
+
Tokens::Colon,
|
15
16
|
Tokens::Dot,
|
16
|
-
Tokens::LineSeparator
|
17
|
+
Tokens::LineSeparator,
|
18
|
+
Tokens::Unknown
|
17
19
|
]
|
18
20
|
|
19
21
|
TOKEN_REGEX = Regexp::new(
|
@@ -23,34 +25,36 @@ module Keisan
|
|
23
25
|
attr_reader :expression, :tokens
|
24
26
|
|
25
27
|
def initialize(expression)
|
26
|
-
@expression = self.class.
|
28
|
+
@expression = self.class.normalize_expression(expression)
|
27
29
|
@scan = @expression.scan(TOKEN_REGEX)
|
28
30
|
@tokens = tokenize!
|
29
31
|
end
|
30
32
|
|
31
|
-
def self.
|
32
|
-
|
33
|
-
expression = expression
|
34
|
-
expression = expression.gsub(/\n/, ";")
|
35
|
-
|
36
|
-
# Only strip whitespace outside of strings, e.g.
|
37
|
-
# "1 + 2 + 'hello world'" => "1+2+'hello world'"
|
38
|
-
expression.split(Tokens::String.regex).map.with_index {|s,i| i.even? ? s.gsub(/\s+/, " ") : s}.join
|
33
|
+
def self.normalize_expression(expression)
|
34
|
+
expression = normalize_line_delimiters(expression)
|
35
|
+
expression = remove_comments(expression)
|
39
36
|
end
|
40
37
|
|
41
38
|
private
|
42
39
|
|
43
|
-
def
|
44
|
-
|
40
|
+
def self.normalize_line_delimiters(expression)
|
41
|
+
expression.gsub(/\n/, ";")
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.remove_comments(expression)
|
45
|
+
expression.gsub(/#[^;]*/, "")
|
46
|
+
end
|
45
47
|
|
46
|
-
|
48
|
+
def tokenize!
|
49
|
+
@scan.map do |scan_result|
|
47
50
|
i = scan_result.find_index {|token| !token.nil?}
|
48
51
|
token_string = scan_result[i]
|
49
|
-
|
50
|
-
|
52
|
+
token = TOKEN_CLASSES[i].new(token_string)
|
53
|
+
if token.is_a?(Tokens::Unknown)
|
54
|
+
raise Keisan::Exceptions::TokenizingError.new("Unexpected token: \"#{token.string}\"")
|
55
|
+
end
|
56
|
+
token
|
51
57
|
end
|
52
|
-
|
53
|
-
tokens
|
54
58
|
end
|
55
59
|
end
|
56
60
|
end
|
@@ -1,7 +1,23 @@
|
|
1
1
|
module Keisan
|
2
2
|
module Tokens
|
3
3
|
class Assignment < Operator
|
4
|
-
REGEX = /(
|
4
|
+
REGEX = /(
|
5
|
+
(?: # possible compound operators in front of equals
|
6
|
+
\|\| |
|
7
|
+
\&\& |
|
8
|
+
\*\* |
|
9
|
+
\+ |
|
10
|
+
\- |
|
11
|
+
\* |
|
12
|
+
\/ |
|
13
|
+
\% |
|
14
|
+
\& |
|
15
|
+
\| |
|
16
|
+
\^
|
17
|
+
)?
|
18
|
+
\=
|
19
|
+
(?!\=) # negative lookahead to prevent matching ==
|
20
|
+
)/x
|
5
21
|
|
6
22
|
def self.regex
|
7
23
|
REGEX
|
@@ -10,6 +26,10 @@ module Keisan
|
|
10
26
|
def operator_type
|
11
27
|
:"="
|
12
28
|
end
|
29
|
+
|
30
|
+
def compound_operator
|
31
|
+
string[0] == "=" ? nil : string[0...-1].to_sym
|
32
|
+
end
|
13
33
|
end
|
14
34
|
end
|
15
35
|
end
|
@@ -26,6 +26,11 @@ module Keisan
|
|
26
26
|
raise Exceptions::UndefinedVariableError.new name
|
27
27
|
end
|
28
28
|
|
29
|
+
def freeze
|
30
|
+
@hash.values.each(&:freeze)
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
29
34
|
def locals
|
30
35
|
@hash
|
31
36
|
end
|
@@ -36,15 +41,15 @@ module Keisan
|
|
36
41
|
false
|
37
42
|
end
|
38
43
|
|
44
|
+
def modifiable?(name)
|
45
|
+
!frozen? && has?(name)
|
46
|
+
end
|
47
|
+
|
39
48
|
def register!(name, value, force: false)
|
49
|
+
raise Exceptions::UnmodifiableError.new("Cannot modify frozen variables registry") if frozen?
|
40
50
|
name = name.to_s
|
41
|
-
name = name.name if name.is_a?(AST::Variable)
|
42
51
|
|
43
|
-
|
44
|
-
if !force && @use_defaults && default_registry.has_name?(name)
|
45
|
-
raise Exceptions::UnmodifiableError.new("Cannot overwrite default variable")
|
46
|
-
end
|
47
|
-
self[name.to_s] = AST::Cell.new(value.to_node)
|
52
|
+
self[name.to_s] = value.to_node.to_cell
|
48
53
|
end
|
49
54
|
|
50
55
|
protected
|
data/lib/keisan/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: keisan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Locke
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -138,9 +138,12 @@ files:
|
|
138
138
|
- lib/keisan/ast/boolean.rb
|
139
139
|
- lib/keisan/ast/builder.rb
|
140
140
|
- lib/keisan/ast/cell.rb
|
141
|
+
- lib/keisan/ast/cell_assignment.rb
|
141
142
|
- lib/keisan/ast/constant_literal.rb
|
142
143
|
- lib/keisan/ast/exponent.rb
|
143
144
|
- lib/keisan/ast/function.rb
|
145
|
+
- lib/keisan/ast/function_assignment.rb
|
146
|
+
- lib/keisan/ast/hash.rb
|
144
147
|
- lib/keisan/ast/indexing.rb
|
145
148
|
- lib/keisan/ast/line_builder.rb
|
146
149
|
- lib/keisan/ast/list.rb
|
@@ -172,6 +175,7 @@ files:
|
|
172
175
|
- lib/keisan/ast/unary_operator.rb
|
173
176
|
- lib/keisan/ast/unary_plus.rb
|
174
177
|
- lib/keisan/ast/variable.rb
|
178
|
+
- lib/keisan/ast/variable_assignment.rb
|
175
179
|
- lib/keisan/calculator.rb
|
176
180
|
- lib/keisan/context.rb
|
177
181
|
- lib/keisan/evaluator.rb
|
@@ -188,6 +192,7 @@ files:
|
|
188
192
|
- lib/keisan/functions/csch.rb
|
189
193
|
- lib/keisan/functions/default_registry.rb
|
190
194
|
- lib/keisan/functions/diff.rb
|
195
|
+
- lib/keisan/functions/enumerable_function.rb
|
191
196
|
- lib/keisan/functions/erf.rb
|
192
197
|
- lib/keisan/functions/exp.rb
|
193
198
|
- lib/keisan/functions/expression_function.rb
|
@@ -199,6 +204,7 @@ files:
|
|
199
204
|
- lib/keisan/functions/map.rb
|
200
205
|
- lib/keisan/functions/math_function.rb
|
201
206
|
- lib/keisan/functions/proc_function.rb
|
207
|
+
- lib/keisan/functions/puts.rb
|
202
208
|
- lib/keisan/functions/rand.rb
|
203
209
|
- lib/keisan/functions/range.rb
|
204
210
|
- lib/keisan/functions/real.rb
|
@@ -213,7 +219,9 @@ files:
|
|
213
219
|
- lib/keisan/functions/sqrt.rb
|
214
220
|
- lib/keisan/functions/tan.rb
|
215
221
|
- lib/keisan/functions/tanh.rb
|
222
|
+
- lib/keisan/functions/to_h.rb
|
216
223
|
- lib/keisan/functions/while.rb
|
224
|
+
- lib/keisan/interpreter.rb
|
217
225
|
- lib/keisan/parser.rb
|
218
226
|
- lib/keisan/parsing/argument.rb
|
219
227
|
- lib/keisan/parsing/arithmetic_operator.rb
|
@@ -226,6 +234,7 @@ files:
|
|
226
234
|
- lib/keisan/parsing/bitwise_xor.rb
|
227
235
|
- lib/keisan/parsing/boolean.rb
|
228
236
|
- lib/keisan/parsing/component.rb
|
237
|
+
- lib/keisan/parsing/compound_assignment.rb
|
229
238
|
- lib/keisan/parsing/curly_group.rb
|
230
239
|
- lib/keisan/parsing/divide.rb
|
231
240
|
- lib/keisan/parsing/dot.rb
|
@@ -235,6 +244,7 @@ files:
|
|
235
244
|
- lib/keisan/parsing/exponent.rb
|
236
245
|
- lib/keisan/parsing/function.rb
|
237
246
|
- lib/keisan/parsing/group.rb
|
247
|
+
- lib/keisan/parsing/hash.rb
|
238
248
|
- lib/keisan/parsing/indexing.rb
|
239
249
|
- lib/keisan/parsing/line_separator.rb
|
240
250
|
- lib/keisan/parsing/list.rb
|
@@ -270,6 +280,7 @@ files:
|
|
270
280
|
- lib/keisan/tokens/assignment.rb
|
271
281
|
- lib/keisan/tokens/bitwise_operator.rb
|
272
282
|
- lib/keisan/tokens/boolean.rb
|
283
|
+
- lib/keisan/tokens/colon.rb
|
273
284
|
- lib/keisan/tokens/comma.rb
|
274
285
|
- lib/keisan/tokens/dot.rb
|
275
286
|
- lib/keisan/tokens/group.rb
|
@@ -279,6 +290,7 @@ files:
|
|
279
290
|
- lib/keisan/tokens/number.rb
|
280
291
|
- lib/keisan/tokens/operator.rb
|
281
292
|
- lib/keisan/tokens/string.rb
|
293
|
+
- lib/keisan/tokens/unknown.rb
|
282
294
|
- lib/keisan/tokens/word.rb
|
283
295
|
- lib/keisan/variables/default_registry.rb
|
284
296
|
- lib/keisan/variables/registry.rb
|