code-ruby 1.9.10 → 1.9.11
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/Gemfile.lock +1 -1
- data/VERSION +1 -1
- data/lib/code/error.rb +9 -7
- data/lib/code/format.rb +3 -1
- data/lib/code/node/code.rb +26 -2
- data/lib/code/node/right_operation.rb +28 -14
- data/lib/code/node/statement.rb +7 -1
- data/lib/code/node/while.rb +50 -18
- data/lib/code/object/function.rb +2 -0
- data/lib/code/object/global.rb +9 -0
- data/lib/code.rb +1 -0
- data/spec/code_spec.rb +15 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 192c4afdcb1d4a87d146ef92fe6241fb510b61b564843c62d07420a2f53caa44
|
|
4
|
+
data.tar.gz: b081b22d57f5582fea6de13e5c24f9c1f33b86a28cd1da97f37449cad40dc5f9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ae5c1a1146088cea5f5c0bf7c871bfeb1f89f863960eb4be68944ce273498f578abba6c2b7fcf990ef4208c9cb936fa8a7f9c8d2bb5c7dcb7490497cb69cfdae
|
|
7
|
+
data.tar.gz: cab243aa74f149e2a4e7b7c3523a14aa74e42bf55b9ca11e751682b359377447ac5c3ce5da5b3f29c4c4124d793fad6a2d126a6721979900e443e887f2a4f17d
|
data/Gemfile.lock
CHANGED
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.9.
|
|
1
|
+
1.9.11
|
data/lib/code/error.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
class Code
|
|
4
4
|
class Error < StandardError
|
|
5
|
-
class
|
|
5
|
+
class ControlFlow < Error
|
|
6
6
|
attr_reader :code_value
|
|
7
7
|
|
|
8
8
|
def initialize(value = nil)
|
|
@@ -10,12 +10,14 @@ class Code
|
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
class
|
|
14
|
-
attr_reader :code_value
|
|
13
|
+
class Break < ControlFlow; end
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
class Next < ControlFlow; end
|
|
16
|
+
|
|
17
|
+
class Continue < Next; end
|
|
18
|
+
|
|
19
|
+
class Return < ControlFlow; end
|
|
20
|
+
|
|
21
|
+
class Retry < ControlFlow; end
|
|
20
22
|
end
|
|
21
23
|
end
|
data/lib/code/format.rb
CHANGED
|
@@ -318,7 +318,7 @@ class Code
|
|
|
318
318
|
|
|
319
319
|
def format_call(call, indent:)
|
|
320
320
|
name = call[:name]
|
|
321
|
-
raw_arguments =
|
|
321
|
+
raw_arguments = call[:arguments].presence || []
|
|
322
322
|
arguments = raw_arguments.map { |arg| format_call_argument(arg) }
|
|
323
323
|
statement =
|
|
324
324
|
if arguments.empty?
|
|
@@ -336,6 +336,8 @@ class Code
|
|
|
336
336
|
end
|
|
337
337
|
|
|
338
338
|
def format_call_argument(argument)
|
|
339
|
+
return format_code_inline(Array(argument), indent: 0) unless argument.is_a?(Hash)
|
|
340
|
+
|
|
339
341
|
value = format_code_inline(argument[:value], indent: 0)
|
|
340
342
|
return value unless argument.key?(:name)
|
|
341
343
|
|
data/lib/code/node/code.rb
CHANGED
|
@@ -11,13 +11,37 @@ class Code
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def evaluate(**args)
|
|
14
|
+
global_control_flow_root = args.fetch(:global_control_flow_root, false)
|
|
15
|
+
control_flow_scope = args.fetch(:control_flow_scope, nil)
|
|
16
|
+
statement_args =
|
|
17
|
+
if global_control_flow_root
|
|
18
|
+
args.merge(global_control_flow_root: false)
|
|
19
|
+
else
|
|
20
|
+
args
|
|
21
|
+
end
|
|
14
22
|
last = Object::Nothing.new
|
|
15
23
|
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
begin
|
|
25
|
+
(@statements || []).each do |statement|
|
|
26
|
+
last = statement.evaluate(**statement_args, object: Object::Global.new)
|
|
27
|
+
end
|
|
28
|
+
rescue Error::Retry
|
|
29
|
+
retry if control_flow_scope == :group
|
|
30
|
+
|
|
31
|
+
raise
|
|
32
|
+
rescue Error::Break => e
|
|
33
|
+
return e.code_value if control_flow_scope == :group
|
|
34
|
+
|
|
35
|
+
raise
|
|
18
36
|
end
|
|
19
37
|
|
|
20
38
|
last
|
|
39
|
+
rescue Error::ControlFlow => e
|
|
40
|
+
raise unless global_control_flow_root
|
|
41
|
+
|
|
42
|
+
retry if e.is_a?(Error::Retry)
|
|
43
|
+
|
|
44
|
+
e.code_value
|
|
21
45
|
end
|
|
22
46
|
|
|
23
47
|
def resolve(**args)
|
|
@@ -28,21 +28,9 @@ class Code
|
|
|
28
28
|
@left.evaluate(**args)
|
|
29
29
|
end
|
|
30
30
|
when "while"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
left = @left&.evaluate(**args) || Object::Nothing.new while (
|
|
34
|
-
@right&.evaluate(**args) || Object::Nothing.new
|
|
35
|
-
).truthy?
|
|
36
|
-
|
|
37
|
-
left
|
|
31
|
+
evaluate_conditional_loop(condition_truthy: true, **args)
|
|
38
32
|
when "until"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
left = @left&.evaluate(**args) || Object::Nothing.new while (
|
|
42
|
-
@right&.evaluate(**args) || Object::Nothing.new
|
|
43
|
-
).falsy?
|
|
44
|
-
|
|
45
|
-
left
|
|
33
|
+
evaluate_conditional_loop(condition_truthy: false, **args)
|
|
46
34
|
when "rescue"
|
|
47
35
|
begin
|
|
48
36
|
@left&.evaluate(**args) || Object::Nothing.new
|
|
@@ -69,6 +57,32 @@ class Code
|
|
|
69
57
|
)
|
|
70
58
|
end
|
|
71
59
|
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def evaluate_conditional_loop(condition_truthy:, **args)
|
|
64
|
+
left = Object::Nothing.new
|
|
65
|
+
|
|
66
|
+
while loop_condition_truthy?(condition_truthy, **args)
|
|
67
|
+
begin
|
|
68
|
+
left = @left&.evaluate(**args) || Object::Nothing.new
|
|
69
|
+
rescue Error::Next, Error::Continue => e
|
|
70
|
+
left = e.code_value
|
|
71
|
+
next
|
|
72
|
+
rescue Error::Retry
|
|
73
|
+
retry
|
|
74
|
+
rescue Error::Break => e
|
|
75
|
+
return e.code_value
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
left
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def loop_condition_truthy?(condition_truthy, **args)
|
|
83
|
+
condition = (@right&.evaluate(**args) || Object::Nothing.new).truthy?
|
|
84
|
+
condition_truthy ? condition : !condition
|
|
85
|
+
end
|
|
72
86
|
end
|
|
73
87
|
end
|
|
74
88
|
end
|
data/lib/code/node/statement.rb
CHANGED
|
@@ -11,6 +11,7 @@ class Code
|
|
|
11
11
|
elsif parsed.key?(:boolean)
|
|
12
12
|
@statement = Boolean.new(parsed.delete(:boolean))
|
|
13
13
|
elsif parsed.key?(:group)
|
|
14
|
+
@control_flow_scope = :group
|
|
14
15
|
@statement = Code.new(parsed.delete(:group))
|
|
15
16
|
elsif parsed.key?(:call)
|
|
16
17
|
@statement = Call.new(parsed.delete(:call))
|
|
@@ -56,7 +57,12 @@ class Code
|
|
|
56
57
|
end
|
|
57
58
|
|
|
58
59
|
def evaluate(**args)
|
|
59
|
-
@
|
|
60
|
+
if @control_flow_scope == :group
|
|
61
|
+
@statement&.evaluate(**args, control_flow_scope: @control_flow_scope) ||
|
|
62
|
+
Object::Nothing.new
|
|
63
|
+
else
|
|
64
|
+
@statement&.evaluate(**args) || Object::Nothing.new
|
|
65
|
+
end
|
|
60
66
|
end
|
|
61
67
|
|
|
62
68
|
def resolve(**args)
|
data/lib/code/node/while.rb
CHANGED
|
@@ -20,29 +20,61 @@ class Code
|
|
|
20
20
|
def evaluate(**args)
|
|
21
21
|
case @operator
|
|
22
22
|
when WHILE_KEYWORD
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
last = @body&.evaluate(**args) || Object::Nothing.new while (
|
|
26
|
-
@statement&.evaluate(**args) || Object::Nothing.new
|
|
27
|
-
).truthy?
|
|
28
|
-
|
|
29
|
-
last
|
|
23
|
+
evaluate_conditional_loop(condition_truthy: true, **args)
|
|
30
24
|
when UNTIL_KEYWORD
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
last = @body&.evaluate(**args) || Object::Nothing.new while (
|
|
34
|
-
@statement&.evaluate(**args) || Object::Nothing.new
|
|
35
|
-
).falsy?
|
|
36
|
-
|
|
37
|
-
last
|
|
25
|
+
evaluate_conditional_loop(condition_truthy: false, **args)
|
|
38
26
|
when LOOP_KEYWORD
|
|
39
|
-
|
|
40
|
-
Object::Nothing.new
|
|
27
|
+
evaluate_infinite_loop(**args)
|
|
41
28
|
else
|
|
42
29
|
Object::Nothing.new
|
|
43
30
|
end
|
|
44
|
-
|
|
45
|
-
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def evaluate_conditional_loop(condition_truthy:, **args)
|
|
36
|
+
last = Object::Nothing.new
|
|
37
|
+
|
|
38
|
+
while loop_condition_truthy?(condition_truthy, **args)
|
|
39
|
+
begin
|
|
40
|
+
last = @body&.evaluate(**args) || Object::Nothing.new
|
|
41
|
+
rescue Error::Next, Error::Continue => e
|
|
42
|
+
last = e.code_value
|
|
43
|
+
next
|
|
44
|
+
rescue Error::Retry
|
|
45
|
+
retry
|
|
46
|
+
rescue Error::Break => e
|
|
47
|
+
return e.code_value
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
last
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def evaluate_infinite_loop(**args)
|
|
55
|
+
last = Object::Nothing.new
|
|
56
|
+
|
|
57
|
+
loop do
|
|
58
|
+
begin
|
|
59
|
+
last = @body&.evaluate(**args) || Object::Nothing.new
|
|
60
|
+
rescue Error::Next, Error::Continue => e
|
|
61
|
+
last = e.code_value
|
|
62
|
+
next
|
|
63
|
+
rescue Error::Retry
|
|
64
|
+
retry
|
|
65
|
+
rescue Error::Break => e
|
|
66
|
+
return e.code_value
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
last
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def loop_condition_truthy?(condition_truthy, **args)
|
|
74
|
+
condition =
|
|
75
|
+
(@statement&.evaluate(**args) || Object::Nothing.new).truthy?
|
|
76
|
+
|
|
77
|
+
condition_truthy ? condition : !condition
|
|
46
78
|
end
|
|
47
79
|
end
|
|
48
80
|
end
|
data/lib/code/object/function.rb
CHANGED
data/lib/code/object/global.rb
CHANGED
|
@@ -23,9 +23,18 @@ class Code
|
|
|
23
23
|
when "break"
|
|
24
24
|
sig(args) { Object.repeat }
|
|
25
25
|
raise Error::Break, code_value || Nothing.new
|
|
26
|
+
when "continue"
|
|
27
|
+
sig(args) { Object.repeat }
|
|
28
|
+
raise Error::Continue, code_value || Nothing.new
|
|
26
29
|
when "next"
|
|
27
30
|
sig(args) { Object.repeat }
|
|
28
31
|
raise Error::Next, code_value || Nothing.new
|
|
32
|
+
when "redo", "retry"
|
|
33
|
+
sig(args) { Object.repeat }
|
|
34
|
+
raise Error::Retry, code_value || Nothing.new
|
|
35
|
+
when "return"
|
|
36
|
+
sig(args) { Object.repeat }
|
|
37
|
+
raise Error::Return, code_value || Nothing.new
|
|
29
38
|
when "Class"
|
|
30
39
|
sig(args) { Object.repeat }
|
|
31
40
|
if code_arguments.any?
|
data/lib/code.rb
CHANGED
data/spec/code_spec.rb
CHANGED
|
@@ -313,6 +313,7 @@ RSpec.describe Code do
|
|
|
313
313
|
["[1, 2, 3]", "[1, 2, 3]"],
|
|
314
314
|
["[1, 2, 3].include?(2)", "true"],
|
|
315
315
|
["[1, 2, 3].include?(4)", "false"],
|
|
316
|
+
["[1, 2, 3].map { |i| continue(0) if i.even? i ** 2}", "[1, 0, 9]"],
|
|
316
317
|
["[1, 2, 3].map { |i| next if i == 2 i ** 2}", "[1, nothing, 9]"],
|
|
317
318
|
["[1, 2, 3].map { |i| next(0) if i.even? i ** 2}", "[1, 0, 9]"],
|
|
318
319
|
["[1, 2, 3].select { |n| n.even? }", "[2]"],
|
|
@@ -328,9 +329,17 @@ RSpec.describe Code do
|
|
|
328
329
|
["[]", "[]"],
|
|
329
330
|
["\r\n", "nothing"],
|
|
330
331
|
["a = 0 [1, 2, 3].each { |i| next if i == 2 a += i } a", "4"],
|
|
332
|
+
["a = 0\nb = 0\nwhile a < 4\n a += 1\n continue if a == 2\n b += a\nend\nb", "8"],
|
|
331
333
|
["a = 0 loop a += 1 break end a", "1"],
|
|
334
|
+
["a = 1\nbegin\n a += 1\n break if a > 3\n retry\nend\na", "4"],
|
|
335
|
+
["x = loop break(42) end x", "42"],
|
|
336
|
+
["a = 0 a += 1 retry if a < 3 a", "3"],
|
|
332
337
|
["a = 0\nuntil a > 10 a += 1 end a", "11"],
|
|
333
338
|
["a = 0\nwhile a < 10 a += 1 end a", "10"],
|
|
339
|
+
[
|
|
340
|
+
"a = 0\nretried = false\nwhile a < 2\n a += 1\n retry if a == 1 && !retried && (retried = true)\nend\na",
|
|
341
|
+
"2"
|
|
342
|
+
],
|
|
334
343
|
["a = 1 3.times { a += 1 } a", "4"],
|
|
335
344
|
["a = 1 a *= 2 a", "2"],
|
|
336
345
|
["a = 1 a += 1 a", "2"],
|
|
@@ -360,9 +369,15 @@ RSpec.describe Code do
|
|
|
360
369
|
["if false 1 elsif false 2", "nothing"],
|
|
361
370
|
["if false 1 elsif true 2", "2"],
|
|
362
371
|
["if false 1", "nothing"],
|
|
372
|
+
["break(5)", "5"],
|
|
373
|
+
["continue(6)", "6"],
|
|
363
374
|
["if true 1", "1"],
|
|
375
|
+
["next(7)", "7"],
|
|
364
376
|
["not not false", "false"],
|
|
365
377
|
["not true", "false"],
|
|
378
|
+
["retry(8)", "8"],
|
|
379
|
+
["return(9)", "9"],
|
|
380
|
+
["f = () => { return(3) 4 } f()", "3"],
|
|
366
381
|
["a = 1 orirginal = 2 orirginal", "2"],
|
|
367
382
|
["a = 1 andy = 2 andy", "2"],
|
|
368
383
|
["ifonly = 1 ifonly", "1"],
|