blockly_interpreter 0.2.0
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 +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
|