Commit 441d2913 authored by carlosperate's avatar carlosperate

Fix variable declarations if used inside user functions.

parent 4a407ec1
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* @fileoverview Object that defines static objects and methods to assign * @fileoverview Object that defines static objects and methods to assign
* Blockly types to Blockly blocks. These can then be converted to * Blockly types to Blockly blocks. These can then be converted to
* language specific type in each language generator. * language specific types in each language generator.
*/ */
'use strict'; 'use strict';
...@@ -43,9 +43,9 @@ Blockly.StaticTyping.BlocklyType = { ...@@ -43,9 +43,9 @@ Blockly.StaticTyping.BlocklyType = {
}; };
/** /**
* Navigates through the blocks collecting all variables and getting their type * Navigates through the top level blocks collecting all variables and getting
* into an associative array with the variable names as the keys and the type * their type into an associative array with the variable names as the keys and
* as the values. * the type as the values.
* @param {Blockly.Workspace} workspace Blockly Workspace to collect variables. * @param {Blockly.Workspace} workspace Blockly Workspace to collect variables.
* @return {Array<string>} Associative array with the variable names as the keys * @return {Array<string>} Associative array with the variable names as the keys
* and the type as the values. * and the type as the values.
...@@ -58,7 +58,7 @@ Blockly.StaticTyping.getAllVarsWithTypes = function(workspace) { ...@@ -58,7 +58,7 @@ Blockly.StaticTyping.getAllVarsWithTypes = function(workspace) {
} }
var varsWithTypes = Object.create(null); var varsWithTypes = Object.create(null);
var varSetTypeCallbacks = Object.create(null); var varUndefBlockList = Object.create(null);
for (var x = 0, xlength_ = blocks.length; x < xlength_; x++) { for (var x = 0, xlength_ = blocks.length; x < xlength_; x++) {
var block = blocks[x]; var block = blocks[x];
do { do {
...@@ -68,18 +68,32 @@ Blockly.StaticTyping.getAllVarsWithTypes = function(workspace) { ...@@ -68,18 +68,32 @@ Blockly.StaticTyping.getAllVarsWithTypes = function(workspace) {
var varName = blockVarsWithTypes[z][0]; var varName = blockVarsWithTypes[z][0];
var varType = blockVarsWithTypes[z][1]; var varType = blockVarsWithTypes[z][1];
Blockly.StaticTyping.manageVarsWithTypes( Blockly.StaticTyping.manageVarsWithTypes(
block, varName, varType, varsWithTypes, varSetTypeCallbacks); block, varName, varType, varsWithTypes, varUndefBlockList);
} // end loop for block variables } // end loop for block variables
block = block.nextConnection && block.nextConnection.targetBlock(); var childBlocks = null;
if (block.nextConnection) {
block = block.nextConnection.targetBlock();
} else if (block.getProcedureDef &&
(childBlocks = block.getChildren()).length > 0) {
// If the block is a function there is no connection, but a child block
block = childBlocks[0];
} else {
block = null;
}
} while (block); } while (block);
} // end loop for all top blocks } // end loop for all top blocks
return varsWithTypes; return varsWithTypes;
}; };
/** Description */ /**
* Retrieves the input argument block variables with their set type.
* @param {Blockly.Block} block Block to retrieve variables from.
* @return {Array<string>} Associative array with the block variable names as
* the keys and the type as the values.
*/
Blockly.StaticTyping.getBlockVars = function(block) { Blockly.StaticTyping.getBlockVars = function(block) {
var varsWithTypes = []; var blockVarsWithTypes = [];
var getVars = block.getVars; var getVars = block.getVars;
if (getVars) { if (getVars) {
var blockVariables = getVars.call(block); var blockVariables = getVars.call(block);
...@@ -89,28 +103,39 @@ Blockly.StaticTyping.getBlockVars = function(block) { ...@@ -89,28 +103,39 @@ Blockly.StaticTyping.getBlockVars = function(block) {
var getVarType = block.getVarType; var getVarType = block.getVarType;
if (getVarType) { if (getVarType) {
var varType = getVarType.call(block, varName); var varType = getVarType.call(block, varName);
varsWithTypes.push([varName, varType]); blockVarsWithTypes.push([varName, varType]);
} else { } else {
varsWithTypes.push( blockVarsWithTypes.push(
[varName, Blockly.StaticTyping.BlocklyType.UNSPECIFIED]); [varName, Blockly.StaticTyping.BlocklyType.UNSPECIFIED]);
} }
} }
} // else block.getVars() existence: Block does not define vars, do nothing } // else: !(block.getVars), block does not define vars, so do nothing
return varsWithTypes; return blockVarsWithTypes;
}; };
/** Description */ /**
Blockly.StaticTyping.manageVarsWithTypes = * Manages the associative array of variables with their type.
function(block, varName, varType, varsWithTypes, varSetTypeCallbacks) { * @param {Blockly.Block} block Blockly providing the variable to manage.
* @param {string} varName Name of the variable to manage.
* @param {string} varType Type assigned by the current block.
* @param {Array<string>} varsWithTypes Associative array containing the
* currently processed variables, with the variable names as the keys and
* the type as the values.
* @param {Array<Blockly.Block>} varUndefBlockList Associative array of blocks
* to call back with a type for the variables (used as the key) that they
* contain currently undefined.
*/
Blockly.StaticTyping.manageVarsWithTypes = function(
block, varName, varType, varsWithTypes, varUndefBlockList) {
if (varsWithTypes[varName] === undefined) { if (varsWithTypes[varName] === undefined) {
// First time variable is encountered, so set type and callback list // First time variable is encountered, so set type and callback list
varsWithTypes[varName] = varType; varsWithTypes[varName] = varType;
varSetTypeCallbacks[varName] = []; varUndefBlockList[varName] = [];
// If this block type is UNDEF it will need to know its type // If this block type is UNDEF it will need to know its type
if ((varType === Blockly.StaticTyping.BlocklyType.UNDEF) && if ((varType === Blockly.StaticTyping.BlocklyType.UNDEF) &&
(block.setBlockType)) { (block.setBlockType)) {
varSetTypeCallbacks[varName].push(block); varUndefBlockList[varName].push(block);
} }
} else if (varsWithTypes[varName] === } else if (varsWithTypes[varName] ===
Blockly.StaticTyping.BlocklyType.UNDEF) { Blockly.StaticTyping.BlocklyType.UNDEF) {
...@@ -120,12 +145,12 @@ Blockly.StaticTyping.manageVarsWithTypes = ...@@ -120,12 +145,12 @@ Blockly.StaticTyping.manageVarsWithTypes =
// If this block type is UNDEF it will need to know its type // If this block type is UNDEF it will need to know its type
if (varType === Blockly.StaticTyping.BlocklyType.UNDEF) { if (varType === Blockly.StaticTyping.BlocklyType.UNDEF) {
if (block.setBlockType) { if (block.setBlockType) {
varSetTypeCallbacks[varName].push(block); varUndefBlockList[varName].push(block);
} }
} else { } else {
// Valid type added, so update all waiting blocks // Valid type added, so update all waiting blocks
for (var i = 0; i < varSetTypeCallbacks[varName].length; i++) { for (var i = 0; i < varUndefBlockList[varName].length; i++) {
varSetTypeCallbacks[varName][i].setBlockType(varType); varUndefBlockList[varName][i].setBlockType(varType);
} }
} }
} else { } else {
...@@ -143,14 +168,20 @@ Blockly.StaticTyping.manageVarsWithTypes = ...@@ -143,14 +168,20 @@ Blockly.StaticTyping.manageVarsWithTypes =
/** /**
* When a block uses a variable this function can compare its type with the * When a block uses a variable this function can compare its type with the
* variable type and set a warning if they are not the same or compatible. * variable type and set a warning if they are not the same or compatible.
* @param {!Blockly.Block} block The block to manage its warning. * @param {!Blockly.Block} block The block to manage its warning.
* @param {!string} bType The type of this block. * @param {!string} bType The type of this block.
* @param {!string} vName The variable name. * @param {!string} vName The variable name.
* @param {!string} vType The type of the variable. * @param {!string} vType The type of the variable.
*/ */
Blockly.StaticTyping.manageTypeWarning = function(block, bType, vName, vType) { Blockly.StaticTyping.manageTypeWarning = function(block, bType, vName, vType) {
if ((vType !== bType) && (bType !== Blockly.StaticTyping.BlocklyType.UNDEF)) { if ((bType === Blockly.StaticTyping.BlocklyType.CHILD_BLOCK_MISSING) ||
(vType === Blockly.StaticTyping.BlocklyType.CHILD_BLOCK_MISSING)) {
// User still has to attach a block to this variable or its first
// declaration, so for now do not display any warning
block.setWarningText(null, 'varType');
} else if ((vType !== bType) &&
(bType !== Blockly.StaticTyping.BlocklyType.UNDEF)) {
block.setWarningText('The variable ' + vName +' has been first assigned' + block.setWarningText('The variable ' + vName +' has been first assigned' +
'to the type "' + vType + '"" and this block needs it to be set to ' + 'to the type "' + vType + '"" and this block needs it to be set to ' +
'the type "' + bType + '" !', 'varType'); 'the type "' + bType + '" !', 'varType');
...@@ -159,10 +190,14 @@ Blockly.StaticTyping.manageTypeWarning = function(block, bType, vName, vType) { ...@@ -159,10 +190,14 @@ Blockly.StaticTyping.manageTypeWarning = function(block, bType, vName, vType) {
} }
}; };
/**
/** Description */ * Iterates through the list of top level blocks and
* @param {Blockly.Workspace} workspace Blockly Workspace to collect variables.
* @param {Array<string>} Associative array with the variable names as the keys
* and the type as the values.
*/
Blockly.StaticTyping.setProcedureArgs = function(workspace, varsWithTypes) { Blockly.StaticTyping.setProcedureArgs = function(workspace, varsWithTypes) {
var blocks = workspace.getAllBlocks(); var blocks = workspace.getTopBlocks();
for (var i = 0, length_ = blocks.length; i < length_; i++) { for (var i = 0, length_ = blocks.length; i < length_; i++) {
var setArgsType = blocks[i].setArgsType; var setArgsType = blocks[i].setArgsType;
if (setArgsType) { if (setArgsType) {
...@@ -172,7 +207,7 @@ Blockly.StaticTyping.setProcedureArgs = function(workspace, varsWithTypes) { ...@@ -172,7 +207,7 @@ Blockly.StaticTyping.setProcedureArgs = function(workspace, varsWithTypes) {
}; };
/** /**
* Navigates through the child blocks to get the block type. * Navigates through the child blocks of the input block to get the block type.
* @param {!Blockly.Block} block Block to navigate through children. * @param {!Blockly.Block} block Block to navigate through children.
* @return {string} Type of the input block. * @return {string} Type of the input block.
*/ */
...@@ -208,9 +243,8 @@ Blockly.StaticTyping.regExpInt_ = new RegExp(/^\d+$/); ...@@ -208,9 +243,8 @@ Blockly.StaticTyping.regExpInt_ = new RegExp(/^\d+$/);
Blockly.StaticTyping.regExpFloat_ = new RegExp(/^[0-9]*[.][0-9]+$/); Blockly.StaticTyping.regExpFloat_ = new RegExp(/^[0-9]*[.][0-9]+$/);
/** /**
* Navigates through the blocks collecting all variables and getting their type * Uses regular expressions to identify if the input number is an integer or a
* into an associative array with the variable names as the keys and the type * floating point.
* as the values.
* @param {string} numberString String of the number to identify. * @param {string} numberString String of the number to identify.
* @return {!Blockly.StaticTyping.BlocklyType} Blockly type. * @return {!Blockly.StaticTyping.BlocklyType} Blockly type.
*/ */
...@@ -225,7 +259,7 @@ Blockly.StaticTyping.identifyNumber = function(numberString) { ...@@ -225,7 +259,7 @@ Blockly.StaticTyping.identifyNumber = function(numberString) {
}; };
/** /**
* Converts the static types dictionary in to a an array with 2-item arrays. * Converts the static types dictionary in to a an array with 2-item arrays.
* This array only contains the valid types, excluding any error or temp types. * This array only contains the valid types, excluding any error or temp types.
* @return {!array<array<string>>} Blockly types in the format described above. * @return {!array<array<string>>} Blockly types in the format described above.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment