blockly_interpreter 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +12 -0
- data/COPYING +8 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +91 -0
- data/Guardfile +22 -0
- data/README.md +72 -0
- data/Rakefile +10 -0
- data/app/assets/javascripts/blockly_interpreter/extension_blocks.js +1 -0
- data/app/assets/javascripts/blockly_interpreter/extension_blocks/dates.js +16 -0
- data/app/assets/javascripts/blockly_interpreter/extension_blocks/debugging.js +17 -0
- data/app/assets/javascripts/blockly_interpreter/extension_blocks/lists.js +45 -0
- data/app/assets/javascripts/blockly_interpreter/extension_blocks/logic.js +274 -0
- data/app/assets/javascripts/blockly_interpreter/extension_blocks/text.js.erb +21 -0
- data/bin/_guard-core +16 -0
- data/bin/console +14 -0
- data/bin/guard +16 -0
- data/bin/rake +16 -0
- data/bin/setup +7 -0
- data/blockly_interpreter.gemspec +33 -0
- data/exe/blocklyi +13 -0
- data/exe/rublocklyc +31 -0
- data/lib/blockly_interpreter.rb +25 -0
- data/lib/blockly_interpreter/block.rb +113 -0
- data/lib/blockly_interpreter/block_library.rb +14 -0
- data/lib/blockly_interpreter/console_interpreter.rb +15 -0
- data/lib/blockly_interpreter/core_blocks.rb +55 -0
- data/lib/blockly_interpreter/core_blocks/arithmetic_operator_block.rb +24 -0
- data/lib/blockly_interpreter/core_blocks/boolean_block.rb +23 -0
- data/lib/blockly_interpreter/core_blocks/comparison_operator_block.rb +50 -0
- data/lib/blockly_interpreter/core_blocks/for_block.rb +68 -0
- data/lib/blockly_interpreter/core_blocks/for_each_block.rb +42 -0
- data/lib/blockly_interpreter/core_blocks/get_variable_block.rb +19 -0
- data/lib/blockly_interpreter/core_blocks/if_block.rb +105 -0
- data/lib/blockly_interpreter/core_blocks/lists_create_empty_block.rb +17 -0
- data/lib/blockly_interpreter/core_blocks/lists_create_with_block.rb +48 -0
- data/lib/blockly_interpreter/core_blocks/lists_get_index_block.rb +95 -0
- data/lib/blockly_interpreter/core_blocks/logic_negate_block.rb +20 -0
- data/lib/blockly_interpreter/core_blocks/logical_operator_block.rb +22 -0
- data/lib/blockly_interpreter/core_blocks/number_block.rb +23 -0
- data/lib/blockly_interpreter/core_blocks/procedure_block.rb +49 -0
- data/lib/blockly_interpreter/core_blocks/procedures_call_no_return_block.rb +21 -0
- data/lib/blockly_interpreter/core_blocks/procedures_call_return_block.rb +21 -0
- data/lib/blockly_interpreter/core_blocks/procedures_def_no_return_block.rb +31 -0
- data/lib/blockly_interpreter/core_blocks/procedures_def_return_block.rb +64 -0
- data/lib/blockly_interpreter/core_blocks/procedures_if_return_block.rb +45 -0
- data/lib/blockly_interpreter/core_blocks/repeat_times_block.rb +33 -0
- data/lib/blockly_interpreter/core_blocks/set_variable_block.rb +24 -0
- data/lib/blockly_interpreter/core_blocks/text_block.rb +23 -0
- data/lib/blockly_interpreter/core_blocks/text_change_case_block.rb +32 -0
- data/lib/blockly_interpreter/core_blocks/text_join_block.rb +50 -0
- data/lib/blockly_interpreter/dsl.rb +291 -0
- data/lib/blockly_interpreter/dsl_generator.rb +147 -0
- data/lib/blockly_interpreter/engine.rb +8 -0
- data/lib/blockly_interpreter/execution_context.rb +72 -0
- data/lib/blockly_interpreter/extension_blocks.rb +25 -0
- data/lib/blockly_interpreter/extension_blocks/date_today_block.rb +17 -0
- data/lib/blockly_interpreter/extension_blocks/debug_message_block.rb +18 -0
- data/lib/blockly_interpreter/extension_blocks/lists_append_block.rb +34 -0
- data/lib/blockly_interpreter/extension_blocks/lists_concat_block.rb +37 -0
- data/lib/blockly_interpreter/extension_blocks/lists_include_operator_block.rb +52 -0
- data/lib/blockly_interpreter/extension_blocks/object_present_block.rb +21 -0
- data/lib/blockly_interpreter/extension_blocks/switch_block.rb +107 -0
- data/lib/blockly_interpreter/extension_blocks/text_inflect_block.rb +27 -0
- data/lib/blockly_interpreter/generic_block_dsl_generator.rb +64 -0
- data/lib/blockly_interpreter/interpreter.rb +25 -0
- data/lib/blockly_interpreter/parser.rb +117 -0
- data/lib/blockly_interpreter/program.rb +51 -0
- data/lib/blockly_interpreter/program_cache.rb +19 -0
- data/lib/blockly_interpreter/test_helper.rb +98 -0
- data/lib/blockly_interpreter/version.rb +3 -0
- metadata +272 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
class BlocklyInterpreter::CoreBlocks::ComparisonOperatorBlock < BlocklyInterpreter::Block
|
2
|
+
self.block_type = :logic_compare
|
3
|
+
|
4
|
+
def value(execution_context)
|
5
|
+
a = values['A'].value(execution_context)
|
6
|
+
b = values['B'].value(execution_context)
|
7
|
+
|
8
|
+
a, b = cast_values(a, b)
|
9
|
+
|
10
|
+
begin
|
11
|
+
case fields['OP']
|
12
|
+
when 'EQ' then a == b
|
13
|
+
when 'NEQ' then a != b
|
14
|
+
when 'LT' then a < b
|
15
|
+
when 'GT' then a > b
|
16
|
+
when 'LTE' then a <= b
|
17
|
+
when 'GTE' then a >= b
|
18
|
+
end
|
19
|
+
rescue
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_dsl
|
25
|
+
BlocklyInterpreter::DSL::BinaryOperationDSLGenerator.new(self, "logic_compare").dsl
|
26
|
+
end
|
27
|
+
|
28
|
+
module DSLMethods
|
29
|
+
def logic_compare(op, a = nil, b = nil, &proc)
|
30
|
+
@blocks << BlocklyInterpreter::DSL::BinaryOperationBlockBuilder.new("logic_compare", op, a, b).tap do |builder|
|
31
|
+
builder.instance_exec(&proc) if block_given?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def cast_values(a, b)
|
39
|
+
return a, b if a.nil? && b.nil?
|
40
|
+
return a, b if a.is_a?(b.class) || b.is_a?(a.class)
|
41
|
+
|
42
|
+
if a.is_a?(Float) || b.is_a?(Float)
|
43
|
+
[a.to_f, b.to_f]
|
44
|
+
elsif a.is_a?(Integer) || b.is_a?(Integer)
|
45
|
+
[a.to_i, b.to_i]
|
46
|
+
else
|
47
|
+
[a, b]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class BlocklyInterpreter::CoreBlocks::ForBlock < BlocklyInterpreter::Block
|
2
|
+
include BlocklyInterpreter::DSLGenerator
|
3
|
+
self.block_type = 'controls_for'
|
4
|
+
|
5
|
+
def execute_statement(execution_context)
|
6
|
+
from = values['FROM'].value(execution_context).to_i
|
7
|
+
to = values['TO'].value(execution_context).to_i
|
8
|
+
by = values['BY'].value(execution_context).to_i
|
9
|
+
|
10
|
+
from.step(by: by, to: to) do |i|
|
11
|
+
execution_context.set_variable(fields['VAR'], i)
|
12
|
+
execution_context.execute(statements['DO'])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_dsl
|
17
|
+
method_call_with_possible_block('controls_for', fields['VAR'].inspect, [
|
18
|
+
method_call_with_block_or_nothing('from', '', values['FROM']),
|
19
|
+
method_call_with_block_or_nothing('to', '', values['TO']),
|
20
|
+
method_call_with_block_or_nothing('by', '', values['BY']),
|
21
|
+
method_call_with_block_or_nothing('action', '', statements['DO'])
|
22
|
+
])
|
23
|
+
end
|
24
|
+
|
25
|
+
module DSLMethods
|
26
|
+
class ForBlockBuilder < BlocklyInterpreter::DSL::BlockBuilder
|
27
|
+
def initialize(block_type, var_name)
|
28
|
+
super(block_type)
|
29
|
+
field :VAR, var_name
|
30
|
+
by(1)
|
31
|
+
end
|
32
|
+
|
33
|
+
def from(val = nil, &proc)
|
34
|
+
proc ||= Proc.new { math_number val }
|
35
|
+
value "FROM", &proc
|
36
|
+
end
|
37
|
+
|
38
|
+
def to(val = nil, &proc)
|
39
|
+
proc ||= Proc.new { math_number val }
|
40
|
+
value "TO", &proc
|
41
|
+
end
|
42
|
+
|
43
|
+
def by(val = nil, &proc)
|
44
|
+
proc ||= Proc.new { math_number val }
|
45
|
+
@by_proc = proc
|
46
|
+
end
|
47
|
+
|
48
|
+
def action(&proc)
|
49
|
+
statement "DO", &proc
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_xml(node)
|
53
|
+
value "BY", &@by_proc
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def controls_for(var_name, from = nil, to = nil, by = nil, &proc)
|
59
|
+
@blocks << BlocklyInterpreter::CoreBlocks::ForBlock::DSLMethods::ForBlockBuilder.new("controls_for", var_name).tap do |builder|
|
60
|
+
builder.from(from) if from
|
61
|
+
builder.to(to) if to
|
62
|
+
builder.by(by) if by
|
63
|
+
|
64
|
+
builder.instance_exec(&proc)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class BlocklyInterpreter::CoreBlocks::ForEachBlock < BlocklyInterpreter::Block
|
2
|
+
include BlocklyInterpreter::DSLGenerator
|
3
|
+
self.block_type = 'controls_forEach'
|
4
|
+
|
5
|
+
def execute_statement(execution_context)
|
6
|
+
list = values['LIST'].value(execution_context)
|
7
|
+
list.each do |item|
|
8
|
+
execution_context.set_variable(fields['VAR'], item)
|
9
|
+
execution_context.execute(statements['DO'])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_dsl
|
14
|
+
method_call_with_possible_block("for_each", fields['VAR'].inspect, [
|
15
|
+
method_call_with_block_or_nothing("list", "", values['LIST']),
|
16
|
+
method_call_with_block_or_nothing("action", "", statements['DO'])
|
17
|
+
].compact)
|
18
|
+
end
|
19
|
+
|
20
|
+
module DSLMethods
|
21
|
+
class ForEachBlockBuilder < BlocklyInterpreter::DSL::BlockBuilder
|
22
|
+
def initialize(block_type, var_name)
|
23
|
+
super(block_type)
|
24
|
+
field :VAR, var_name
|
25
|
+
end
|
26
|
+
|
27
|
+
def list(&proc)
|
28
|
+
value "LIST", &proc
|
29
|
+
end
|
30
|
+
|
31
|
+
def action(&proc)
|
32
|
+
statement "DO", &proc
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def for_each(var_name, &proc)
|
37
|
+
@blocks << BlocklyInterpreter::CoreBlocks::ForEachBlock::DSLMethods::ForEachBlockBuilder.new("controls_forEach", var_name).tap do |builder|
|
38
|
+
builder.instance_exec(&proc)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class BlocklyInterpreter::CoreBlocks::GetVariableBlock < BlocklyInterpreter::Block
|
2
|
+
self.block_type = :variables_get
|
3
|
+
|
4
|
+
def value(execution_context)
|
5
|
+
execution_context.get_variable(fields['VAR'])
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_dsl
|
9
|
+
"variables_get #{fields['VAR'].inspect}"
|
10
|
+
end
|
11
|
+
|
12
|
+
module DSLMethods
|
13
|
+
def variables_get(name)
|
14
|
+
block :variables_get do
|
15
|
+
field :VAR, name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
class BlocklyInterpreter::CoreBlocks::IfBlock < BlocklyInterpreter::Block
|
2
|
+
include BlocklyInterpreter::DSLGenerator
|
3
|
+
self.block_type = :controls_if
|
4
|
+
|
5
|
+
class Conditional
|
6
|
+
attr_reader :predicate_block, :action_block
|
7
|
+
|
8
|
+
def initialize(if_block, num)
|
9
|
+
@predicate_block = if_block.values["IF#{num}"]
|
10
|
+
@action_block = if_block.statements["DO#{num}"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def matches?(execution_context)
|
14
|
+
predicate_block.value(execution_context).present?
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute_statements(execution_context)
|
18
|
+
execution_context.execute(action_block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def predicates
|
23
|
+
@predicates ||= begin
|
24
|
+
(0..elseif_count).map { |num| Conditional.new(self, num) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def elseif_count
|
29
|
+
@elseif_count ||= mutation.try(:[], 'elseif').try(:to_i) || 0
|
30
|
+
end
|
31
|
+
|
32
|
+
def else_block
|
33
|
+
statements['ELSE']
|
34
|
+
end
|
35
|
+
|
36
|
+
def execute_statement(execution_context)
|
37
|
+
match = matching_predicate(execution_context)
|
38
|
+
|
39
|
+
if match
|
40
|
+
match.execute_statements(execution_context)
|
41
|
+
elsif else_block
|
42
|
+
execution_context.execute(else_block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def matching_predicate(execution_context)
|
47
|
+
predicates.detect { |predicate| predicate.matches? execution_context }
|
48
|
+
end
|
49
|
+
|
50
|
+
def predicate_action_dsl(num)
|
51
|
+
[
|
52
|
+
method_call_with_possible_block("predicate", "", values["IF#{num}"]),
|
53
|
+
method_call_with_possible_block("action", "", statements["DO#{num}"])
|
54
|
+
]
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_dsl
|
58
|
+
block_contents = predicate_action_dsl(0) + (1..elseif_count).flat_map do |num|
|
59
|
+
method_call_with_possible_block("elsif_clause", "", predicate_action_dsl(num))
|
60
|
+
end
|
61
|
+
block_contents << method_call_with_block_or_nothing("else_action", "", else_block)
|
62
|
+
|
63
|
+
method_call_with_block_or_nothing("controls_if", "", block_contents.compact)
|
64
|
+
end
|
65
|
+
|
66
|
+
module DSLMethods
|
67
|
+
class IfBlockBuilder < BlocklyInterpreter::DSL::BlockBuilder
|
68
|
+
attr_reader :predicate_number
|
69
|
+
|
70
|
+
def initialize(block_type)
|
71
|
+
super
|
72
|
+
@predicate_number = 0
|
73
|
+
end
|
74
|
+
|
75
|
+
def predicate(&proc)
|
76
|
+
value "IF#{predicate_number}", &proc
|
77
|
+
end
|
78
|
+
|
79
|
+
def action(&proc)
|
80
|
+
statement "DO#{predicate_number}", &proc
|
81
|
+
end
|
82
|
+
|
83
|
+
def elsif_clause(&proc)
|
84
|
+
@predicate_number += 1
|
85
|
+
instance_exec(&proc)
|
86
|
+
end
|
87
|
+
|
88
|
+
def else_action(&proc)
|
89
|
+
mutation_attr "else", 1
|
90
|
+
statement "ELSE", &proc
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_xml(node)
|
94
|
+
mutation_attr("elseif", @predicate_number) if @predicate_number > 0
|
95
|
+
super
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def controls_if(&proc)
|
100
|
+
@blocks << BlocklyInterpreter::CoreBlocks::IfBlock::DSLMethods::IfBlockBuilder.new("controls_if").tap do |builder|
|
101
|
+
builder.instance_exec(&proc)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class BlocklyInterpreter::CoreBlocks::ListsCreateEmptyBlock < BlocklyInterpreter::Block
|
2
|
+
self.block_type = :lists_create_empty
|
3
|
+
|
4
|
+
def value(execution_context)
|
5
|
+
[]
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_dsl
|
9
|
+
"lists_create_empty"
|
10
|
+
end
|
11
|
+
|
12
|
+
module DSLMethods
|
13
|
+
def lists_create_empty
|
14
|
+
block :lists_create_empty
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class BlocklyInterpreter::CoreBlocks::ListsCreateWithBlock < BlocklyInterpreter::Block
|
2
|
+
include BlocklyInterpreter::DSLGenerator
|
3
|
+
self.block_type = :lists_create_with
|
4
|
+
|
5
|
+
def item_count
|
6
|
+
@item_count ||= mutation.try(:[], 'items').try(:to_i) || 0
|
7
|
+
end
|
8
|
+
|
9
|
+
def items
|
10
|
+
@items ||= (0...item_count).map do |i|
|
11
|
+
values["ADD#{i}"]
|
12
|
+
end.compact
|
13
|
+
end
|
14
|
+
|
15
|
+
def value(execution_context)
|
16
|
+
items.map { |item| item.value(execution_context) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_dsl
|
20
|
+
item_dsls = items.map { |item| method_call_with_possible_block("item", "", item) }
|
21
|
+
method_call_with_possible_block("lists_create_with", "", item_dsls)
|
22
|
+
end
|
23
|
+
|
24
|
+
module DSLMethods
|
25
|
+
class ListsCreateWithBlockBuilder < BlocklyInterpreter::DSL::BlockBuilder
|
26
|
+
def initialize(block_type)
|
27
|
+
super
|
28
|
+
@item_number = 0
|
29
|
+
end
|
30
|
+
|
31
|
+
def item(&proc)
|
32
|
+
value("ADD#{@item_number}", &proc)
|
33
|
+
@item_number += 1
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_xml(node)
|
37
|
+
mutation_attr("items", @item_number)
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def lists_create_with(&proc)
|
43
|
+
@blocks << BlocklyInterpreter::CoreBlocks::ListsCreateWithBlock::DSLMethods::ListsCreateWithBlockBuilder.new('lists_create_with').tap do |builder|
|
44
|
+
builder.instance_exec(&proc)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
class BlocklyInterpreter::CoreBlocks::ListsGetIndexBlock < BlocklyInterpreter::Block
|
2
|
+
include BlocklyInterpreter::DSLGenerator
|
3
|
+
self.block_type = :lists_getIndex
|
4
|
+
|
5
|
+
def is_statement?
|
6
|
+
mutation.try(:[], 'statement') == 'true'
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute_statement(execution_context)
|
10
|
+
return unless is_statement?
|
11
|
+
value(execution_context)
|
12
|
+
end
|
13
|
+
|
14
|
+
def value(execution_context)
|
15
|
+
list = values['VALUE'].value(execution_context)
|
16
|
+
return unless list
|
17
|
+
|
18
|
+
list_index = index(execution_context, list)
|
19
|
+
|
20
|
+
value_at_index = list[list_index]
|
21
|
+
list.delete_at(list_index) if %w(GET_REMOVE REMOVE).include?(fields['MODE'])
|
22
|
+
value_at_index
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_dsl
|
26
|
+
case fields['WHERE']
|
27
|
+
when 'FIRST', 'LAST', 'RANDOM'
|
28
|
+
method_call_with_possible_block("lists_get_#{fields['WHERE'].downcase}", "", values['VALUE'])
|
29
|
+
else
|
30
|
+
block_contents = [
|
31
|
+
method_call_with_block_or_nothing('at', '', values['AT']),
|
32
|
+
method_call_with_block_or_nothing('list', '', values['VALUE'])
|
33
|
+
].compact
|
34
|
+
|
35
|
+
method_call_with_possible_block("lists_get_index", "mode: #{fields["MODE"].inspect}, where: #{fields["WHERE"].inspect}", block_contents)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module DSLMethods
|
40
|
+
class ListsGetIndexBlockBuilder < BlocklyInterpreter::DSL::BlockBuilder
|
41
|
+
def at(index = nil, &proc)
|
42
|
+
proc ||= Proc.new { math_number index }
|
43
|
+
@has_at = true
|
44
|
+
value 'AT', &proc
|
45
|
+
end
|
46
|
+
|
47
|
+
def list(&proc)
|
48
|
+
value 'VALUE', &proc
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_xml(node)
|
52
|
+
mutation_attr('statement', (@fields["MODE"] == 'REMOVE').to_s)
|
53
|
+
mutation_attr('at', (!!@has_at).to_s)
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def lists_get_first(&proc)
|
59
|
+
lists_get_index where: 'FIRST' do
|
60
|
+
list &proc
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def lists_get_last(&proc)
|
65
|
+
lists_get_index where: 'LAST' do
|
66
|
+
list &proc
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def lists_get_random(&proc)
|
71
|
+
lists_get_index where: 'RANDOM' do
|
72
|
+
list &proc
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def lists_get_index(mode: 'GET', where: 'FROM_START', &proc)
|
77
|
+
@blocks << BlocklyInterpreter::CoreBlocks::ListsGetIndexBlock::DSLMethods::ListsGetIndexBlockBuilder.new("lists_getIndex").tap do |builder|
|
78
|
+
builder.field 'MODE', mode
|
79
|
+
builder.field 'WHERE', where
|
80
|
+
builder.instance_exec(&proc)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
def index(execution_context, list)
|
87
|
+
case fields['WHERE']
|
88
|
+
when 'FIRST' then 0
|
89
|
+
when 'LAST' then list.size - 1
|
90
|
+
when 'FROM_START' then values['AT'].value(execution_context) - 1
|
91
|
+
when 'FROM_END' then list.size - values['AT'].value(execution_context)
|
92
|
+
when 'RANDOM' then rand(list.size)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|