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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG.md +12 -0
  5. data/COPYING +8 -0
  6. data/Gemfile +4 -0
  7. data/Gemfile.lock +91 -0
  8. data/Guardfile +22 -0
  9. data/README.md +72 -0
  10. data/Rakefile +10 -0
  11. data/app/assets/javascripts/blockly_interpreter/extension_blocks.js +1 -0
  12. data/app/assets/javascripts/blockly_interpreter/extension_blocks/dates.js +16 -0
  13. data/app/assets/javascripts/blockly_interpreter/extension_blocks/debugging.js +17 -0
  14. data/app/assets/javascripts/blockly_interpreter/extension_blocks/lists.js +45 -0
  15. data/app/assets/javascripts/blockly_interpreter/extension_blocks/logic.js +274 -0
  16. data/app/assets/javascripts/blockly_interpreter/extension_blocks/text.js.erb +21 -0
  17. data/bin/_guard-core +16 -0
  18. data/bin/console +14 -0
  19. data/bin/guard +16 -0
  20. data/bin/rake +16 -0
  21. data/bin/setup +7 -0
  22. data/blockly_interpreter.gemspec +33 -0
  23. data/exe/blocklyi +13 -0
  24. data/exe/rublocklyc +31 -0
  25. data/lib/blockly_interpreter.rb +25 -0
  26. data/lib/blockly_interpreter/block.rb +113 -0
  27. data/lib/blockly_interpreter/block_library.rb +14 -0
  28. data/lib/blockly_interpreter/console_interpreter.rb +15 -0
  29. data/lib/blockly_interpreter/core_blocks.rb +55 -0
  30. data/lib/blockly_interpreter/core_blocks/arithmetic_operator_block.rb +24 -0
  31. data/lib/blockly_interpreter/core_blocks/boolean_block.rb +23 -0
  32. data/lib/blockly_interpreter/core_blocks/comparison_operator_block.rb +50 -0
  33. data/lib/blockly_interpreter/core_blocks/for_block.rb +68 -0
  34. data/lib/blockly_interpreter/core_blocks/for_each_block.rb +42 -0
  35. data/lib/blockly_interpreter/core_blocks/get_variable_block.rb +19 -0
  36. data/lib/blockly_interpreter/core_blocks/if_block.rb +105 -0
  37. data/lib/blockly_interpreter/core_blocks/lists_create_empty_block.rb +17 -0
  38. data/lib/blockly_interpreter/core_blocks/lists_create_with_block.rb +48 -0
  39. data/lib/blockly_interpreter/core_blocks/lists_get_index_block.rb +95 -0
  40. data/lib/blockly_interpreter/core_blocks/logic_negate_block.rb +20 -0
  41. data/lib/blockly_interpreter/core_blocks/logical_operator_block.rb +22 -0
  42. data/lib/blockly_interpreter/core_blocks/number_block.rb +23 -0
  43. data/lib/blockly_interpreter/core_blocks/procedure_block.rb +49 -0
  44. data/lib/blockly_interpreter/core_blocks/procedures_call_no_return_block.rb +21 -0
  45. data/lib/blockly_interpreter/core_blocks/procedures_call_return_block.rb +21 -0
  46. data/lib/blockly_interpreter/core_blocks/procedures_def_no_return_block.rb +31 -0
  47. data/lib/blockly_interpreter/core_blocks/procedures_def_return_block.rb +64 -0
  48. data/lib/blockly_interpreter/core_blocks/procedures_if_return_block.rb +45 -0
  49. data/lib/blockly_interpreter/core_blocks/repeat_times_block.rb +33 -0
  50. data/lib/blockly_interpreter/core_blocks/set_variable_block.rb +24 -0
  51. data/lib/blockly_interpreter/core_blocks/text_block.rb +23 -0
  52. data/lib/blockly_interpreter/core_blocks/text_change_case_block.rb +32 -0
  53. data/lib/blockly_interpreter/core_blocks/text_join_block.rb +50 -0
  54. data/lib/blockly_interpreter/dsl.rb +291 -0
  55. data/lib/blockly_interpreter/dsl_generator.rb +147 -0
  56. data/lib/blockly_interpreter/engine.rb +8 -0
  57. data/lib/blockly_interpreter/execution_context.rb +72 -0
  58. data/lib/blockly_interpreter/extension_blocks.rb +25 -0
  59. data/lib/blockly_interpreter/extension_blocks/date_today_block.rb +17 -0
  60. data/lib/blockly_interpreter/extension_blocks/debug_message_block.rb +18 -0
  61. data/lib/blockly_interpreter/extension_blocks/lists_append_block.rb +34 -0
  62. data/lib/blockly_interpreter/extension_blocks/lists_concat_block.rb +37 -0
  63. data/lib/blockly_interpreter/extension_blocks/lists_include_operator_block.rb +52 -0
  64. data/lib/blockly_interpreter/extension_blocks/object_present_block.rb +21 -0
  65. data/lib/blockly_interpreter/extension_blocks/switch_block.rb +107 -0
  66. data/lib/blockly_interpreter/extension_blocks/text_inflect_block.rb +27 -0
  67. data/lib/blockly_interpreter/generic_block_dsl_generator.rb +64 -0
  68. data/lib/blockly_interpreter/interpreter.rb +25 -0
  69. data/lib/blockly_interpreter/parser.rb +117 -0
  70. data/lib/blockly_interpreter/program.rb +51 -0
  71. data/lib/blockly_interpreter/program_cache.rb +19 -0
  72. data/lib/blockly_interpreter/test_helper.rb +98 -0
  73. data/lib/blockly_interpreter/version.rb +3 -0
  74. metadata +272 -0
