code-ruby 0.13.1 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +15 -0
  3. data/.github/workflows/ci.yml +31 -0
  4. data/.rubocop.yml +8 -0
  5. data/Gemfile +2 -0
  6. data/Gemfile.lock +51 -3
  7. data/bin/bundle-audit +31 -0
  8. data/bin/bundler-audit +31 -0
  9. data/bin/console +1 -0
  10. data/bin/rspec +31 -0
  11. data/bin/rubocop +31 -0
  12. data/lib/code/error.rb +0 -3
  13. data/lib/code/node/base_10.rb +4 -3
  14. data/lib/code/node/base_16.rb +1 -0
  15. data/lib/code/node/base_2.rb +1 -0
  16. data/lib/code/node/base_8.rb +1 -0
  17. data/lib/code/node/boolean.rb +1 -0
  18. data/lib/code/node/call.rb +14 -15
  19. data/lib/code/node/call_argument.rb +4 -4
  20. data/lib/code/node/code.rb +1 -0
  21. data/lib/code/node/decimal.rb +4 -3
  22. data/lib/code/node/dictionary.rb +5 -3
  23. data/lib/code/node/function.rb +1 -0
  24. data/lib/code/node/function_parameter.rb +14 -0
  25. data/lib/code/node/if.rb +6 -4
  26. data/lib/code/node/left_operation.rb +3 -3
  27. data/lib/code/node/list.rb +1 -0
  28. data/lib/code/node/negation.rb +1 -0
  29. data/lib/code/node/not.rb +1 -0
  30. data/lib/code/node/nothing.rb +1 -0
  31. data/lib/code/node/right_operation.rb +3 -2
  32. data/lib/code/node/splat.rb +1 -0
  33. data/lib/code/node/square_bracket.rb +1 -0
  34. data/lib/code/node/string.rb +3 -0
  35. data/lib/code/node/ternary.rb +4 -3
  36. data/lib/code/node/unary_minus.rb +1 -0
  37. data/lib/code/node/while.rb +4 -3
  38. data/lib/code/object/boolean.rb +2 -2
  39. data/lib/code/object/context.rb +1 -1
  40. data/lib/code/object/decimal.rb +9 -21
  41. data/lib/code/object/dictionary.rb +43 -113
  42. data/lib/code/object/function.rb +25 -35
  43. data/lib/code/object/global.rb +33 -32
  44. data/lib/code/object/identifier_list.rb +4 -4
  45. data/lib/code/object/integer.rb +14 -23
  46. data/lib/code/object/json.rb +10 -2
  47. data/lib/code/object/list.rb +50 -23
  48. data/lib/code/object/parameter.rb +18 -10
  49. data/lib/code/object/range.rb +33 -10
  50. data/lib/code/object/string.rb +2 -2
  51. data/lib/code/object/time.rb +4 -4
  52. data/lib/code/object.rb +31 -50
  53. data/lib/code/parser/string.rb +1 -1
  54. data/lib/code/type/repeat.rb +1 -1
  55. data/lib/code/type/sig.rb +1 -3
  56. data/lib/code/version.rb +1 -1
  57. data/lib/code-ruby.rb +2 -7
  58. data/lib/code.rb +1 -3
  59. data/spec/code/object/dictionary_spec.rb +6 -6
  60. data/spec/code_spec.rb +5 -8
  61. data/yarn.lock +4 -0
  62. metadata +10 -3
  63. data/lib/code/object/argument.rb +0 -27
@@ -5,6 +5,7 @@ class Code
5
5
  class Splat < Node
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
+
8
9
  @operator = parsed.delete(:operator).presence
9
10
  @right = Node::Statement.new(parsed.delete(:right).presence)
10
11
  end
@@ -5,6 +5,7 @@ class Code
5
5
  class SquareBracket < Node
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
+
8
9
  @left = Node::Statement.new(parsed.delete(:left).presence)
9
10
  @statements = parsed.delete(:statements).presence || []
10
11
  @statements.map! { |statement| Node::Statement.new(statement) }
@@ -7,6 +7,7 @@ class Code
7
7
  class Code < Node
8
8
  def initialize(parsed)
9
9
  return if parsed.blank?
