keisan 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|