@@ -0,0 +1,20 @@
1
+ class BlocklyInterpreter::CoreBlocks::LogicNegateBlock < BlocklyInterpreter::Block
2
+ include BlocklyInterpreter::DSLGenerator
3
+ self.block_type = :logic_negate
4
+
5
+ def value(execution_context)
6
+ !values['BOOL'].value(execution_context)
7
+ end
8
+
9
+ def to_dsl
10
+ method_call_with_possible_block("logic_negate", "", values['BOOL'])
11
+ end
12
+
13
+ module DSLMethods
14
+ def logic_negate(&proc)
15
+ block :logic_negate do
16
+ value 'BOOL', &proc
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ class BlocklyInterpreter::CoreBlocks::LogicalOperatorBlock < BlocklyInterpreter::Block
2
+ self.block_type = :logic_operation
3
+
4
+ def value(execution_context)
5
+ case fields['OP']
6
+ when 'AND' then values['A'].value(execution_context) && values['B'].value(execution_context)
7
+ when 'OR' then values['A'].value(execution_context) || values['B'].value(execution_context)
8
+ end
9
+ end
10
+
11
+ def to_dsl
12
+ BlocklyInterpreter::DSL::BinaryOperationDSLGenerator.new(self, "logic_operation").dsl
13
+ end
14
+
15
+ module DSLMethods
16
+ def logic_operation(op, a = nil, b = nil, &proc)
17
+ @blocks << BlocklyInterpreter::DSL::BinaryOperationBlockBuilder.new("logic_operation", op, a, b).tap do |builder|
18
+ builder.instance_exec(&proc) if block_given?
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ class BlocklyInterpreter::CoreBlocks::NumberBlock < BlocklyInterpreter::Block
2
+ self.block_type = :math_number
3
+
4
+ def num
5
+ fields['NUM'].to_i
6
+ end
7
+
8
+ def value(execution_context)
9
+ num
10
+ end
11
+
12
+ def to_dsl
13
+ "math_number #{num.inspect}"
14
+ end
15
+
16
+ module DSLMethods
17
+ def math_number(n)
18
+ block :math_number do
19
+ field :NUM, n.to_s
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,49 @@
1
+ class BlocklyInterpreter::CoreBlocks::ProcedureBlock < BlocklyInterpreter::Block
2
+ include BlocklyInterpreter::DSLGenerator
3
+
4
+ def arg_hash(parameters)
5
+ Hash[arg_names.zip(parameters)]
6
+ end
7
+
8
+ def arg_names
9
+ @arg_names ||= (mutation && mutation.css('> arg').map { |arg| arg['name'] }) || []
10
+ end
11
+
12
+ def arg_values(execution_context)
13
+ (0...arg_names.size).map do |arg_num|
14
+ values["ARG#{arg_num}"].value(execution_context)
15
+ end
16
+ end
17
+
18
+ def args_dsl
19
+ arg_names.each_with_index.map do |arg_name, i|
20
+ method_call_with_possible_block("arg", arg_name.inspect, values["ARG#{i}"])
21
+ end.compact
22
+ end
23
+
24
+ def to_dsl
25
+ method_call_with_possible_block "#{self.class.block_type}", procedure_name.inspect, args_dsl
26
+ end
27
+
28
+ module DSLMethods
29
+ class ProcedureCallBlockBuilder < BlocklyInterpreter::DSL::BlockBuilder
30
+ attr_reader :arg_number
31
+
32
+ def initialize(block_type, procedure_name)
33
+ super(block_type)
34
+
35
+ mutation_attr :name, procedure_name
36
+ @arg_number = 0
37
+ end
38
+
39
+ def arg(name, &proc)
40
+ mutation_child :arg do |child|
41
+ child['name'] = name
42
+ end
43
+
44
+ value "ARG#{arg_number}", &proc
45
+ @arg_number += 1
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,21 @@
1
+ class BlocklyInterpreter::CoreBlocks::ProceduresCallNoReturnBlock < BlocklyInterpreter::CoreBlocks::ProcedureBlock
2
+ self.block_type = :procedures_callnoreturn
3
+
4
+ def procedure_name
5
+ @procedure_name ||= mutation.try!(:[], 'name')
6
+ end
7
+
8
+ def execute_statement(execution_context)
9
+ execution_context.execute_procedure(procedure_name, arg_values(execution_context))
10
+ end
11
+
12
+ module DSLMethods
13
+ def procedures_callnoreturn(name, &proc)
14
+ builder = BlocklyInterpreter::CoreBlocks::ProcedureBlock::DSLMethods::ProcedureCallBlockBuilder.new("procedures_callnoreturn", name)
15
+
16
+ @blocks << builder.tap do |builder|
17
+ builder.instance_exec(&proc) if proc
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ class BlocklyInterpreter::CoreBlocks::ProceduresCallReturnBlock < BlocklyInterpreter::CoreBlocks::ProcedureBlock
2
+ self.block_type = :procedures_callreturn
3
+
4
+ def procedure_name
5
+ @procedure_name ||= mutation.try!(:[], 'name')
6
+ end
7
+
8
+ def value(execution_context)
9
+ execution_context.value_for_procedure(procedure_name, arg_values(execution_context))
10
+ end
11
+
12
+ module DSLMethods
13
+ def procedures_callreturn(name, &proc)
14
+ builder = BlocklyInterpreter::CoreBlocks::ProcedureBlock::DSLMethods::ProcedureCallBlockBuilder.new("procedures_callreturn", name)
15
+
16
+ @blocks << builder.tap do |builder|
17
+ builder.instance_exec(&proc) if proc
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ class BlocklyInterpreter::CoreBlocks::ProceduresDefNoReturnBlock < BlocklyInterpreter::CoreBlocks::ProcedureBlock
2
+ self.block_type = :procedures_defnoreturn
3
+
4
+ def procedure_name
5
+ fields['NAME']
6
+ end
7
+
8
+ def execute_statement(execution_context)
9
+ execution_context.execute(statements['STACK'])
10
+ end
11
+
12
+ def to_dsl
13
+ method_call_with_possible_block("procedures_defnoreturn", ([procedure_name] + arg_names).map(&:inspect).join(", "), statements['STACK'])
14
+ end
15
+
16
+ module DSLMethods
17
+ def procedures_defnoreturn(name, *arg_names, &proc)
18
+ block :procedures_defnoreturn do
19
+ field :NAME, name
20
+
21
+ arg_names.each do |arg_name|
22
+ mutation_child :arg do |child|
23
+ child['name'] = arg_name
24
+ end
25
+ end
26
+
27
+ statement :STACK, &proc
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,64 @@
1
+ class BlocklyInterpreter::CoreBlocks::ProceduresDefReturnBlock < BlocklyInterpreter::CoreBlocks::ProcedureBlock
2
+ self.block_type = :procedures_defreturn
3
+
4
+ def procedure_name
5
+ fields['NAME']
6
+ end
7
+
8
+ def value(execution_context)
9
+ execution_context.execute(statements['STACK'])
10
+
11
+ if execution_context.terminated
12
+ execution_context.early_return_value
13
+ else
14
+ values['RETURN'].value(execution_context)
15
+ end
16
+ end
17
+
18
+ def to_dsl
19
+ block_contents = [
20
+ method_call_with_block_or_nothing("body", "", statements['STACK']),
21
+ method_call_with_block_or_nothing("return_value", "", values['RETURN'])
22
+ ]
23
+
24
+ method_call_with_possible_block "#{self.class.block_type}", ([procedure_name] + arg_names).map(&:inspect).join(", "), block_contents
25
+ end
26
+
27
+ module DSLMethods
28
+ class ProceduresDefReturnBlockBuilder < BlocklyInterpreter::DSL::BlockBuilder
29
+ attr_reader :stack
30
+
31
+ def initialize(block_type, procedure_name, arg_names)
32
+ super(block_type)
33
+
34
+ field :NAME, procedure_name
35
+
36
+ arg_names.each do |arg_name|
37
+ mutation_child :arg do |child|
38
+ child['name'] = arg_name
39
+ end
40
+ end
41
+ end
42
+
43
+ def body(&proc)
44
+ statement :STACK, &proc
45
+ end
46
+
47
+ def return_value(&proc)
48
+ value :RETURN, &proc
49
+ end
50
+ end
51
+
52
+ def procedures_defreturn(name, *arg_names, &proc)
53
+ builder = BlocklyInterpreter::CoreBlocks::ProceduresDefReturnBlock::DSLMethods::ProceduresDefReturnBlockBuilder.new(
54
+ "procedures_defreturn",
55
+ name,
56
+ arg_names
57
+ )
58
+
59
+ @blocks << builder.tap do |builder|
60
+ builder.instance_exec(&proc) if proc
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,45 @@
1
+ class BlocklyInterpreter::CoreBlocks::ProceduresIfReturnBlock < BlocklyInterpreter::Block
2
+ include BlocklyInterpreter::DSLGenerator
3
+
4
+ self.block_type = :procedures_ifreturn
5
+
6
+ def execute_statement(execution_context)
7
+ if values['CONDITION'].value(execution_context).present?
8
+ return_value = values['VALUE'].value(execution_context) if values['VALUE']
9
+ execution_context.early_return!(return_value)
10
+ end
11
+ end
12
+
13
+ def to_dsl
14
+ block_contents = [method_call_with_possible_block("condition", "", values['CONDITION'])]
15
+ block_contents << method_call_with_block_or_nothing("return_value", "", values['VALUE'])
16
+
17
+ method_call_with_possible_block("procedures_ifreturn", "", block_contents.compact)
18
+ end
19
+
20
+ module DSLMethods
21
+ class ProceduresIfReturnBlockBuilder < BlocklyInterpreter::DSL::BlockBuilder
22
+ def initialize(block_type)
23
+ super
24
+ mutation_attr :value, 0
25
+ end
26
+
27
+ def condition(&proc)
28
+ value :CONDITION, &proc
29
+ end
30
+
31
+ def return_value(&proc)
32
+ mutation_attr :value, 1
33
+ value :VALUE, &proc
34
+ end
35
+ end
36
+
37
+ def procedures_ifreturn(&proc)
38
+ builder = BlocklyInterpreter::CoreBlocks::ProceduresIfReturnBlock::DSLMethods::ProceduresIfReturnBlockBuilder.new("procedures_ifreturn")
39
+
40
+ @blocks << builder.tap do |builder|
41
+ builder.instance_exec(&proc) if proc
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,33 @@
1
+ class BlocklyInterpreter::CoreBlocks::RepeatTimesBlock < BlocklyInterpreter::Block
2
+ self.block_type = :controls_repeat_ext
3
+
4
+ def execute_statement(execution_context)
5
+ n = values['TIMES'].value(execution_context).to_i
6
+ n.times { execution_context.execute(statements['DO']) }
7
+ end
8
+
9
+ module DSLMethods
10
+ class RepeatBlockBuilder < BlocklyInterpreter::DSL::BlockBuilder
11
+ def times(&proc)
12
+ value "TIMES", &proc
13
+ end
14
+
15
+ def action(&proc)
16
+ statement "DO", &proc
17
+ end
18
+ end
19
+
20
+ def controls_repeat_ext(&proc)
21
+ @blocks << BlocklyInterpreter::CoreBlocks::RepeatTimesBlock::DSLMethods::RepeatBlockBuilder.new("controls_repeat_ext").tap do |builder|
22
+ builder.instance_exec(&proc)
23
+ end
24
+ end
25
+
26
+ def repeat_times(n, &proc)
27
+ controls_repeat_ext do
28
+ times { math_number n }
29
+ action &proc
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,24 @@
1
+ class BlocklyInterpreter::CoreBlocks::SetVariableBlock < BlocklyInterpreter::Block
2
+ include BlocklyInterpreter::DSLGenerator
3
+
4
+ self.block_type = :variables_set
5
+
6
+ def execute_statement(execution_context)
7
+ execution_context.set_variable(fields['VAR'], values['VALUE'].value(execution_context))
8
+ end
9
+
10
+ def to_dsl
11
+ method_call_with_possible_block("variables_set", fields['VAR'].inspect, values['VALUE'])
12
+ end
13
+
14
+ module DSLMethods
15
+ def variables_set(name, &proc)
16
+ block :variables_set do
17
+ field :VAR, name
18
+ value :VALUE do
19
+ instance_exec &proc
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ class BlocklyInterpreter::CoreBlocks::TextBlock < BlocklyInterpreter::Block
2
+ self.block_type = :text
3
+
4
+ def text
5
+ fields['TEXT']
6
+ end
7
+
8
+ def value(execution_context)
9
+ text
10
+ end
11
+
12
+ def to_dsl
13
+ "text #{text.inspect}"
14
+ end
15
+
16
+ module DSLMethods
17
+ def text(content)
18
+ block :text do
19
+ field :TEXT, content
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ class BlocklyInterpreter::CoreBlocks::TextChangeCaseBlock < BlocklyInterpreter::Block
2
+ include BlocklyInterpreter::DSLGenerator
3
+ self.block_type = :text_changeCase
4
+
5
+ def destination_case
6
+ fields['CASE']
7
+ end
8
+
9
+ def value(execution_context)
10
+ text = values['TEXT'].value(execution_context).to_s
11
+
12
+ case destination_case
13
+ when 'UPPERCASE' then text.upcase
14
+ when 'LOWERCASE' then text.downcase
15
+ when 'TITLECASE' then text.titleize
16
+ else raise "Unknown case: #{destination_case.inspect}"
17
+ end
18
+ end
19
+
20
+ def to_dsl
21
+ method_call_with_possible_block "text_change_case", destination_case.inspect, values['TEXT']
22
+ end
23
+
24
+ module DSLMethods
25
+ def text_change_case(destination_case, &proc)
26
+ block :text_changeCase do
27
+ field :CASE, destination_case
28
+ value :TEXT, &proc
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,50 @@
1
+ class BlocklyInterpreter::CoreBlocks::TextJoinBlock < BlocklyInterpreter::Block
2
+ include BlocklyInterpreter::DSLGenerator
3
+ self.block_type = :text_join
4
+
5
+ def item_count
6
+ @item_count ||= mutation.try(:[], 'items').try(:to_i) || 0
7
+ end
8
+
9
+ def value(execution_context)
10
+ (0...item_count).map { |i| values["ADD#{i}"].value(execution_context) }.join
11
+ end
12
+
13
+ def to_dsl
14
+ item_dsls = (0...item_count).map do |i|
15
+ method_call_with_block_or_nothing("item", "", values["ADD#{i}"])
16
+ end.compact
17
+
18
+ method_call_with_possible_block("text_join", "", item_dsls)
19
+ end
20
+
21
+ module DSLMethods
22
+ class TextJoinBlockBuilder < BlocklyInterpreter::DSL::BlockBuilder
23
+ def initialize(block_type)
24
+ super
25
+ @item_number = 0
26
+ end
27
+
28
+ def item(string = nil, &proc)
29
+ proc ||= Proc.new { text string }
30
+ value("ADD#{@item_number}", &proc)
31
+ @item_number += 1
32
+ end
33
+
34
+ def to_xml(node)
35
+ mutation_attr("items", @item_number)
36
+ super
37
+ end
38
+ end
39
+
40
+ def text_join(*strings, &proc)
41
+ @blocks << BlocklyInterpreter::CoreBlocks::TextJoinBlock::DSLMethods::TextJoinBlockBuilder.new('text_join').tap do |builder|
42
+ strings.each do |string|
43
+ builder.item string
44
+ end
45
+
46
+ builder.instance_exec(&proc) if proc
47
+ end
48
+ end
49
+ end
50
+ end