10
+
10
11
  @code = Node::Code.new(parsed.presence)
11
12
  end
12
13
 
@@ -18,6 +19,7 @@ class Code
18
19
  class Text < Node
19
20
  def initialize(parsed)
20
21
  return if parsed.blank?
22
+
21
23
  @text = parsed
22
24
  end
23
25
 
@@ -53,6 +55,7 @@ class Code
53
55
 
54
56
  def initialize(parsed)
55
57
  return if parsed.blank?
58
+
56
59
  @parts =
57
60
  (parsed.presence || []).map { |part| Node::String::Part.new(part) }
58
61
  end
@@ -5,11 +5,12 @@ class Code
5
5
  class Ternary < Node
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
+
8
9
  @left = Node::Statement.new(parsed.delete(:left).presence)
9
10
  @middle = Node::Statement.new(parsed.delete(:middle).presence)
10
- if parsed.key?(:right)
11
- @right = Node::Statement.new(parsed.delete(:right).presence)
12
- end
11
+ return unless parsed.key?(:right)
12
+
13
+ @right = Node::Statement.new(parsed.delete(:right).presence)
13
14
  end
14
15
 
15
16
  def evaluate(**args)
@@ -5,6 +5,7 @@ class Code
5
5
  class UnaryMinus < Node
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
+
8
9
  @operator = parsed.delete(:operator).presence
9
10
  @right = Node::Statement.new(parsed.delete(:right).presence)
10
11
  end
@@ -9,10 +9,11 @@ class Code
9
9
 
10
10
  def initialize(parsed)
11
11
  return if parsed.blank?
12
+
12
13
  @operator = parsed.delete(:operator).presence
13
- if parsed.key?(:statement)
14
- @statement = Statement.new(parsed.delete(:statement))
15
- end
14
+ @statement = Statement.new(parsed.delete(:statement)) if parsed.key?(
15
+ :statement
16
+ )
16
17
  @body = Code.new(parsed.delete(:body).presence)
17
18
  end
18
19
 
@@ -11,8 +11,8 @@ class Code
11
11
 
12
12
  def call(**args)
13
13
  operator = args.fetch(:operator, nil)
14
- arguments = args.fetch(:arguments, [])
15
- value = arguments.first&.value
14
+ arguments = args.fetch(:arguments, List.new)
15
+ value = arguments.code_first
16
16
 
17
17
  case operator.to_s
18
18
  when "&", "bitwise_and"
@@ -18,7 +18,7 @@ class Code
18
18
  elsif parent?
19
19
  parent.lookup!(identifier)
20
20
  else
21
- raise Error::Undefined, "#{identifier} is not defined"
21
+ raise Error::Undefined, "#{identifier} is not defined"
22
22
  end
23
23
  end
24
24
 
@@ -9,14 +9,14 @@ class Code
9
9
  decimal = decimal.raw if decimal.is_an?(Object)
10
10
  exponent = exponent.raw if exponent.is_an?(Object)
11
11
  @raw = decimal.to_d * 10**exponent.to_d
12
- rescue FloatDomainError => e
12
+ rescue FloatDomainError
13
13
  raise Error, "#{decimal.inspect} * 10**#{exponent.inspect} is invalid"
14
14
  end
15
15
 
16
16
  def call(**args)
17
17
  operator = args.fetch(:operator, nil)
18
- arguments = args.fetch(:arguments, [])
19
- value = arguments.first&.value
18
+ arguments = args.fetch(:arguments, List.new)
19
+ value = arguments.code_first
20
20
 
21
21
  case operator.to_s
22
22
  when "%", "modulo"
@@ -33,10 +33,10 @@ class Code
33
33
  code_power(value)
34
34
  when "+", "plus"
35
35
  sig(args) { Object.maybe }
36
- value ? code_plus(value) : self
36
+ arguments.any? ? code_plus(value) : self
37
37
  when "-", "minus"
38
38
  sig(args) { (Integer | Decimal).maybe }
39
- value ? code_minus(value) : code_unary_minus
39
+ arguments.any? ? code_minus(value) : code_unary_minus
40
40
  when "/", "division"
41
41
  sig(args) { Integer | Decimal }
42
42
  code_division(value)
