dentaku 3.5.5 → 3.5.7
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/CHANGELOG.md +11 -0
- data/lib/dentaku/ast/arithmetic.rb +27 -1
- data/lib/dentaku/ast/comparators.rb +1 -1
- data/lib/dentaku/parser.rb +48 -83
- data/lib/dentaku/token_scanner.rb +8 -6
- data/lib/dentaku/version.rb +1 -1
- data/spec/ast/addition_spec.rb +3 -3
- data/spec/ast/division_spec.rb +3 -3
- data/spec/calculator_spec.rb +7 -0
- data/spec/parser_spec.rb +5 -0
- data/spec/tokenizer_spec.rb +14 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6992ab2a13558e752be1db54e612dba4230c8e273ebb4bc11b51d655435ab463
|
|
4
|
+
data.tar.gz: fe53f64d1015b13ec909382679e3dbc93ec822fb97d8389a3bd83870fe2dacea
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cad7fc2694c626beb952b44c5014bda140ef5e7953de85e333e8482b35ac02ce87f8054e2e752f9f47a0ae2c5af7666224803d28b484c7c2defaa11aa782521f
|
|
7
|
+
data.tar.gz: 53a267501045fce0f6f4cb26bfb7308e65a9b6cb1a1e8d4386cafffbbb865976b0c320fae2553da30b07193a9126be05068c2b7ba7c5034a341698733cf88305
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## [v3.5.7] 2025-12-16
|
|
4
|
+
- fix misclassification of unary minus as subtraction
|
|
5
|
+
- fix parsing empty function call
|
|
6
|
+
|
|
7
|
+
## [v3.5.6] 2025-10-20
|
|
8
|
+
- fix comparison of Hash with integer
|
|
9
|
+
- refactor case parsing
|
|
10
|
+
- remove input mutation
|
|
11
|
+
- fix bug with arithmetic node validation
|
|
12
|
+
|
|
3
13
|
## [v3.5.5] 2025-08-20
|
|
4
14
|
- fix percentages in print visitor
|
|
5
15
|
- repo cleanup
|
|
@@ -267,6 +277,7 @@
|
|
|
267
277
|
## [v0.1.0] 2012-01-20
|
|
268
278
|
- initial release
|
|
269
279
|
|
|
280
|
+
[v3.5.6]: https://github.com/rubysolo/dentaku/compare/v3.5.5...v3.5.6
|
|
270
281
|
[v3.5.5]: https://github.com/rubysolo/dentaku/compare/v3.5.4...v3.5.5
|
|
271
282
|
[v3.5.4]: https://github.com/rubysolo/dentaku/compare/v3.5.3...v3.5.4
|
|
272
283
|
[v3.5.3]: https://github.com/rubysolo/dentaku/compare/v3.5.2...v3.5.3
|
|
@@ -9,6 +9,20 @@ module Dentaku
|
|
|
9
9
|
DECIMAL = /\A-?\d*\.\d+\z/.freeze
|
|
10
10
|
INTEGER = /\A-?\d+\z/.freeze
|
|
11
11
|
|
|
12
|
+
def initialize(*)
|
|
13
|
+
super
|
|
14
|
+
|
|
15
|
+
unless valid_left?
|
|
16
|
+
raise NodeError.new(:incompatible, left.type, :left),
|
|
17
|
+
"#{self.class} requires operands that are numeric or compatible types, not #{left.type}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
unless valid_right?
|
|
21
|
+
raise NodeError.new(:incompatible, right.type, :right),
|
|
22
|
+
"#{self.class} requires operands that are numeric or compatible types, not #{right.type}"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
12
26
|
def type
|
|
13
27
|
:numeric
|
|
14
28
|
end
|
|
@@ -61,7 +75,19 @@ module Dentaku
|
|
|
61
75
|
end
|
|
62
76
|
|
|
63
77
|
def valid_node?(node)
|
|
64
|
-
|
|
78
|
+
return false unless node
|
|
79
|
+
|
|
80
|
+
# Allow nodes with dependencies (identifiers that will be resolved later)
|
|
81
|
+
return true if node.dependencies.any?
|
|
82
|
+
|
|
83
|
+
# Allow compatible types
|
|
84
|
+
return true if [:numeric, :integer, :array].include?(node.type)
|
|
85
|
+
|
|
86
|
+
# Allow nodes without a type (operations, groupings)
|
|
87
|
+
return true if node.type.nil?
|
|
88
|
+
|
|
89
|
+
# Reject incompatible types
|
|
90
|
+
false
|
|
65
91
|
end
|
|
66
92
|
|
|
67
93
|
def valid_left?
|
|
@@ -20,7 +20,7 @@ module Dentaku
|
|
|
20
20
|
r = validate_value(cast(right.value(context)))
|
|
21
21
|
|
|
22
22
|
l.public_send(operator, r)
|
|
23
|
-
rescue ::ArgumentError => e
|
|
23
|
+
rescue ::ArgumentError, ::TypeError => e
|
|
24
24
|
raise Dentaku::ArgumentError.for(:incompatible_type, value: r, for: l.class), e.message
|
|
25
25
|
end
|
|
26
26
|
|
data/lib/dentaku/parser.rb
CHANGED
|
@@ -37,6 +37,7 @@ module Dentaku
|
|
|
37
37
|
@arities = options.fetch(:arities, [])
|
|
38
38
|
@function_registry = options.fetch(:function_registry, nil)
|
|
39
39
|
@case_sensitive = options.fetch(:case_sensitive, false)
|
|
40
|
+
@skip_indices = []
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
def consume(count = 2)
|
|
@@ -82,19 +83,20 @@ module Dentaku
|
|
|
82
83
|
|
|
83
84
|
i = 0
|
|
84
85
|
while i < input.length
|
|
86
|
+
if @skip_indices.include?(i)
|
|
87
|
+
i += 1
|
|
88
|
+
next
|
|
89
|
+
end
|
|
90
|
+
|
|
85
91
|
token = input[i]
|
|
86
92
|
lookahead = input[i + 1]
|
|
87
|
-
process_token(token, lookahead, i
|
|
93
|
+
process_token(token, lookahead, i)
|
|
88
94
|
i += 1
|
|
89
95
|
end
|
|
90
96
|
|
|
91
|
-
while operations.any?
|
|
92
|
-
consume
|
|
93
|
-
end
|
|
97
|
+
consume while operations.any?
|
|
94
98
|
|
|
95
|
-
unless output.count == 1
|
|
96
|
-
fail! :invalid_statement
|
|
97
|
-
end
|
|
99
|
+
fail! :invalid_statement unless output.count == 1
|
|
98
100
|
|
|
99
101
|
output.first
|
|
100
102
|
end
|
|
@@ -113,7 +115,7 @@ module Dentaku
|
|
|
113
115
|
|
|
114
116
|
private
|
|
115
117
|
|
|
116
|
-
def process_token(token, lookahead, index
|
|
118
|
+
def process_token(token, lookahead, index)
|
|
117
119
|
case token.category
|
|
118
120
|
when :datetime then output << AST::DateTime.new(token)
|
|
119
121
|
when :numeric then output << AST::Numeric.new(token)
|
|
@@ -127,13 +129,13 @@ module Dentaku
|
|
|
127
129
|
when :function
|
|
128
130
|
handle_function(token)
|
|
129
131
|
when :case
|
|
130
|
-
handle_case(token
|
|
132
|
+
handle_case(token)
|
|
131
133
|
when :access
|
|
132
134
|
handle_access(token)
|
|
133
135
|
when :array
|
|
134
136
|
handle_array(token)
|
|
135
137
|
when :grouping
|
|
136
|
-
handle_grouping(token, lookahead,
|
|
138
|
+
handle_grouping(token, lookahead, index)
|
|
137
139
|
else
|
|
138
140
|
fail! :not_implemented_token_category, token_category: token.category
|
|
139
141
|
end
|
|
@@ -142,13 +144,9 @@ module Dentaku
|
|
|
142
144
|
def handle_operator(token, lookahead)
|
|
143
145
|
op_class = operation(token).resolve_class(lookahead)
|
|
144
146
|
if op_class.right_associative?
|
|
145
|
-
while operations.last && operations.last < AST::Operation && op_class.precedence < operations.last.precedence
|
|
146
|
-
consume
|
|
147
|
-
end
|
|
147
|
+
consume while operations.last && operations.last < AST::Operation && op_class.precedence < operations.last.precedence
|
|
148
148
|
else
|
|
149
|
-
while operations.last && operations.last < AST::Operation && op_class.precedence <= operations.last.precedence
|
|
150
|
-
consume
|
|
151
|
-
end
|
|
149
|
+
consume while operations.last && operations.last < AST::Operation && op_class.precedence <= operations.last.precedence
|
|
152
150
|
end
|
|
153
151
|
operations.push op_class
|
|
154
152
|
end
|
|
@@ -160,74 +158,40 @@ module Dentaku
|
|
|
160
158
|
operations.push func
|
|
161
159
|
end
|
|
162
160
|
|
|
163
|
-
def handle_case(token
|
|
164
|
-
|
|
161
|
+
def handle_case(token)
|
|
162
|
+
# We always operate on the innermost (most recent) CASE on the stack.
|
|
163
|
+
case_index = operations.rindex(AST::Case) || -1
|
|
165
164
|
token_index = case_index + 1
|
|
166
165
|
|
|
167
166
|
case token.value
|
|
168
167
|
when :open
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
case_end_index = nil
|
|
173
|
-
j = index + 1
|
|
174
|
-
while j < tokens.length
|
|
175
|
-
t = tokens[j]
|
|
176
|
-
if t.category == :case
|
|
177
|
-
if t.value == :open
|
|
178
|
-
open_cases += 1
|
|
179
|
-
elsif t.value == :close
|
|
180
|
-
if open_cases > 0
|
|
181
|
-
open_cases -= 1
|
|
182
|
-
else
|
|
183
|
-
case_end_index = j
|
|
184
|
-
break
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
j += 1
|
|
189
|
-
end
|
|
190
|
-
inner_case_inputs = tokens.slice!(index + 1, case_end_index - index) || []
|
|
191
|
-
subparser = Parser.new(
|
|
192
|
-
inner_case_inputs,
|
|
193
|
-
operations: [AST::Case],
|
|
194
|
-
arities: [0],
|
|
195
|
-
function_registry: @function_registry,
|
|
196
|
-
case_sensitive: case_sensitive
|
|
197
|
-
)
|
|
198
|
-
subparser.parse
|
|
199
|
-
output.concat(subparser.output)
|
|
200
|
-
else
|
|
201
|
-
operations.push AST::Case
|
|
202
|
-
arities.push(0)
|
|
203
|
-
end
|
|
168
|
+
# Start a new CASE context.
|
|
169
|
+
operations.push AST::Case
|
|
170
|
+
arities.push(0)
|
|
204
171
|
|
|
205
172
|
when :close
|
|
173
|
+
# Finalize any trailing THEN/ELSE expression still on the stack.
|
|
206
174
|
if operations[token_index] == AST::CaseThen
|
|
207
|
-
|
|
208
|
-
consume
|
|
209
|
-
end
|
|
175
|
+
consume_until(AST::Case)
|
|
210
176
|
operations.push(AST::CaseConditional)
|
|
211
177
|
consume(2)
|
|
212
178
|
arities[-1] += 1
|
|
213
179
|
elsif operations[token_index] == AST::CaseElse
|
|
214
|
-
|
|
215
|
-
consume
|
|
216
|
-
end
|
|
180
|
+
consume_until(AST::Case)
|
|
217
181
|
arities[-1] += 1
|
|
218
182
|
end
|
|
219
|
-
fail! :unprocessed_token, token_name: token.value unless operations.
|
|
183
|
+
fail! :unprocessed_token, token_name: token.value unless operations.last == AST::Case
|
|
220
184
|
consume(arities.pop.succ)
|
|
221
185
|
|
|
222
186
|
when :when
|
|
223
187
|
if operations[token_index] == AST::CaseThen
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
end
|
|
188
|
+
# Close out previous WHEN/THEN pair.
|
|
189
|
+
consume_until([AST::CaseWhen, AST::Case])
|
|
227
190
|
operations.push(AST::CaseConditional)
|
|
228
191
|
consume(2)
|
|
229
192
|
arities[-1] += 1
|
|
230
193
|
elsif operations.last == AST::Case
|
|
194
|
+
# First WHEN: finalize switch variable expression.
|
|
231
195
|
operations.push(AST::CaseSwitchVariable)
|
|
232
196
|
consume
|
|
233
197
|
end
|
|
@@ -235,36 +199,41 @@ module Dentaku
|
|
|
235
199
|
|
|
236
200
|
when :then
|
|
237
201
|
if operations[token_index] == AST::CaseWhen
|
|
238
|
-
|
|
239
|
-
consume
|
|
240
|
-
end
|
|
202
|
+
consume_until([AST::CaseThen, AST::Case])
|
|
241
203
|
end
|
|
242
204
|
operations.push(AST::CaseThen)
|
|
243
205
|
|
|
244
206
|
when :else
|
|
245
207
|
if operations[token_index] == AST::CaseThen
|
|
246
|
-
|
|
247
|
-
consume
|
|
248
|
-
end
|
|
208
|
+
consume_until(AST::Case)
|
|
249
209
|
operations.push(AST::CaseConditional)
|
|
250
210
|
consume(2)
|
|
251
211
|
arities[-1] += 1
|
|
252
212
|
end
|
|
253
213
|
operations.push(AST::CaseElse)
|
|
214
|
+
|
|
254
215
|
else
|
|
255
216
|
fail! :unknown_case_token, token_name: token.value
|
|
256
217
|
end
|
|
257
218
|
end
|
|
258
219
|
|
|
220
|
+
def consume_until(target)
|
|
221
|
+
matcher =
|
|
222
|
+
case target
|
|
223
|
+
when Array then ->(op) { target.include?(op) }
|
|
224
|
+
else ->(op) { op == target }
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
consume while operations.any? && !matcher.call(operations.last)
|
|
228
|
+
end
|
|
229
|
+
|
|
259
230
|
def handle_access(token)
|
|
260
231
|
case token.value
|
|
261
232
|
when :lbracket
|
|
262
233
|
operations.push AST::Access
|
|
263
234
|
|
|
264
235
|
when :rbracket
|
|
265
|
-
while operations.any? && operations.last != AST::Access
|
|
266
|
-
consume
|
|
267
|
-
end
|
|
236
|
+
consume while operations.any? && operations.last != AST::Access
|
|
268
237
|
fail! :unbalanced_bracket, token: token unless operations.last == AST::Access
|
|
269
238
|
consume
|
|
270
239
|
end
|
|
@@ -277,20 +246,19 @@ module Dentaku
|
|
|
277
246
|
arities.push 0
|
|
278
247
|
|
|
279
248
|
when :array_end
|
|
280
|
-
while operations.any? && operations.last != AST::Array
|
|
281
|
-
consume
|
|
282
|
-
end
|
|
249
|
+
consume while operations.any? && operations.last != AST::Array
|
|
283
250
|
fail! :unbalanced_bracket, token: token unless operations.last == AST::Array
|
|
284
251
|
consume(arities.pop.succ)
|
|
285
252
|
end
|
|
286
253
|
end
|
|
287
254
|
|
|
288
|
-
def handle_grouping(token, lookahead,
|
|
255
|
+
def handle_grouping(token, lookahead, token_index)
|
|
289
256
|
case token.value
|
|
290
257
|
when :open
|
|
291
258
|
if lookahead && lookahead.value == :close
|
|
292
259
|
# empty grouping (e.g. function with zero arguments) — we trigger consume later
|
|
293
|
-
|
|
260
|
+
# skip to the end
|
|
261
|
+
@skip_indices << token_index + 1
|
|
294
262
|
arities.pop
|
|
295
263
|
consume(0)
|
|
296
264
|
else
|
|
@@ -298,9 +266,7 @@ module Dentaku
|
|
|
298
266
|
end
|
|
299
267
|
|
|
300
268
|
when :close
|
|
301
|
-
while operations.any? && operations.last != AST::Grouping
|
|
302
|
-
consume
|
|
303
|
-
end
|
|
269
|
+
consume while operations.any? && operations.last != AST::Grouping
|
|
304
270
|
lparen = operations.pop
|
|
305
271
|
fail! :unbalanced_parenthesis, token unless lparen == AST::Grouping
|
|
306
272
|
if operations.last && operations.last < AST::Function
|
|
@@ -310,9 +276,8 @@ module Dentaku
|
|
|
310
276
|
when :comma
|
|
311
277
|
fail! :invalid_statement if arities.empty?
|
|
312
278
|
arities[-1] += 1
|
|
313
|
-
while operations.any? && operations.last != AST::Grouping && operations.last != AST::Array
|
|
314
|
-
|
|
315
|
-
end
|
|
279
|
+
consume while operations.any? && operations.last != AST::Grouping && operations.last != AST::Array
|
|
280
|
+
|
|
316
281
|
else
|
|
317
282
|
fail! :unknown_grouping_token, token_name: token.value
|
|
318
283
|
end
|
|
@@ -114,12 +114,14 @@ module Dentaku
|
|
|
114
114
|
|
|
115
115
|
def negate
|
|
116
116
|
new(:operator, '-', lambda { |raw| :negate }, lambda { |last_token|
|
|
117
|
-
last_token.nil?
|
|
118
|
-
last_token.is?(:operator)
|
|
119
|
-
last_token.is?(:comparator)
|
|
120
|
-
last_token.is?(:combinator)
|
|
121
|
-
last_token.value == :open
|
|
122
|
-
last_token.value == :comma
|
|
117
|
+
last_token.nil? ||
|
|
118
|
+
last_token.is?(:operator) ||
|
|
119
|
+
last_token.is?(:comparator) ||
|
|
120
|
+
last_token.is?(:combinator) ||
|
|
121
|
+
last_token.value == :open ||
|
|
122
|
+
last_token.value == :comma ||
|
|
123
|
+
last_token.value == :lbracket ||
|
|
124
|
+
last_token.value == :array_start
|
|
123
125
|
})
|
|
124
126
|
end
|
|
125
127
|
|
data/lib/dentaku/version.rb
CHANGED
data/spec/ast/addition_spec.rb
CHANGED
|
@@ -22,14 +22,14 @@ describe Dentaku::AST::Addition do
|
|
|
22
22
|
|
|
23
23
|
it 'requires operands that respond to +' do
|
|
24
24
|
expect {
|
|
25
|
-
described_class.new(five, t)
|
|
26
|
-
}.to raise_error(Dentaku::
|
|
25
|
+
described_class.new(five, t)
|
|
26
|
+
}.to raise_error(Dentaku::NodeError, /requires operands/)
|
|
27
27
|
|
|
28
28
|
expression = Dentaku::AST::Multiplication.new(five, five)
|
|
29
29
|
group = Dentaku::AST::Grouping.new(expression)
|
|
30
30
|
|
|
31
31
|
expect {
|
|
32
|
-
described_class.new(group, five)
|
|
32
|
+
described_class.new(group, five)
|
|
33
33
|
}.not_to raise_error
|
|
34
34
|
end
|
|
35
35
|
|
data/spec/ast/division_spec.rb
CHANGED
|
@@ -22,14 +22,14 @@ describe Dentaku::AST::Division do
|
|
|
22
22
|
|
|
23
23
|
it 'requires operands that respond to /' do
|
|
24
24
|
expect {
|
|
25
|
-
described_class.new(five, t)
|
|
26
|
-
}.to raise_error(Dentaku::
|
|
25
|
+
described_class.new(five, t)
|
|
26
|
+
}.to raise_error(Dentaku::NodeError, /requires operands/)
|
|
27
27
|
|
|
28
28
|
expression = Dentaku::AST::Multiplication.new(five, five)
|
|
29
29
|
group = Dentaku::AST::Grouping.new(expression)
|
|
30
30
|
|
|
31
31
|
expect {
|
|
32
|
-
described_class.new(group, five)
|
|
32
|
+
described_class.new(group, five)
|
|
33
33
|
}.not_to raise_error
|
|
34
34
|
end
|
|
35
35
|
|
data/spec/calculator_spec.rb
CHANGED
|
@@ -130,6 +130,7 @@ describe Dentaku::Calculator do
|
|
|
130
130
|
expect { calculator.evaluate!('"foo" & "bar"') }.to raise_error(Dentaku::ArgumentError)
|
|
131
131
|
expect { calculator.evaluate!('1.0 & "bar"') }.to raise_error(Dentaku::ArgumentError)
|
|
132
132
|
expect { calculator.evaluate!('1 & "bar"') }.to raise_error(Dentaku::ArgumentError)
|
|
133
|
+
expect { calculator.evaluate!('data < 1', data: { a: 5 }) }.to raise_error(Dentaku::ArgumentError)
|
|
133
134
|
end
|
|
134
135
|
|
|
135
136
|
it 'raises argument error if a function is called with incorrect arity' do
|
|
@@ -235,6 +236,12 @@ describe Dentaku::Calculator do
|
|
|
235
236
|
expect(calculator.dependencies('MAP(vals, val, val + step)')).to eq(['vals', 'step'])
|
|
236
237
|
expect(calculator.dependencies('ALL(people, person, person.age < adult)')).to eq(['people', 'adult'])
|
|
237
238
|
end
|
|
239
|
+
|
|
240
|
+
it "raises an error when trying to find dependencies with invalid syntax" do
|
|
241
|
+
expect { calculator.dependencies('bob + / 3') }.to raise_error(Dentaku::ParseError)
|
|
242
|
+
expect { calculator.dependencies('123 * TRUE') }.to raise_error(Dentaku::ParseError)
|
|
243
|
+
expect { calculator.dependencies('4 + "asdf"') }.to raise_error(Dentaku::ParseError)
|
|
244
|
+
end
|
|
238
245
|
end
|
|
239
246
|
|
|
240
247
|
describe 'solve!' do
|
data/spec/parser_spec.rb
CHANGED
|
@@ -52,6 +52,11 @@ describe Dentaku::Parser do
|
|
|
52
52
|
expect(node.value).to eq(2)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
it 'parses multiple zero-argument functions in sequence' do
|
|
56
|
+
node = parse('count() + count()') # count() without arguments returns 0
|
|
57
|
+
expect(node.value).to eq(0)
|
|
58
|
+
end
|
|
59
|
+
|
|
55
60
|
it 'represents formulas with variables' do
|
|
56
61
|
node = parse('5 * x')
|
|
57
62
|
expect { node.value }.to raise_error(Dentaku::UnboundVariableError)
|
data/spec/tokenizer_spec.rb
CHANGED
|
@@ -49,6 +49,20 @@ describe Dentaku::Tokenizer do
|
|
|
49
49
|
expect(tokens.map(&:category)).to eq([:grouping, :operator, :numeric, :grouping])
|
|
50
50
|
expect(tokens.map(&:value)).to eq([:open, :negate, 5, :close])
|
|
51
51
|
|
|
52
|
+
tokens = tokenizer.tokenize('{-5, -2}[-1]')
|
|
53
|
+
expect(tokens.map(&:category)).to eq([
|
|
54
|
+
:array, # {
|
|
55
|
+
:operator, :numeric, :grouping, # -5,
|
|
56
|
+
:operator, :numeric, :array, # -2}
|
|
57
|
+
:access, :operator, :numeric, :access # [-1]
|
|
58
|
+
])
|
|
59
|
+
expect(tokens.map(&:value)).to eq([
|
|
60
|
+
:array_start, # {
|
|
61
|
+
:negate, 5, :comma, # -5,
|
|
62
|
+
:negate, 2, :array_end, # -2}
|
|
63
|
+
:lbracket, :negate, 1, :rbracket # [-1]
|
|
64
|
+
])
|
|
65
|
+
|
|
52
66
|
tokens = tokenizer.tokenize('if(-5 > x, -7, -8) - 9')
|
|
53
67
|
expect(tokens.map(&:category)).to eq([
|
|
54
68
|
:function, :grouping, # if(
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dentaku
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.5.
|
|
4
|
+
version: 3.5.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Solomon White
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2025-
|
|
10
|
+
date: 2025-12-16 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: bigdecimal
|