blockly_interpreter 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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,21 @@
1
+ 'use strict';
2
+
3
+ goog.provide('BlocklyInterpreter.ExtensionBlocks.text');
4
+ goog.require('Blockly.Blocks');
5
+
6
+ Blockly.Blocks['text_inflect'] = {
7
+ init: function() {
8
+ var inflections = <%= BlocklyInterpreter::ExtensionBlocks::TextInflectBlock::INFLECTIONS.to_json %>;
9
+ var dropdownOptions = _.map(inflections, function (inflection) {
10
+ return [inflection, inflection]
11
+ });
12
+
13
+ this.appendValueInput('TEXT')
14
+ .appendField(new Blockly.FieldDropdown(dropdownOptions), 'OP')
15
+ .appendField('text')
16
+ .setCheck('String');
17
+
18
+ this.setOutput(true, 'String');
19
+ this.setColour(Blockly.Blocks.texts.HUE);
20
+ }
21
+ }
data/bin/_guard-core ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application '_guard-core' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('guard', '_guard-core')
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "blockly_interpreter"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/guard ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'guard' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('guard', 'guard')
data/bin/rake ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rake', 'rake')
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'blockly_interpreter/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "blockly_interpreter"
8
+ spec.version = BlocklyInterpreter::VERSION
9
+ spec.authors = ["Nat Budin"]
10
+ spec.email = ["natbudin@gmail.com"]
11
+
12
+ spec.summary = %q{An interpreter for Blockly programs}
13
+ spec.description = %q{Blockly is a library from Google for building visual programming editors. This gem is an interpreter for Blockly programs in Ruby.}
14
+ spec.homepage = "https://github.com/patientslikeme/blockly_interpreter"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "nokogiri"
22
+ spec.add_dependency "activesupport"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.10"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "minitest"
27
+ spec.add_development_dependency "minitest-reporters"
28
+ spec.add_development_dependency "timecop"
29
+ spec.add_development_dependency "pry"
30
+ spec.add_development_dependency "guard"
31
+ spec.add_development_dependency "guard-minitest"
32
+ spec.add_development_dependency "terminal-notifier-guard"
33
+ end
data/exe/blocklyi ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "blockly_interpreter"
5
+
6
+ program_name = ARGV[0]
7
+ unless program_name
8
+ puts "Please specify a program name to run."
9
+ exit!
10
+ end
11
+
12
+ xml = File.open(program_name).read
13
+ BlocklyInterpreter::ConsoleInterpreter.new(xml).execute
data/exe/rublocklyc ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "blockly_interpreter"
5
+
6
+ program_name = ARGV[0]
7
+ unless program_name
8
+ puts "Please specify a program name to compile."
9
+ exit!
10
+ end
11
+
12
+ module ConsoleDSL
13
+ def console_print(content = nil, &proc)
14
+ block :console_print do
15
+ value :VALUE do
16
+ if block_given?
17
+ instance_exec &proc
18
+ else
19
+ text content
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ BlocklyInterpreter::DSL::BlockContext.send :include, ConsoleDSL
26
+
27
+ xml = BlocklyInterpreter::DSL.build_xml do
28
+ binding.eval(File.open(program_name).read, program_name)
29
+ end
30
+
31
+ STDOUT.write xml
@@ -0,0 +1,25 @@
1
+ require "blockly_interpreter/version"
2
+ require "active_support/dependencies/autoload"
3
+ require "active_support/core_ext"
4
+
5
+ if defined?(::Rails::Engine)
6
+ # Rails autoloading will take care of the requires for us, and explicitly doing it will
7
+ # break it.
8
+ require 'blockly_interpreter/engine'
9
+ else
10
+ module BlocklyInterpreter
11
+ extend ActiveSupport::Autoload
12
+
13
+ autoload :Block
14
+ autoload :BlockLibrary
15
+ autoload :CoreBlocks
16
+ autoload :DSL
17
+ autoload :DSLGenerator
18
+ autoload :ExecutionContext
19
+ autoload :GenericBlockDSLGenerator
20
+ autoload :Interpreter
21
+ autoload :Parser
22
+ autoload :ProgramCache
23
+ autoload :Program
24
+ end
25
+ end
@@ -0,0 +1,113 @@
1
+ require 'nokogiri'
2
+
3
+ class BlocklyInterpreter::Block
4
+ class << self
5
+ attr_accessor :block_type
6
+ end
7
+
8
+ attr_reader :block_type, :values, :statements, :fields, :next_block, :mutation, :comment, :comment_pinned, :is_shadow, :x, :y
9
+ alias_method :is_shadow?, :is_shadow
10
+
11
+ def initialize(block_type, fields, values, statements, next_block, mutation, comment, comment_pinned, is_shadow, x, y)
12
+ @block_type = block_type
13
+ @fields = fields
14
+ @values = values
15
+ @statements = statements
16
+ @next_block = next_block
17
+ @mutation = mutation
18
+ @comment = comment
19
+ @comment_pinned = comment_pinned
20
+ @is_shadow = is_shadow
21
+ @x = x
22
+ @y = y
23
+ end
24
+
25
+ def execute_statement(execution_context)
26
+ end
27
+
28
+ def value(execution_context)
29
+ nil
30
+ end
31
+
32
+ def each_block(iterate_subblocks = true)
33
+ return to_enum(:each_block, iterate_subblocks) unless block_given?
34
+
35
+ yield self
36
+
37
+ if iterate_subblocks
38
+ statements.each do |key, statement|
39
+ statement.each_block(iterate_subblocks) do |block|
40
+ yield block
41
+ end
42
+ end
43
+ end
44
+
45
+ if next_block
46
+ next_block.each_block(iterate_subblocks) do |block|
47
+ yield block
48
+ end
49
+ end
50
+ end
51
+
52
+ def to_dsl
53
+ BlocklyInterpreter::GenericBlockDSLGenerator.new(self).dsl
54
+ end
55
+
56
+ def has_comment?
57
+ comment.present?
58
+ end
59
+
60
+ def has_position?
61
+ x || y
62
+ end
63
+
64
+ def to_xml_element(document)
65
+ tag_name = is_shadow ? 'shadow' : 'block'
66
+
67
+ Nokogiri::XML::Element.new(tag_name, document).tap do |node|
68
+ node['type'] = block_type
69
+ node['x'] = x if x
70
+ node['y'] = y if y
71
+ node.add_child(mutation.dup) if mutation
72
+
73
+ if comment
74
+ comment_node = Nokogiri::XML::Element.new('comment', document)
75
+ comment_node['pinned'] = 'true' if comment_pinned
76
+ node.add_child comment_node
77
+ end
78
+
79
+ fields.each do |name, value|
80
+ field_node = Nokogiri::XML::Element.new('field', document)
81
+ field_node['name'] = name
82
+ field_node.add_child Nokogiri::XML::Text.new(value, document)
83
+ node.add_child field_node
84
+ end
85
+
86
+ values.each do |name, value|
87
+ value_node = Nokogiri::XML::Element.new('value', document)
88
+ value_node['name'] = name
89
+ value_node.add_child value.to_xml_element(document)
90
+ node.add_child value_node
91
+ end
92
+
93
+ statements.each do |name, value|
94
+ statement_node = Nokogiri::XML::Element.new('statement', document)
95
+ statement_node['name'] = name
96
+ statement_node.add_child value.to_xml_element(document)
97
+ node.add_child statement_node
98
+ end
99
+
100
+ if next_block
101
+ next_block_node = Nokogiri::XML::Element.new('next_block', document)
102
+ next_block_node.add_child next_block.to_xml_element(document)
103
+ node.add_child next_block_node
104
+ end
105
+ end
106
+ end
107
+
108
+ def to_xml(options = {})
109
+ doc = Nokogiri::XML::Document.new
110
+ element = to_xml_element(doc)
111
+ element.to_xml(options = {})
112
+ end
113
+ end
@@ -0,0 +1,14 @@
1
+ module BlocklyInterpreter::BlockLibrary
2
+ attr_accessor :block_classes
3
+
4
+ def block_classes
5
+ @block_classes ||= []
6
+ end
7
+
8
+ def register!(parser_class = BlocklyInterpreter::Parser, block_context_class = BlocklyInterpreter::DSL::BlockContext)
9
+ block_classes.each do |block_class|
10
+ parser_class.register_block_class block_class
11
+ block_context_class.register_block_class block_class
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ class BlocklyInterpreter::ConsoleInterpreter < BlocklyInterpreter::Interpreter
2
+ class ConsolePrintBlock < BlocklyInterpreter::Block
3
+ def execute_statement(execution_context)
4
+ puts values['VALUE'].value(execution_context)
5
+ end
6
+ end
7
+
8
+ def block_class_for_element(element)
9
+ case element['type']
10
+ when 'console_print' then ConsolePrintBlock
11
+ else
12
+ super(element)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,55 @@
1
+ module BlocklyInterpreter::CoreBlocks
2
+ extend ActiveSupport::Autoload
3
+ extend BlocklyInterpreter::BlockLibrary
4
+
5
+ autoload :ArithmeticOperatorBlock
6
+ autoload :BooleanBlock
7
+ autoload :ComparisonOperatorBlock
8
+ autoload :ForBlock
9
+ autoload :ForEachBlock
10
+ autoload :GetVariableBlock
11
+ autoload :IfBlock
12
+ autoload :ListsCreateEmptyBlock
13
+ autoload :ListsCreateWithBlock
14
+ autoload :ListsGetIndexBlock
15
+ autoload :LogicNegateBlock
16
+ autoload :LogicalOperatorBlock
17
+ autoload :NumberBlock
18
+ autoload :ProcedureBlock
19
+ autoload :ProceduresCallNoReturnBlock
20
+ autoload :ProceduresCallReturnBlock
21
+ autoload :ProceduresDefNoReturnBlock
22
+ autoload :ProceduresDefReturnBlock
23
+ autoload :ProceduresIfReturnBlock
24
+ autoload :RepeatTimesBlock
25
+ autoload :SetVariableBlock
26
+ autoload :TextBlock
27
+ autoload :TextChangeCaseBlock
28
+ autoload :TextJoinBlock
29
+
30
+ self.block_classes = [
31
+ ArithmeticOperatorBlock,
32
+ BooleanBlock,
33
+ ComparisonOperatorBlock,
34
+ ForBlock,
35
+ ForEachBlock,
36
+ GetVariableBlock,
37
+ IfBlock,
38
+ ListsCreateEmptyBlock,
39
+ ListsCreateWithBlock,
40
+ ListsGetIndexBlock,
41
+ LogicNegateBlock,
42
+ LogicalOperatorBlock,
43
+ NumberBlock,
44
+ ProceduresCallNoReturnBlock,
45
+ ProceduresCallReturnBlock,
46
+ ProceduresDefNoReturnBlock,
47
+ ProceduresDefReturnBlock,
48
+ ProceduresIfReturnBlock,
49
+ RepeatTimesBlock,
50
+ SetVariableBlock,
51
+ TextBlock,
52
+ TextChangeCaseBlock,
53
+ TextJoinBlock
54
+ ]
55
+ end
@@ -0,0 +1,24 @@
1
+ class BlocklyInterpreter::CoreBlocks::ArithmeticOperatorBlock < BlocklyInterpreter::Block
2
+ self.block_type = :math_arithmetic
3
+
4
+ def value(execution_context)
5
+ a = values['A'].value(execution_context)
6
+ b = values['B'].value(execution_context)
7
+
8
+ case fields['OP'].to_s.upcase
9
+ when 'ADD' then a + b
10
+ when 'MINUS' then a - b
11
+ when 'MULTIPLY' then a * b
12
+ when 'DIVIDE' then a / b
13
+ when 'POWER' then a ** b
14
+ end
15
+ end
16
+
17
+ module DSLMethods
18
+ def math_arithmetic(op, a = nil, b = nil, &proc)
19
+ @blocks << BlocklyInterpreter::DSL::BinaryOperationBlockBuilder.new("math_arithmetic", op, a, b).tap do |builder|
20
+ builder.instance_exec(&proc) if block_given?
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ class BlocklyInterpreter::CoreBlocks::BooleanBlock < BlocklyInterpreter::Block
2
+ self.block_type = :logic_boolean
3
+
4
+ def to_bool
5
+ fields['BOOL'] == 'TRUE'
6
+ end
7
+
8
+ def value(execution_context)
9
+ to_bool
10
+ end
11
+
12
+ def to_dsl
13
+ "logic_boolean #{to_bool.inspect}"
14
+ end
15
+
16
+ module DSLMethods
17
+ def logic_boolean(value)
18
+ block :logic_boolean do
19
+ field :BOOL, value ? "TRUE" : "FALSE"
20
+ end
21
+ end
22
+ end
23
+ end