@@ -152,7 +152,7 @@ class Code
152
152
  end
153
153
 
154
154
  def code_ceil(n = nil)
155
- n ||= Integer.new(0)
155
+ n = Integer.new(0) if n.nil? || n.is_a?(Nothing)
156
156
  Decimal.new(raw.ceil(n.raw))
157
157
  end
158
158
 
@@ -177,7 +177,7 @@ class Code
177
177
  end
178
178
 
179
179
  def code_floor(n = nil)
180
- n ||= Integer.new(0)
180
+ n = Integer.new(0) if n.nil? || n.is_a?(Nothing)
181
181
  Decimal.new(raw.floor(n.raw))
182
182
  end
183
183
 
@@ -234,7 +234,7 @@ class Code
234
234
  end
235
235
 
236
236
  def code_round(n = nil)
237
- n ||= Integer.new(0)
237
+ n = Integer.new(0) if n.nil? || n.is_a?(Nothing)
238
238
  Decimal.new(raw.round(n.raw))
239
239
  end
240
240
 
@@ -279,7 +279,7 @@ class Code
279
279
  end
280
280
 
281
281
  def code_truncate(n = nil)
282
- n ||= Integer.new(0)
282
+ n = Integer.new(0) if n.nil? || n.is_a?(Nothing)
283
283
  Decimal.new(raw.truncate(n.raw))
284
284
  end
285
285
 
@@ -294,18 +294,6 @@ class Code
294
294
  def code_zero?
295
295
  Boolean.new(raw.zero?)
296
296
  end
297
-
298
- def whole?
299
- whole == raw
300
- end
301
-
302
- def whole
303
- raw.round
304
- end
305
-
306
- def as_json(...)
307
- whole? ? whole.as_json(...) : super
308
- end
309
297
  end
310
298
  end
311
299
  end
@@ -3,19 +3,15 @@
3
3
  class Code
4
4
  class Object
5
5
  class Dictionary < ::Code::Object
6
- def initialize(*args, **_kargs, &_block)
7
- @raw = (args.first.presence || {})
8
- .as_json
9
- .to_h
10
- .transform_keys { |key| Json.to_code(key) }
11
- .transform_values { |value| Json.to_code(value) }
6
+ def initialize(*args, **kargs, &_block)
7
+ @raw = args.map(&:to_h).reduce({}, &:merge).merge(kargs)
12
8
  end
13
9
 
14
10
  def call(**args)
15
11
  operator = args.fetch(:operator, nil)
16
- arguments = args.fetch(:arguments, [])
12
+ arguments = args.fetch(:arguments, List.new)
17
13
  globals = multi_fetch(args, *GLOBALS)
18
- value = arguments.first&.value
14
+ value = arguments.code_first
19
15
 
20
16
  case operator.to_s
21
17
  when "<", "inferior"
@@ -50,7 +46,7 @@ class Code
50
46
  code_compact
51
47
  when "delete"
52
48
  sig(args) { Object.repeat(1) }
53
- code_delete(*arguments.map(&:value), **globals)
49
+ code_delete(*arguments.raw, **globals)
54
50
  when "delete_if"
55
51
  sig(args) { Function | Class }
56
52
  code_delete_if(value, **globals)
@@ -59,7 +55,7 @@ class Code
59
55
  code_delete_unless(value, **globals)
60
56
  when "dig"
61
57
  sig(args) { Object.repeat(1) }
62
- code_dig(*arguments.map(&:value))
58
+ code_dig(*arguments.raw)
63
59
  when "each"
64
60
  sig(args) { Function }
65
61
  code_each(value, **globals)
@@ -71,13 +67,13 @@ class Code
71
67
  code_empty?
72
68
  when "except"
73
69
  sig(args) { Object.repeat(1) }
74
- code_except(*arguments.map(&:value))
70
+ code_except(*arguments.raw)
75
71
  when "fetch"
76
72
  sig(args) { Object.repeat(1) }
77
- code_fetch(*arguments.map(&:value), **globals)
73
+ code_fetch(*arguments.raw, **globals)
78
74
  when "fetch_values"
79
75
  sig(args) { Object.repeat(1) }
