diff --git a/core/names.js b/core/names.js index bfe942ab9..016c01538 100644 --- a/core/names.js +++ b/core/names.js @@ -26,6 +26,11 @@ goog.provide('Blockly.Names'); +/** + * Constant to separate developer variable names from user-defined variable + * names when running generators. + */ +Blockly.Names.DEVELOPER_VARIABLE_TYPE = 'DEVELOPER_VARIABLE'; /** * Class for a database of entity names (variables, functions, etc). @@ -62,6 +67,23 @@ Blockly.Names = function(reservedWords, opt_variablePrefix) { Blockly.Names.prototype.reset = function() { this.db_ = Object.create(null); this.dbReverse_ = Object.create(null); + this.variableMap_ = null; +}; + +Blockly.Names.prototype.setVariableMap = function(map) { + this.variableMap_ = map; +}; + +Blockly.Names.prototype.getNameForVariable = function(id) { + if (!this.variableMap_) { + return null; + } + var variable = this.variableMap_.getVariableById(id); + if (variable) { + return variable.name; + } else { + return null; + } }; /** @@ -72,9 +94,18 @@ Blockly.Names.prototype.reset = function() { * @return {string} An entity name legal for the exported language. */ Blockly.Names.prototype.getName = function(name, type) { + if (type == Blockly.Variables.NAME_TYPE) { + var varName = this.getNameForVariable(name); + if (varName) { + name = varName; + } + } var normalized = name.toLowerCase() + '_' + type; - var prefix = (type == Blockly.Variables.NAME_TYPE) ? - this.variablePrefix_ : ''; + + var isVarType = type == Blockly.Variables.NAME_TYPE || + type == Blockly.Names.DEVELOPER_VARIABLE_TYPE; + + var prefix = isVarType ? this.variablePrefix_ : ''; if (normalized in this.db_) { return prefix + this.db_[normalized]; } @@ -103,8 +134,9 @@ Blockly.Names.prototype.getDistinctName = function(name, type) { } safeName += i; this.dbReverse_[safeName] = true; - var prefix = (type == Blockly.Variables.NAME_TYPE) ? - this.variablePrefix_ : ''; + var isVarType = type == Blockly.Variables.NAME_TYPE || + type == Blockly.Names.DEVELOPER_VARIABLE_TYPE; + var prefix = isVarType ? this.variablePrefix_ : ''; return prefix + safeName; }; diff --git a/core/variables.js b/core/variables.js index b8d40028b..3eb3bcedf 100644 --- a/core/variables.js +++ b/core/variables.js @@ -100,6 +100,38 @@ Blockly.Variables.allVariables = function(root) { return root.getAllVariables(); }; +/** + * Find all developer variables used by blocks in the workspace. + * Developer variables are never shown to the user, but are declared as global + * variables in the generated code. + * To declare developer variables, define the getDeveloperVariables function on + * your block and return a list of variable names. + * For use by generators. + * @param {!Blockly.Workspace} workspace The workspace to search. + * @return {!Array.} A list of non-duplicated variable names. + * @package + */ +Blockly.Variables.allDeveloperVariables = function(workspace) { + var blocks = workspace.getAllBlocks(); + var hash = {}; + for (var i = 0; i < blocks.length; i++) { + var block = blocks[i]; + if (block.getDeveloperVars) { + var devVars = block.getDeveloperVars(); + for (var j = 0; j < devVars.length; j++) { + hash[devVars[j]] = devVars[j]; + } + } + } + + // Flatten the hash into a list. + var list = []; + for (var name in hash) { + list.push(hash[name]); + } + return list; +}; + /** * Construct the elements (blocks and button) required by the flyout for the * variable category. diff --git a/generators/dart.js b/generators/dart.js index 83ef76cd6..1d3c93b75 100644 --- a/generators/dart.js +++ b/generators/dart.js @@ -102,13 +102,25 @@ Blockly.Dart.init = function(workspace) { Blockly.Dart.variableDB_.reset(); } + Blockly.Dart.variableDB_.setVariableMap(workspace.getVariableMap()); + var defvars = []; + // Add user variables. var variables = workspace.getAllVariables(); - if (variables.length) { - for (var i = 0; i < variables.length; i++) { - defvars[i] = Blockly.Dart.variableDB_.getName(variables[i].name, - Blockly.Variables.NAME_TYPE); - } + for (var i = 0; i < variables.length; i++) { + defvars[i] = Blockly.Dart.variableDB_.getName(variables[i].name, + Blockly.Variables.NAME_TYPE); + } + + // Add developer variables (not created or named by the user). + var devVarList = Blockly.Variables.allDeveloperVariables(workspace); + for (var i = 0; i < devVarList.length; i++) { + defvars.push(Blockly.Dart.variableDB_.getName(devVarList[i], + Blockly.Names.DEVELOPER_VARIABLE_TYPE)); + } + + // Declare all of the variables. + if (defvars.length) { Blockly.Dart.definitions_['variables'] = 'var ' + defvars.join(', ') + ';'; } diff --git a/generators/javascript.js b/generators/javascript.js index 00b96bcc1..864ae50c3 100644 --- a/generators/javascript.js +++ b/generators/javascript.js @@ -152,13 +152,25 @@ Blockly.JavaScript.init = function(workspace) { Blockly.JavaScript.variableDB_.reset(); } + Blockly.JavaScript.variableDB_.setVariableMap(workspace.getVariableMap()); + var defvars = []; + // Add user variables. var variables = workspace.getAllVariables(); - if (variables.length) { - for (var i = 0; i < variables.length; i++) { - defvars[i] = Blockly.JavaScript.variableDB_.getName(variables[i].name, - Blockly.Variables.NAME_TYPE); - } + for (var i = 0; i < variables.length; i++) { + defvars[i] = Blockly.JavaScript.variableDB_.getName(variables[i].name, + Blockly.Variables.NAME_TYPE); + } + + // Add developer variables (not created or named by the user). + var devVarList = Blockly.Variables.allDeveloperVariables(workspace); + for (var i = 0; i < devVarList.length; i++) { + defvars.push(Blockly.JavaScript.variableDB_.getName(devVarList[i], + Blockly.Names.DEVELOPER_VARIABLE_TYPE)); + } + + // Declare all of the variables. + if (defvars.length) { Blockly.JavaScript.definitions_['variables'] = 'var ' + defvars.join(', ') + ';'; } diff --git a/tests/generators/unittest.js b/tests/generators/unittest.js index 5c471d1b7..6b7378210 100644 --- a/tests/generators/unittest.js +++ b/tests/generators/unittest.js @@ -34,7 +34,7 @@ Blockly.Blocks['unittest_main'] = { this.setTooltip('Executes the enclosed unit tests,\n' + 'then prints a summary.'); }, - getVars: function() { + getDeveloperVars: function() { return ['unittestResults']; } }; @@ -54,7 +54,7 @@ Blockly.Blocks['unittest_assertequals'] = { .appendField('expected'); this.setTooltip('Tests that "actual == expected".'); }, - getVars: function() { + getDeveloperVars: function() { return ['unittestResults']; } }; @@ -74,7 +74,7 @@ Blockly.Blocks['unittest_assertvalue'] = { [['true', 'TRUE'], ['false', 'FALSE'], ['null', 'NULL']]), 'EXPECTED'); this.setTooltip('Tests that the value is true, false, or null.'); }, - getVars: function() { + getDeveloperVars: function() { return ['unittestResults']; } }; @@ -90,7 +90,7 @@ Blockly.Blocks['unittest_fail'] = { .appendField('fail'); this.setTooltip('Records an error.'); }, - getVars: function() { + getDeveloperVars: function() { return ['unittestResults']; } }; diff --git a/tests/generators/unittest_dart.js b/tests/generators/unittest_dart.js index 97e6ae466..436bcff63 100644 --- a/tests/generators/unittest_dart.js +++ b/tests/generators/unittest_dart.js @@ -27,7 +27,7 @@ Blockly.Dart['unittest_main'] = function(block) { // Container for unit tests. var resultsVar = Blockly.Dart.variableDB_.getName('unittestResults', - Blockly.Variables.NAME_TYPE); + Blockly.Names.DEVELOPER_VARIABLE_TYPE); var functionName = Blockly.Dart.provideFunction_( 'unittest_report', [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '() {', @@ -71,7 +71,7 @@ Blockly.Dart['unittest_main'] = function(block) { Blockly.Dart['unittest_main'].defineAssert_ = function() { var resultsVar = Blockly.Dart.variableDB_.getName('unittestResults', - Blockly.Variables.NAME_TYPE); + Blockly.Names.DEVELOPER_VARIABLE_TYPE); var functionName = Blockly.Dart.provideFunction_( 'unittest_assertequals', [ 'void ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + @@ -139,7 +139,7 @@ Blockly.Dart['unittest_assertvalue'] = function(block) { Blockly.Dart['unittest_fail'] = function(block) { // Always assert an error. var resultsVar = Blockly.Dart.variableDB_.getName('unittestResults', - Blockly.Variables.NAME_TYPE); + Blockly.Names.DEVELOPER_VARIABLE_TYPE); var message = Blockly.Dart.quote_(block.getFieldValue('MESSAGE')); var functionName = Blockly.Dart.provideFunction_( 'unittest_fail', diff --git a/tests/generators/unittest_javascript.js b/tests/generators/unittest_javascript.js index 9fda5be30..92d8a2913 100644 --- a/tests/generators/unittest_javascript.js +++ b/tests/generators/unittest_javascript.js @@ -27,7 +27,7 @@ Blockly.JavaScript['unittest_main'] = function(block) { // Container for unit tests. var resultsVar = Blockly.JavaScript.variableDB_.getName('unittestResults', - Blockly.Variables.NAME_TYPE); + Blockly.Names.DEVELOPER_VARIABLE_TYPE); var functionName = Blockly.JavaScript.provideFunction_( 'unittest_report', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '() {', @@ -72,7 +72,7 @@ Blockly.JavaScript['unittest_main'] = function(block) { Blockly.JavaScript['unittest_main'].defineAssert_ = function(block) { var resultsVar = Blockly.JavaScript.variableDB_.getName('unittestResults', - Blockly.Variables.NAME_TYPE); + Blockly.Names.DEVELOPER_VARIABLE_TYPE); var functionName = Blockly.JavaScript.provideFunction_( 'assertEquals', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + @@ -143,7 +143,7 @@ Blockly.JavaScript['unittest_assertvalue'] = function(block) { Blockly.JavaScript['unittest_fail'] = function(block) { // Always assert an error. var resultsVar = Blockly.JavaScript.variableDB_.getName('unittestResults', - Blockly.Variables.NAME_TYPE); + Blockly.Names.DEVELOPER_VARIABLE_TYPE); var message = Blockly.JavaScript.quote_(block.getFieldValue('MESSAGE')); var functionName = Blockly.JavaScript.provideFunction_( 'unittest_fail',