80
- code_fetch_values(*arguments.map(&:value))
76
+ code_fetch_values(*arguments.raw)
81
77
  when "five?"
82
78
  sig(args)
83
79
  code_five?
@@ -104,13 +100,13 @@ class Code
104
100
  code_keep_unless(value, **globals)
105
101
  when "key"
106
102
  sig(args) { [Object, Function.maybe] }
107
- code_key(*arguments.map(&:value), **globals)
103
+ code_key(*arguments.raw, **globals)
108
104
  when "keys"
109
105
  sig(args)
110
106
  code_keys
111
107
  when "merge"
112
108
  sig(args) { [Dictionary.repeat, Function.maybe] }
113
- code_merge(*arguments.map(&:value), **globals)
109
+ code_merge(*arguments.raw, **globals)
114
110
  when "nine?"
115
111
  sig(args)
116
112
  code_nine?
@@ -177,12 +173,7 @@ class Code
177
173
  raw.any? do |key, value|
178
174
  argument
179
175
  .call(
180
- arguments: [
181
- Argument.new(key),
182
- Argument.new(value),
183
- Argument.new(self),
184
- Argument.new(Integer.new(index))
185
- ],
176
+ arguments: List.new([key, value, self, Integer.new(index)]),
186
177
  **globals
187
178
  )
188
179
  .truthy?
@@ -219,22 +210,16 @@ class Code
219
210
  )
220
211
 
221
212
  arguments = arguments[..-2] if default
213
+ first = arguments.first
222
214
 
223
215
  if arguments.one?
224
- raw.delete(arguments.first) do
216
+ raw.delete(first) do
225
217
  if default
226
- default.call(
227
- arguments: [
228
- Argument.new(arguments.first),
229
- Argument.new(self),
230
- Argument.new(index)
231
- ],
232
- **globals
233
- )
218
+ default.call(arguments: List.new([first, self, index]), **globals)
234
219
  else
235
220
  raise(
236
221
  Code::Error::KeyNotFound,
237
- "#{arguments.first.inspect} not found on #{inspect}"
222
+ "#{first.inspect} not found on #{inspect}"
238
223
  )
239
224
  end
240
225
  end
@@ -271,12 +256,7 @@ class Code
271
256
  else
272
257
  raw.delete_if.with_index do |(key, value), index|
273
258
  argument.call(
274
- arguments: [
275
- Argument.new(key),
276
- Argument.new(value),
277
- Argument.new(self),
278
- Argument.new(Integer.new(index))
279
- ],
259
+ arguments: List.new([key, value, self, Integer.new(index)]),
280
260
  **globals
281
261
  ).truthy?
282
262
  end
@@ -291,12 +271,7 @@ class Code
291
271
  else
292
272
  raw.delete_if.with_index do |(key, value), index|
293
273
  argument.call(
294
- arguments: [
295
- Argument.new(key),
296
- Argument.new(value),
297
- Argument.new(self),
298
- Argument.new(Integer.new(index))
299
- ],
274
+ arguments: List.new([key, value, self, Integer.new(index)]),
300
275
  **globals
301
276
  ).falsy?
302
277
  end
@@ -312,12 +287,7 @@ class Code
312
287
  def code_each(argument, **globals)
313
288
  raw.each.with_index do |(key, value), index|
314
289
  argument.call(
315
- arguments: [
316
- Argument.new(key),
317
- Argument.new(value),
318
- Argument.new(self),
319
- Argument.new(Integer.new(index))
320
- ],
290
+ arguments: List.new([key, value, self, Integer.new(index)]),
321
291
  **globals
322
292
  )
323
293
  end
@@ -337,7 +307,7 @@ class Code
337
307
  self.class.new(raw.except(*))
338
308
  end
339
309
 
340
- def code_fetch(*arguments, index: Integer.new(0), **globals)
310
+ def code_fetch(*arguments, index: 0, **globals)
341
311
  default =
342
312
  (
343
313
  if arguments.last.is_a?(Function) && arguments.size > 1
@@ -346,45 +316,31 @@ class Code
346
316
  )
347
317
 
348
318
  arguments = arguments[..-2] if default
319
+ first = arguments.first || Nothing.new
349
320
 
350
321
  if arguments.one?
351
- raw.fetch(arguments.first) do
322
+ raw.fetch(first) do
352
323
  if default
353
324
  default.call(
354
- arguments: [
355
- Argument.new(arguments.first),
356
- Argument.new(self),
357
- Argument.new(index)
358
- ],
325
+ arguments: List.new([first, Integer.new(index), self]),
359
326
  **globals
360
327
  )
361
328
  else
362
329
  raise(
363
- Code::Error::KeyNotFound,
364
- "#{arguments.first.inspect} not found on #{inspect}"
330
+ Error::KeyNotFound,
331
+ "#{first.inspect} not found on #{inspect}"
365
332
  )
366
333
  end
367
334
  end
368
335
  else
369
- self.class.new(
336
+ Dictionary.new(
370
337
  arguments
371
338
  .map
372
339
  .with_index do |argument, index|
373
340
  if default
374
- [
375
- argument,
376
- code_fetch(
377
- argument,
378
- default,
379
- index: Integer.new(index),
380
- **globals
381
- )
382
- ]
341
+ [argument, code_fetch(argument, default, index:, **globals)]
383
342
  else
384
- [
385
- argument,
386
- code_fetch(argument, index: Integer.new(index), **globals)
387
- ]
343
+ [argument, code_fetch(argument, index:, **globals)]
388
344
  end
389
345
  end
390
346
  .to_h
@@ -401,7 +357,7 @@ class Code
401
357
  end
402
358
 
403
359
  def code_flatten(level = nil)
404
- level ||= Integer.new(-1)
360
+ level = Integer.new(-1) if level.nil? || level.falsy?
405
361
  code_to_list.code_flatten(level)
406
362
  end
407
363
 
@@ -439,12 +395,7 @@ class Code
439
395
  else
440
396
  raw.keep_if.with_index do |(key, value), index|
441
397
  argument.call(
442
- arguments: [
443
- Argument.new(key),
444
- Argument.new(value),
445
- Argument.new(self),
446
- Argument.new(Integer.new(index))
447
- ],
398
+ arguments: List.new([key, value, Integer.new(index), self]),
448
399
  **globals
449
400
  ).truthy?
450
401
  end
@@ -459,12 +410,7 @@ class Code
459
410
  else
460
411
  raw.keep_if.with_index do |(key, value), index|
461
412
  argument.call(
462
- arguments: [
463
- Argument.new(key),
464
- Argument.new(value),
465
- Argument.new(self),
466
- Argument.new(Integer.new(index))
467
- ],
413
+ arguments: List.new([key, value, Integer.new(index), self]),
468
414
  **globals
469
415
  ).falsy?
470
416
  rescue Error::Next => e
@@ -478,10 +424,7 @@ class Code
478
424
  def code_key(value, function = nil, **globals)
479
425
  if function
480
426
  raw.key(value) ||
481
- function.call(
482
- arguments: [Argument.new(value), Argument.new(self)],
483
- **globals
484
- )
427
+ function.call(arguments: List.new([value, self]), **globals)
485
428
  else
486
429
  raw.key(value) || Nothing.new
487
430
  end
@@ -510,13 +453,10 @@ class Code
510
453
  if conflict
511
454
  conflict
512
455
  .call(
513
- arguments: [
514
- Argument.new(key),
515
- Argument.new(old_value),
516
- Argument.new(new_value),
517
- Argument.new(self),
518
- Argument.new(Integer.new(index))
519
- ],
456
+ arguments:
457
+ List.new(
458
+ [key, old_value, new_value, Integer.new(index), self]
459
+ ),
520
460
  **globals
521
461
  )
522
462
  .tap { index += 1 }
@@ -544,12 +484,7 @@ class Code
544
484
  else
545
485
  raw.select!.with_index do |(key, value), index|
546
486
  argument.call(
547
- arguments: [
548
- Argument.new(key),
549
- Argument.new(value),
550
- Argument.new(self),
551
- Argument.new(Integer.new(index))
552
- ],
487
+ arguments: List.new([key, value, Integer.new(index), self]),
553
488
  **globals
554
489
  ).truthy?
555
490
  rescue Error::Next => e
@@ -567,12 +502,7 @@ class Code
567
502
  self.class.new(
568
503
  raw.select.with_index do |(key, value), index|
569
504
  argument.call(
570
- arguments: [
571
- Argument.new(key),
572
- Argument.new(value),
573
- Argument.new(self),
574
- Argument.new(Integer.new(index))
575
- ],
505
+ arguments: List.new([key, value, Integer.new(index), self]),
576
506
  **globals
577
507
  ).truthy?
578
508
  rescue Error::Next => e
@@ -623,15 +553,15 @@ class Code
623
553
  List.new(raw.to_a.map { |key_value| List.new(key_value) })
624
554
  end
625
555
 
556
+ def to_h
557
+ raw
558
+ end
559
+
626
560
  def code_transform_values(function, **globals)
627
561
  self.class.new(
628
562
  raw.transform_values.with_index do |value, index|
629
563
  function.call(
630
- arguments: [
631
- Argument.new(value),
632
- Argument.new(self),
633
- Argument.new(Integer.new(index))
634
- ],
564
+ arguments: List.new([value, Integer.new(index), self]),
635
565
  **globals
636
566
  )
637
567
  rescue Error::Next => e
@@ -14,13 +14,13 @@ class Code
14
14
 
15
15
  def call(**args)
16
16
  operator = args.fetch(:operator, nil)
17
- arguments = args.fetch(:arguments, [])
17
+ arguments = args.fetch(:arguments, List.new)
18
18
  globals = multi_fetch(args, *GLOBALS)
19
19
 
20
20
  case operator.to_s
21
21
  when "", "call"
22
22
  sig(args) { signature_for_call }
23
- code_call(*arguments, **globals)
23
+ code_call(*arguments.raw, **globals)
24
24
  else
25
25
  super
26
26
  end
@@ -30,48 +30,38 @@ class Code
30
30
  context = Context.new({}, globals[:context])
31
31
 
32
32
  parameters.raw.each.with_index do |parameter, index|
33
- if parameter.regular_splat?
34
- context.code_set(
35
- parameter.code_name,
36
- List.new(arguments.select(&:regular?).map(&:value))
37
- )
38
- elsif parameter.keyword_splat?
39
- context.code_set(
40
- parameter.code_name,
41
- Dictionary.new(
42
- arguments.select(&:keyword?).map(&:name_value).to_h
43
- )
44
- )
45
- elsif parameter.keyword?
46
- argument =
33
+ argument =
34
+ if parameter.keyword?
47
35
  arguments
48
- .detect { |argument| argument.name == parameter.code_name }
49
- &.value
50
- argument = parameter.evaluate(**globals) if argument.nil?
51
- context.code_set(parameter.code_name, argument)
52
- elsif parameter.regular?
53
- argument = arguments[index]&.value
54
- argument = parameter.evaluate(**globals) if argument.nil?
55
- context.code_set(parameter.code_name, argument)
56
- end
36
+ .detect do |dictionary|
37
+ dictionary.code_has_value?(parameter.code_name)
38
+ end
39
+ &.code_get(parameter.code_name)
40
+ else
41
+ arguments[index]
42
+ end
43
+ argument = parameter.evaluate(**globals) if argument.nil?
44
+ context.code_set(parameter.code_name, argument)
57
45
  end
58
46
 
59
47
  body.evaluate(**globals, context:)
60
48
  end
61
49
 
62
50
  def signature_for_call
63
- parameters.raw.inject([]) do |signature, parameter|
64
- if parameter.keyword?
65
- if signature.last.is_a?(::Hash)
66
- signature.last.code_set(parameter.code_name, Object)
67
- signature
51
+ parameters
52
+ .raw
53
+ .inject([]) do |signature, parameter|
54
+ if parameter.keyword?
55
+ if signature.last.is_a?(::Hash)
56
+ signature.last.code_set(parameter.code_name, Object)
57
+ signature
58
+ else
59
+ signature + [{ parameter.code_name => Object }]
60
+ end
68
61
  else
69
- signature + [{ parameter.code_name => Object }]
62
+ signature + [Object]
70
63
  end
71
- else
72
- signature + [Object]
73
- end
74
- end + [Object.repeat]
64
+ end + [Object.repeat]
75
65
  end
76
66
  end
77
67
  end