diff --git a/accessible/app.component.js b/accessible/app.component.js
index 5de03e575..763a13c11 100644
--- a/accessible/app.component.js
+++ b/accessible/app.component.js
@@ -25,9 +25,6 @@
blocklyApp.workspace = new Blockly.Workspace();
-// If the debug flag is true, print console.logs to help with debugging.
-blocklyApp.debug = false;
-
blocklyApp.AppView = ng.core
.Component({
selector: 'blockly-app',
diff --git a/accessible/clipboard.service.js b/accessible/clipboard.service.js
index de9b382a3..db65e2d9f 100644
--- a/accessible/clipboard.service.js
+++ b/accessible/clipboard.service.js
@@ -30,6 +30,60 @@ blocklyApp.ClipboardService = ng.core
this.clipboardBlockNextConnection_ = null;
this.markedConnection_ = null;
},
+ areConnectionsCompatible_: function(blockConnection, connection) {
+ // Check that both connections exist, that it's the right kind of
+ // connection, and that the types match.
+ return Boolean(
+ connection && blockConnection &&
+ Blockly.OPPOSITE_TYPE[blockConnection.type] == connection.type &&
+ connection.checkType_(blockConnection));
+ },
+ isCompatibleWithClipboard: function(connection) {
+ var superiorConnection = this.clipboardBlockSuperiorConnection_;
+ var nextConnection = this.clipboardBlockNextConnection_;
+ return Boolean(
+ this.areConnectionsCompatible_(connection, superiorConnection) ||
+ this.areConnectionsCompatible_(connection, nextConnection));
+ },
+ isMovableToMarkedConnection: function(block) {
+ // It should not be possible to move any ancestor of the block containing
+ // the marked spot to the marked spot.
+ if (!this.markedConnection_) {
+ return false;
+ }
+
+ var markedSpotAncestorBlock = this.markedConnection_.getSourceBlock();
+ while (markedSpotAncestorBlock) {
+ if (markedSpotAncestorBlock.id == block.id) {
+ return false;
+ }
+ markedSpotAncestorBlock = markedSpotAncestorBlock.getParent();
+ }
+
+ return this.canBeCopiedToMarkedConnection(block);
+ },
+ canBeCopiedToMarkedConnection: function(block) {
+ if (!this.markedConnection_ ||
+ !this.markedConnection_.getSourceBlock().workspace) {
+ return false;
+ }
+
+ var potentialConnections = [
+ block.outputConnection,
+ block.previousConnection,
+ block.nextConnection
+ ];
+
+ var that = this;
+ return potentialConnections.some(function(connection) {
+ return that.areConnectionsCompatible_(
+ connection, that.markedConnection_);
+ });
+ },
+ markConnection: function(connection) {
+ this.markedConnection_ = connection;
+ alert(Blockly.Msg.MARKED_SPOT_MSG);
+ },
cut: function(block) {
var blockSummary = block.toString();
this.copy(block, false);
@@ -64,42 +118,36 @@ blocklyApp.ClipboardService = ng.core
},
pasteToMarkedConnection: function(block, announce) {
var xml = Blockly.Xml.blockToDom(block);
- var reconstitutedBlock =
- Blockly.Xml.domToBlock(blocklyApp.workspace, xml);
- this.markedConnection_.connect(
- reconstitutedBlock.outputConnection ||
- reconstitutedBlock.previousConnection);
+ var reconstitutedBlock = Blockly.Xml.domToBlock(
+ blocklyApp.workspace, xml);
+
+ var potentialConnections = [
+ reconstitutedBlock.outputConnection,
+ reconstitutedBlock.previousConnection,
+ reconstitutedBlock.nextConnection
+ ];
+
+ var connectionSuccessful = false;
+ for (var i = 0; i < potentialConnections.length; i++) {
+ if (this.areConnectionsCompatible_(
+ this.markedConnection_, potentialConnections[i])) {
+ this.markedConnection_.connect(potentialConnections[i]);
+ connectionSuccessful = true;
+ break;
+ }
+ }
+
+ if (!connectionSuccessful) {
+ console.error('ERROR: Could not connect block to marked spot.');
+ return;
+ }
+
if (announce) {
alert(
Blockly.Msg.PASTED_BLOCK_TO_MARKED_SPOT_MSG +
reconstitutedBlock.toString());
}
- },
- markConnection: function(connection) {
- this.markedConnection_ = connection;
- alert(Blockly.Msg.MARKED_SPOT_MSG);
- },
- isCompatibleWithConnection_: function(blockConnection, connection) {
- // Check that both connections exist, that the types match, and that it's
- // the right kind of connection.
- return Boolean(
- connection && blockConnection &&
- Blockly.OPPOSITE_TYPE[blockConnection.type] == connection.type &&
- connection.checkType_(blockConnection));
- },
- isBlockCompatibleWithMarkedConnection: function(block) {
- var blockConnection = block.outputConnection || block.previousConnection;
- return Boolean(
- this.markedConnection_ &&
- this.markedConnection_.sourceBlock_.workspace &&
- this.isCompatibleWithConnection_(
- blockConnection, this.markedConnection_));
- },
- isClipboardCompatibleWithConnection: function(connection) {
- var superiorConnection = this.clipboardBlockSuperiorConnection_;
- var nextConnection = this.clipboardBlockNextConnection_;
- return Boolean(
- this.isCompatibleWithConnection_(connection, superiorConnection) ||
- this.isCompatibleWithConnection_(connection, nextConnection));
+
+ this.markedConnection_ = null;
}
});
diff --git a/accessible/toolbox-tree.component.js b/accessible/toolbox-tree.component.js
index cc701fc35..64320458d 100644
--- a/accessible/toolbox-tree.component.js
+++ b/accessible/toolbox-tree.component.js
@@ -59,12 +59,12 @@ blocklyApp.ToolboxTreeComponent = ng.core
+ [disabled]="!canBeCopiedToMarkedConnection(block)">
{{'COPY_TO_MARKED_SPOT'|translate}}
@@ -138,6 +138,9 @@ blocklyApp.ToolboxTreeComponent = ng.core
return this.utilsService.generateAriaLabelledByAttr(
mainLabel, secondLabel, isDisabled);
},
+ canBeCopiedToMarkedConnection: function(block) {
+ return this.clipboardService.canBeCopiedToMarkedConnection(block);
+ },
copyToWorkspace: function(block) {
var xml = Blockly.Xml.blockToDom(block);
Blockly.Xml.domToBlock(blocklyApp.workspace, xml);
diff --git a/accessible/toolbox.component.js b/accessible/toolbox.component.js
index 589a73712..081803103 100644
--- a/accessible/toolbox.component.js
+++ b/accessible/toolbox.component.js
@@ -98,7 +98,7 @@ blocklyApp.ToolboxComponent = ng.core
this.idMap['Parent' + i] = 'blockly-toolbox-tree-node' + i;
}
} else {
- // Create a single category is created with all the top-level blocks.
+ // Create a single category with all the top-level blocks.
this.xmlHasCategories = false;
this.toolboxCategories = [Array.from(xmlToolboxElt.children)];
}
@@ -108,8 +108,7 @@ blocklyApp.ToolboxComponent = ng.core
// descendant after the ids have been computed.
if (this.xmlHasCategories) {
this.treeService.setActiveDesc(
- document.getElementById('blockly-toolbox-tree-node0'),
- document.getElementById('blockly-toolbox-tree'));
+ 'blockly-toolbox-tree-node0', 'blockly-toolbox-tree');
}
},
getToolboxWorkspace: function(categoryNode) {
diff --git a/accessible/tree.service.js b/accessible/tree.service.js
index 84ac80541..e464bc788 100644
--- a/accessible/tree.service.js
+++ b/accessible/tree.service.js
@@ -27,12 +27,6 @@
blocklyApp.TreeService = ng.core
.Class({
constructor: function() {
- // Keeping track of the last key pressed. If the user presses
- // enter (to edit a text input or press a button), the keyboard
- // focus shifts to that element. In the next keystroke, if the user
- // navigates away from the element using the arrow keys, we want
- // to shift focus back to the tree as a whole.
- this.previousKey_ = null;
// Stores active descendant ids for each tree in the page.
this.activeDescendantIds_ = {};
},
@@ -76,6 +70,16 @@ blocklyApp.TreeService = ng.core
return this.getToolboxTreeNode_();
},
+ focusOnCurrentTree_: function(treeId) {
+ var trees = this.getAllTreeNodes_();
+ for (var i = 0; i < trees.length; i++) {
+ if (trees[i].id == treeId) {
+ trees[i].focus();
+ return true;
+ }
+ }
+ return false;
+ },
focusOnNextTree_: function(treeId) {
var trees = this.getAllTreeNodes_();
for (var i = 0; i < trees.length - 1; i++) {
@@ -113,9 +117,10 @@ blocklyApp.TreeService = ng.core
},
// Runs the given function while preserving the focus and active descendant
// for the given tree.
- runWhilePreservingFocus: function(func, treeId) {
- var activeDescId = this.getActiveDescId(treeId);
- this.unmarkActiveDesc_(activeDescId);
+ runWhilePreservingFocus: function(func, treeId, optionalNewActiveDescId) {
+ var oldDescId = this.getActiveDescId(treeId);
+ var newDescId = optionalNewActiveDescId || oldDescId;
+ this.unmarkActiveDesc_(oldDescId);
func();
// The timeout is needed in order to give the DOM time to stabilize
@@ -123,132 +128,136 @@ blocklyApp.TreeService = ng.core
// pasteAbove().
var that = this;
setTimeout(function() {
- that.markActiveDesc_(activeDescId);
- that.activeDescendantIds_[treeId] = activeDescId;
+ that.markActiveDesc_(newDescId);
+ that.activeDescendantIds_[treeId] = newDescId;
document.getElementById(treeId).focus();
}, 0);
},
// Make a given node the active descendant of a given tree.
- setActiveDesc: function(newActiveDesc, tree) {
- this.unmarkActiveDesc_(this.getActiveDescId(tree.id));
- this.markActiveDesc_(newActiveDesc.id);
- this.activeDescendantIds_[tree.id] = newActiveDesc.id;
+ setActiveDesc: function(newActiveDescId, treeId) {
+ this.unmarkActiveDesc_(this.getActiveDescId(treeId));
+ this.markActiveDesc_(newActiveDescId);
+ this.activeDescendantIds_[treeId] = newActiveDescId;
},
onWorkspaceToolbarKeypress: function(e, treeId) {
- switch (e.keyCode) {
- case 9:
- // 16,9: shift, tab
- if (e.shiftKey) {
- // If the previous key is shift, we're shift-tabbing mode.
- this.focusOnPreviousTree_(treeId);
- } else {
- // If previous key isn't shift, we're tabbing.
- this.focusOnNextTree_(treeId);
- }
- e.preventDefault();
- e.stopPropagation();
- break;
+ if (e.keyCode == 9) {
+ // Tab key.
+ if (e.shiftKey) {
+ this.focusOnPreviousTree_(treeId);
+ } else {
+ this.focusOnNextTree_(treeId);
+ }
+ e.preventDefault();
+ e.stopPropagation();
}
},
+ isButtonOrFieldNode_: function(node) {
+ return ['BUTTON', 'INPUT'].indexOf(node.tagName) != -1;
+ },
+ getNextActiveDescWhenBlockIsDeleted: function(blockRootNode) {
+ // Go up a level, if possible.
+ var nextNode = blockRootNode.parentNode;
+ while (nextNode && nextNode.tagName != 'LI') {
+ nextNode = nextNode.parentNode;
+ }
+ if (nextNode) {
+ return nextNode;
+ }
+
+ // Otherwise, go to the next sibling.
+ var nextSibling = this.getNextSibling(blockRootNode);
+ if (nextSibling) {
+ return nextSibling;
+ }
+
+ // Otherwise, go to the previous sibling.
+ var previousSibling = this.getPreviousSibling(blockRootNode);
+ if (previousSibling) {
+ return previousSibling;
+ }
+
+ // Otherwise, this is a top-level isolated block, which means that
+ // something's gone wrong and this function should not have been called
+ // in the first place.
+ console.error('Could not handle deletion of block.' + blockRootNode);
+ },
onKeypress: function(e, tree) {
var treeId = tree.id;
- var node = document.getElementById(this.getActiveDescId(treeId));
- var keepFocus = this.previousKey_ == 13;
- if (!node) {
- blocklyApp.debug && console.log('KeyHandler: no active descendant');
+ var activeDesc = document.getElementById(this.getActiveDescId(treeId));
+ if (!activeDesc) {
+ console.error('ERROR: no active descendant for current tree.');
+
+ // TODO(sll): Generalize this to other trees (outside the workspace).
+ var workspaceTreeNodes = this.getWorkspaceTreeNodes_();
+ for (var i = 0; i < workspaceTreeNodes.length; i++) {
+ if (workspaceTreeNodes[i].id == treeId) {
+ // Set the active desc to the first child in this tree.
+ this.setActiveDesc(
+ this.getFirstChild(workspaceTreeNodes[i]).id, treeId);
+ break;
+ }
+ }
+ return;
}
- switch (e.keyCode) {
- case 9:
- // 16,9: shift, tab
- if (e.shiftKey) {
- // If the previous key is shift, we're shift-tabbing.
- this.focusOnPreviousTree_(treeId);
- } else {
- // If previous key isn't shift, we're tabbing
- // we want to go to the run code button.
- this.focusOnNextTree_(treeId);
+
+ var isFocusingIntoField = false;
+
+ if (e.keyCode == 13) {
+ // Enter key. The user wants to interact with a child.
+ if (activeDesc.children.length == 1) {
+ var child = activeDesc.children[0];
+ if (child.tagName == 'BUTTON') {
+ child.click();
+ this.isFocusingIntoField = true;
+ } else if (child.tagName == 'INPUT') {
+ child.focus();
}
- // Setting the previous key variable in each case because
- // we only want to save the previous navigation keystroke,
- // not any typing.
- this.previousKey_ = e.keyCode;
- e.preventDefault();
- e.stopPropagation();
- break;
- case 37:
- // Left-facing arrow: go out a level, if possible. If not, do nothing.
- var nextNode = node.parentNode;
- if (node.tagName == 'BUTTON' || node.tagName == 'INPUT') {
+ }
+ } else if (e.keyCode == 9) {
+ // Tab key.
+ if (e.shiftKey) {
+ this.focusOnPreviousTree_(treeId);
+ } else {
+ this.focusOnNextTree_(treeId);
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ } else if (e.keyCode >= 37 && e.keyCode <= 40) {
+ // Arrow keys.
+ if (e.keyCode == 37) {
+ // Left arrow key. Go up a level, if possible.
+ var nextNode = activeDesc.parentNode;
+ if (this.isButtonOrFieldNode_(activeDesc)) {
nextNode = nextNode.parentNode;
}
- while (nextNode && nextNode.className != 'treeview' &&
- nextNode.tagName != 'LI') {
+ while (nextNode && nextNode.tagName != 'LI') {
nextNode = nextNode.parentNode;
}
- if (!nextNode || nextNode.className == 'treeview') {
- return;
+ if (nextNode) {
+ this.setActiveDesc(nextNode.id, treeId);
}
- this.setActiveDesc(nextNode, tree);
- this.previousKey_ = e.keyCode;
- e.preventDefault();
- e.stopPropagation();
- break;
- case 38:
- // Up-facing arrow: go up a level, if possible. If not, do nothing.
- var prevSibling = this.getPreviousSibling(node);
- if (prevSibling && prevSibling.tagName != 'H1') {
- this.setActiveDesc(prevSibling, tree);
- } else {
- blocklyApp.debug && console.log('no previous sibling');
+ } else if (e.keyCode == 38) {
+ // Up arrow key. Go to the previous sibling, if possible.
+ var prevSibling = this.getPreviousSibling(activeDesc);
+ if (prevSibling) {
+ this.setActiveDesc(prevSibling.id, treeId);
}
- this.previousKey_ = e.keyCode;
- e.preventDefault();
- e.stopPropagation();
- break;
- case 39:
- var firstChild = this.getFirstChild(node);
+ } else if (e.keyCode == 39) {
+ // Right arrow key. Go down a level, if possible.
+ var firstChild = this.getFirstChild(activeDesc);
if (firstChild) {
- this.setActiveDesc(firstChild, tree);
- } else {
- blocklyApp.debug && console.log('no valid child');
+ this.setActiveDesc(firstChild.id, treeId);
}
- this.previousKey_ = e.keyCode;
- e.preventDefault();
- e.stopPropagation();
- break;
- case 40:
- // Down-facing arrow: go down a level, if possible.
- // If not, do nothing.
- var nextSibling = this.getNextSibling(node);
+ } else if (e.keyCode == 40) {
+ // Down arrow key. Go to the next sibling, if possible.
+ var nextSibling = this.getNextSibling(activeDesc);
if (nextSibling) {
- this.setActiveDesc(nextSibling, tree);
- } else {
- blocklyApp.debug && console.log('no next sibling');
+ this.setActiveDesc(nextSibling.id, treeId);
}
- this.previousKey_ = e.keyCode;
- e.preventDefault();
- e.stopPropagation();
- break;
- case 13:
- // If I've pressed enter, I want to interact with a child.
- var activeDesc = node;
- if (activeDesc) {
- var children = activeDesc.children;
- var child = children[0];
- if (children.length == 1 && (child.tagName == 'INPUT' ||
- child.tagName == 'BUTTON')) {
- if (child.tagName == 'BUTTON') {
- child.click();
- }
- else if (child.tagName == 'INPUT') {
- child.focus();
- }
- }
- } else {
- blocklyApp.debug && console.log('no activeDesc');
- }
- this.previousKey_ = e.keyCode;
- break;
+ }
+
+ e.preventDefault();
+ e.stopPropagation();
}
},
getFirstChild: function(element) {
@@ -273,13 +282,12 @@ blocklyApp.TreeService = ng.core
if (element.nextElementSibling) {
// If there is a sibling, find the list element child of the sibling.
var node = element.nextElementSibling;
- if (node.tagName != 'LI') {
- var listElems = node.getElementsByTagName('li');
- // getElementsByTagName returns in DFS order
- // therefore the first element is the first relevant list child.
- return listElems[0];
+ if (node.tagName == 'LI') {
+ return node;
} else {
- return element.nextElementSibling;
+ // getElementsByTagName returns in DFS order, therefore the first
+ // element is the first relevant list child.
+ return node.getElementsByTagName('li')[0];
}
} else {
var parent = element.parentNode;
@@ -343,7 +351,6 @@ blocklyApp.TreeService = ng.core
}
}
}
- blocklyApp.debug && console.log('no last child');
return null;
}
}
diff --git a/accessible/workspace-tree.component.js b/accessible/workspace-tree.component.js
index 2fe99002c..5c7f4dc5f 100644
--- a/accessible/workspace-tree.component.js
+++ b/accessible/workspace-tree.component.js
@@ -28,69 +28,29 @@ blocklyApp.WorkspaceTreeComponent = ng.core
.Component({
selector: 'blockly-workspace-tree',
template: `
-
+ [attr.aria-level]="level" aria-selected="false">
{{block.toString()}}
-
+
+
+ [attr.aria-level]="level+1" aria-selected="false">
{{'BLOCK_ACTION_LIST'|translate}}
-
-
- {{'CUT_BLOCK'|translate}}
-
-
- {{'COPY_BLOCK'|translate}}
-
-
-
- {{'PASTE_BELOW'|translate}}
+
+
+
+ {{buttonInfo.translationIdForText|translate}}
-
-
- {{'PASTE_ABOVE'|translate}}
-
-
-
-
- {{'MARK_SPOT_BELOW'|translate}}
-
-
-
- {{'MARK_SPOT_ABOVE'|translate}}
-
-
- {{'MOVE_TO_MARKED_SPOT'|translate}}
-
-
- {{'DELETE'|translate}}
-
+
{{utilsService.getInputTypeLabel(inputBlock.connection)}} {{utilsService.getBlockTypeLabel(inputBlock)}} needed:
-
+
@@ -135,40 +95,173 @@ blocklyApp.WorkspaceTreeComponent = ng.core
})
.Class({
constructor: [
- blocklyApp.ClipboardService, blocklyApp.TreeService, blocklyApp.UtilsService,
+ blocklyApp.ClipboardService, blocklyApp.TreeService,
+ blocklyApp.UtilsService,
function(_clipboardService, _treeService, _utilsService) {
this.infoBlocks = Object.create(null);
this.clipboardService = _clipboardService;
this.treeService = _treeService;
this.utilsService = _utilsService;
}],
- getElementsNeedingIds_: function() {
- var elementsNeedingIds = ['blockSummary', 'listItem', 'label',
- 'cutListItem', 'cutButton', 'copyListItem', 'copyButton',
- 'pasteBelow', 'pasteBelowButton', 'pasteAbove', 'pasteAboveButton',
- 'markBelow', 'markBelowButton', 'markAbove', 'markAboveButton',
- 'sendToSelectedListItem', 'sendToSelectedButton', 'delete',
- 'deleteButton'];
+ isIsolatedTopLevelBlock_: function(block) {
+ // Returns whether the given block is at the top level, and has no
+ // siblings.
+ return Boolean(
+ !block.nextConnection.targetConnection &&
+ !block.previousConnection.targetConnection &&
+ blocklyApp.workspace.topBlocks_.some(function(topBlock) {
+ return topBlock.id == block.id;
+ }));
+ },
+ removeBlockAndSetFocus_: function(block, deleteBlockFunc) {
+ // This method runs the given function and then does one of two things:
+ // - If the block is an isolated top-level block, it shifts the tree
+ // focus.
+ // - Otherwise, it sets the correct new active desc for the current tree.
+ if (this.isIsolatedTopLevelBlock_(block)) {
+ var nextNodeToFocusOn =
+ this.treeService.getNodeToFocusOnWhenTreeIsDeleted(this.tree.id);
+ deleteBlockFunc();
+ nextNodeToFocusOn.focus();
+ } else {
+ var blockRootNode = document.getElementById(this.idMap['blockRoot']);
+ var nextActiveDesc =
+ this.treeService.getNextActiveDescWhenBlockIsDeleted(
+ blockRootNode);
+ this.treeService.runWhilePreservingFocus(
+ deleteBlockFunc, this.tree.id, nextActiveDesc.id);
+ }
+ },
+ cutBlock_: function() {
+ var that = this;
+ this.removeBlockAndSetFocus_(this.block, function() {
+ that.clipboardService.cut(that.block);
+ });
+ },
+ deleteBlock_: function() {
+ var that = this;
+ this.removeBlockAndSetFocus_(this.block, function() {
+ that.block.dispose(true);
+ });
+ },
+ pasteToConnection_: function(connection) {
+ var that = this;
+ this.treeService.runWhilePreservingFocus(function() {
+ // If the connection is a 'previousConnection' and that connection is
+ // already joined to something, use the 'nextConnection' of the
+ // previous block instead in order to do an insertion.
+ if (connection.type == Blockly.PREVIOUS_STATEMENT &&
+ connection.isConnected()) {
+ that.clipboardService.pasteFromClipboard(
+ connection.targetConnection);
+ } else {
+ that.clipboardService.pasteFromClipboard(connection);
+ }
+ }, this.tree.id);
+ },
+ sendToMarkedSpot_: function() {
+ this.clipboardService.pasteToMarkedConnection(this.block, false);
+ var that = this;
+ this.removeBlockAndSetFocus_(this.block, function() {
+ that.block.dispose(true);
+ });
+
+ alert('Block moved to marked spot: ' + this.block.toString());
+ },
+ ngOnInit: function() {
+ var that = this;
+
+ // Generate a list of action buttons.
+ this.actionButtonsInfo = [{
+ baseIdKey: 'cut',
+ translationIdForText: 'CUT_BLOCK',
+ action: that.cutBlock_.bind(that),
+ isDisabled: function() {
+ return false;
+ }
+ }, {
+ baseIdKey: 'copy',
+ translationIdForText: 'COPY_BLOCK',
+ action: that.clipboardService.copy.bind(
+ that.clipboardService, that.block, true),
+ isDisabled: function() {
+ return false;
+ }
+ }, {
+ baseIdKey: 'pasteBelow',
+ translationIdForText: 'PASTE_BELOW',
+ action: that.pasteToConnection_.bind(that, that.block.nextConnection),
+ isDisabled: function() {
+ return Boolean(
+ !that.block.nextConnection ||
+ !that.isCompatibleWithClipboard(that.block.nextConnection));
+ }
+ }, {
+ baseIdKey: 'pasteAbove',
+ translationIdForText: 'PASTE_ABOVE',
+ action: that.pasteToConnection_.bind(
+ that, that.block.previousConnection),
+ isDisabled: function() {
+ return Boolean(
+ !that.block.previousConnection ||
+ !that.isCompatibleWithClipboard(that.block.previousConnection));
+ }
+ }, {
+ baseIdKey: 'markBelow',
+ translationIdForText: 'MARK_SPOT_BELOW',
+ action: that.clipboardService.markConnection.bind(
+ that.clipboardService, that.block.nextConnection),
+ isDisabled: function() {
+ return !that.block.nextConnection;
+ }
+ }, {
+ baseIdKey: 'markAbove',
+ translationIdForText: 'MARK_SPOT_ABOVE',
+ action: that.clipboardService.markConnection.bind(
+ that.clipboardService, that.block.previousConnection),
+ isDisabled: function() {
+ return !that.block.previousConnection;
+ }
+ }, {
+ baseIdKey: 'sendToMarkedSpot',
+ translationIdForText: 'MOVE_TO_MARKED_SPOT',
+ action: that.sendToMarkedSpot_.bind(that),
+ isDisabled: function() {
+ return !that.clipboardService.isMovableToMarkedConnection(
+ that.block);
+ }
+ }, {
+ baseIdKey: 'delete',
+ translationIdForText: 'DELETE',
+ action: that.deleteBlock_.bind(that),
+ isDisabled: function() {
+ return false;
+ }
+ }];
+
+ // Make a list of all the id keys.
+ this.idKeys = ['blockRoot', 'blockSummary', 'listItem', 'label'];
+ this.actionButtonsInfo.forEach(function(buttonInfo) {
+ that.idKeys.push(buttonInfo.baseIdKey, buttonInfo.baseIdKey + 'Button');
+ });
for (var i = 0; i < this.block.inputList.length; i++) {
var inputBlock = this.block.inputList[i];
if (inputBlock.connection && !inputBlock.connection.targetBlock()) {
- elementsNeedingIds = elementsNeedingIds.concat(
- ['inputList' + i, 'inputMenuLabel' + i, 'markSpot' + i,
- 'markSpotButton' + i, 'paste' + i, 'pasteButton' + i]);
+ that.idKeys.push(
+ 'inputList' + i, 'inputMenuLabel' + i, 'markSpot' + i,
+ 'markSpotButton' + i, 'paste' + i, 'pasteButton' + i);
}
}
-
- return elementsNeedingIds;
},
- ngOnInit: function() {
- var elementsNeedingIds = this.getElementsNeedingIds_();
-
- this.idMap = {}
- this.idMap['parentList'] = this.utilsService.generateUniqueId();
- for (var i = 0; i < elementsNeedingIds.length; i++) {
- this.idMap[elementsNeedingIds[i]] =
- this.block.id + elementsNeedingIds[i];
+ ngDoCheck: function() {
+ // Generate a unique id for each id key. This needs to be done every time
+ // changes happen, but after the first ng-init, in order to force the
+ // element ids to change in cases where, e.g., a block is inserted in the
+ // middle of a sequence of blocks.
+ this.idMap = {};
+ for (var i = 0; i < this.idKeys.length; i++) {
+ this.idMap[this.idKeys[i]] = this.block.id + this.idKeys[i];
}
},
ngAfterViewInit: function() {
@@ -177,80 +270,16 @@ blocklyApp.WorkspaceTreeComponent = ng.core
if (this.tree && this.isTopLevel && !this.tree.id) {
this.tree.id = this.utilsService.generateUniqueId();
}
-
if (this.tree && this.isTopLevel &&
!this.treeService.getActiveDescId(this.tree.id)) {
- this.treeService.setActiveDesc(
- document.getElementById(this.idMap['parentList']),
- this.tree);
- }
- },
- hasPreviousConnection: function(block) {
- return Boolean(block.previousConnection);
- },
- hasNextConnection: function(block) {
- return Boolean(block.nextConnection);
- },
- isCompatibleWithClipboard: function(connection) {
- return this.clipboardService.isClipboardCompatibleWithConnection(
- connection);
- },
- isTopLevelBlock: function(block) {
- return blocklyApp.workspace.topBlocks_.some(function(topBlock) {
- return topBlock.id == block.id;
- });
- },
- pasteAbove: function(block) {
- var that = this;
- this.treeService.runWhilePreservingFocus(function() {
- that.clipboardService.pasteFromClipboard(block.previousConnection);
- }, this.tree.id);
- },
- pasteBelow: function(block) {
- var that = this;
- this.treeService.runWhilePreservingFocus(function() {
- that.clipboardService.pasteFromClipboard(block.nextConnection);
- }, this.tree.id);
- },
- cutToClipboard: function(block) {
- if (this.isTopLevelBlock(block)) {
- nextNodeToFocusOn = this.treeService.getNodeToFocusOnWhenTreeIsDeleted(
- this.tree.id);
- this.clipboardService.cut(block);
- nextNodeToFocusOn.focus();
- } else {
- // TODO(sll): Change the active descendant of the tree.
- this.clipboardService.cut(block);
- }
- },
- deleteBlock: function(block) {
- if (this.isTopLevelBlock(block)) {
- nextNodeToFocusOn = this.treeService.getNodeToFocusOnWhenTreeIsDeleted(
- this.tree.id);
- block.dispose(true);
- nextNodeToFocusOn.focus();
- } else {
- // TODO(sll): Change the active descendant of the tree.
- block.dispose(true);
+ this.treeService.setActiveDesc(this.idMap['blockRoot'], this.tree.id);
}
},
generateAriaLabelledByAttr: function(mainLabel, secondLabel, isDisabled) {
return this.utilsService.generateAriaLabelledByAttr(
mainLabel, secondLabel, isDisabled);
},
- sendToMarkedSpot: function(block) {
- this.clipboardService.pasteToMarkedConnection(block, false);
-
- if (this.isTopLevelBlock(block)) {
- nextNodeToFocusOn = this.treeService.getNodeToFocusOnWhenTreeIsDeleted(
- this.tree.id);
- block.dispose(true);
- nextNodeToFocusOn.focus();
- } else {
- // TODO(sll): Change the active descendant of the tree.
- block.dispose(true);
- }
-
- alert('Block moved to marked spot: ' + block.toString());
+ isCompatibleWithClipboard: function(connection) {
+ return this.clipboardService.isCompatibleWithClipboard(connection);
}
});
diff --git a/blockly_compressed.js b/blockly_compressed.js
index c8154fd65..3a5ae9115 100644
--- a/blockly_compressed.js
+++ b/blockly_compressed.js
@@ -859,7 +859,7 @@ goog.ui.tree.TreeControl.prototype.handleMouseEvent_=function(a){goog.log.fine(t
goog.ui.tree.TreeControl.prototype.handleKeyEvent=function(a){var b;(b=this.typeAhead_.handleNavigation(a)||this.selectedItem_&&this.selectedItem_.onKeyDown(a)||this.typeAhead_.handleTypeAheadChar(a))&&a.preventDefault();return b};goog.ui.tree.TreeControl.prototype.getNodeFromEvent_=function(a){for(var b=a.target;null!=b;){if(a=goog.ui.tree.BaseNode.allNodes[b.id])return a;if(b==this.getElement())break;b=b.parentNode}return null};
goog.ui.tree.TreeControl.prototype.createNode=function(a){return new goog.ui.tree.TreeNode(a||goog.html.SafeHtml.EMPTY,this.getConfig(),this.getDomHelper())};goog.ui.tree.TreeControl.prototype.setNode=function(a){this.typeAhead_.setNodeInMap(a)};goog.ui.tree.TreeControl.prototype.removeNode=function(a){this.typeAhead_.removeNodeFromMap(a)};goog.ui.tree.TreeControl.prototype.clearTypeAhead=function(){this.typeAhead_.clear()};goog.ui.tree.TreeControl.defaultConfig=goog.ui.tree.BaseNode.defaultConfig;
// Copyright 2013 Google Inc. Apache License 2.0
-var Blockly={Blocks:{}};
+var Blockly={Blocks:{}};Blockly.Blocks.ONE_BASED_INDEXING=!0;
// Copyright 2012 Google Inc. Apache License 2.0
Blockly.Workspace=function(a){this.id=Blockly.genUid();Blockly.Workspace.WorkspaceDB_[this.id]=this;this.options=a||{};this.RTL=!!this.options.RTL;this.horizontalLayout=!!this.options.horizontalLayout;this.toolboxPosition=this.options.toolboxPosition;this.topBlocks_=[];this.listeners_=[];this.undoStack_=[];this.redoStack_=[];this.blockDB_=Object.create(null)};Blockly.Workspace.prototype.rendered=!1;Blockly.Workspace.prototype.MAX_UNDO=1024;
Blockly.Workspace.prototype.dispose=function(){this.listeners_.length=0;this.clear();delete Blockly.Workspace.WorkspaceDB_[this.id]};Blockly.Workspace.SCAN_ANGLE=3;Blockly.Workspace.prototype.addTopBlock=function(a){this.topBlocks_.push(a)};Blockly.Workspace.prototype.removeTopBlock=function(a){for(var b=!1,c,d=0;c=this.topBlocks_[d];d++)if(c==a){this.topBlocks_.splice(d,1);b=!0;break}if(!b)throw"Block not present in workspace's list of top-most blocks.";};
@@ -889,7 +889,7 @@ Blockly.Bubble.prototype.renderArrow_=function(){var a=[],b=this.width_/2,c=this
p*d,e=c+p*e,p=b+h*m,l=c+h*k,b=b-h*m,c=c-h*k,k=g+this.arrow_radians_;k>2*Math.PI&&(k-=2*Math.PI);g=Math.sin(k)*f/Blockly.Bubble.ARROW_BEND;f=Math.cos(k)*f/Blockly.Bubble.ARROW_BEND;a.push("M"+p+","+l);a.push("C"+(p+f)+","+(l+g)+" "+d+","+e+" "+d+","+e);a.push("C"+d+","+e+" "+(b+f)+","+(c+g)+" "+b+","+c)}a.push("z");this.bubbleArrow_.setAttribute("d",a.join(" "))};Blockly.Bubble.prototype.setColour=function(a){this.bubbleBack_.setAttribute("fill",a);this.bubbleArrow_.setAttribute("fill",a)};
Blockly.Bubble.prototype.dispose=function(){Blockly.Bubble.unbindDragEvents_();goog.dom.removeNode(this.bubbleGroup_);this.shape_=this.content_=this.workspace_=this.resizeGroup_=this.bubbleBack_=this.bubbleArrow_=this.bubbleGroup_=null};Blockly.Icon=function(a){this.block_=a};Blockly.Icon.prototype.collapseHidden=!0;Blockly.Icon.prototype.SIZE=17;Blockly.Icon.prototype.bubble_=null;Blockly.Icon.prototype.iconXY_=null;Blockly.Icon.prototype.createIcon=function(){this.iconGroup_||(this.iconGroup_=Blockly.createSvgElement("g",{"class":"blocklyIconGroup"},null),this.drawIcon_(this.iconGroup_),this.block_.getSvgRoot().appendChild(this.iconGroup_),Blockly.bindEvent_(this.iconGroup_,"mouseup",this,this.iconClick_),this.updateEditable())};
Blockly.Icon.prototype.dispose=function(){goog.dom.removeNode(this.iconGroup_);this.iconGroup_=null;this.setVisible(!1);this.block_=null};Blockly.Icon.prototype.updateEditable=function(){this.block_.isInFlyout||!this.block_.isEditable()?Blockly.addClass_(this.iconGroup_,"blocklyIconGroupReadonly"):Blockly.removeClass_(this.iconGroup_,"blocklyIconGroupReadonly")};Blockly.Icon.prototype.isVisible=function(){return!!this.bubble_};
-Blockly.Icon.prototype.iconClick_=function(a){Blockly.dragMode_!=Blockly.DRAG_FREE&&(this.block_.isInFlyout||Blockly.isRightButton(a)||this.setVisible(!this.isVisible()))};Blockly.Icon.prototype.updateColour=function(){this.isVisible()&&this.bubble_.setColour(this.block_.getColour())};
+Blockly.Icon.prototype.iconClick_=function(a){this.block_.workspace.isDragging()||this.block_.isInFlyout||Blockly.isRightButton(a)||this.setVisible(!this.isVisible())};Blockly.Icon.prototype.updateColour=function(){this.isVisible()&&this.bubble_.setColour(this.block_.getColour())};
Blockly.Icon.prototype.renderIcon=function(a){if(this.collapseHidden&&this.block_.isCollapsed())return this.iconGroup_.setAttribute("display","none"),a;this.iconGroup_.setAttribute("display","block");var b=this.SIZE;this.block_.RTL&&(a-=b);this.iconGroup_.setAttribute("transform","translate("+a+",5)");this.computeIconLocation();return a=this.block_.RTL?a-Blockly.BlockSvg.SEP_SPACE_X:a+(b+Blockly.BlockSvg.SEP_SPACE_X)};
Blockly.Icon.prototype.setIconLocation=function(a){this.iconXY_=a;this.isVisible()&&this.bubble_.setAnchorLocation(a)};Blockly.Icon.prototype.computeIconLocation=function(){var a=this.block_.getRelativeToSurfaceXY(),b=Blockly.getRelativeXY_(this.iconGroup_),a=new goog.math.Coordinate(a.x+b.x+this.SIZE/2,a.y+b.y+this.SIZE/2);goog.math.Coordinate.equals(this.getIconLocation(),a)||this.setIconLocation(a)};Blockly.Icon.prototype.getIconLocation=function(){return this.iconXY_};
// Copyright 2011 Google Inc. Apache License 2.0
@@ -924,13 +924,14 @@ Blockly.Field.prototype.setSourceBlock=function(a){goog.asserts.assert(!this.sou
Blockly.Field.prototype.init=function(){this.fieldGroup_||(this.fieldGroup_=Blockly.createSvgElement("g",{},null),this.visible_||(this.fieldGroup_.style.display="none"),this.borderRect_=Blockly.createSvgElement("rect",{rx:4,ry:4,x:-Blockly.BlockSvg.SEP_SPACE_X/2,y:0,height:16},this.fieldGroup_,this.sourceBlock_.workspace),this.textElement_=Blockly.createSvgElement("text",{"class":"blocklyText",y:this.size_.height-12.5},this.fieldGroup_),this.updateEditable(),this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_),
this.mouseUpWrapper_=Blockly.bindEvent_(this.fieldGroup_,"mouseup",this,this.onMouseUp_),this.updateTextNode_())};Blockly.Field.prototype.dispose=function(){this.mouseUpWrapper_&&(Blockly.unbindEvent_(this.mouseUpWrapper_),this.mouseUpWrapper_=null);this.sourceBlock_=null;goog.dom.removeNode(this.fieldGroup_);this.validator_=this.borderRect_=this.textElement_=this.fieldGroup_=null};
Blockly.Field.prototype.updateEditable=function(){this.EDITABLE&&this.sourceBlock_&&(this.sourceBlock_.isEditable()?(Blockly.addClass_(this.fieldGroup_,"blocklyEditableText"),Blockly.removeClass_(this.fieldGroup_,"blocklyNoNEditableText"),this.fieldGroup_.style.cursor=this.CURSOR):(Blockly.addClass_(this.fieldGroup_,"blocklyNonEditableText"),Blockly.removeClass_(this.fieldGroup_,"blocklyEditableText"),this.fieldGroup_.style.cursor=""))};Blockly.Field.prototype.isVisible=function(){return this.visible_};
-Blockly.Field.prototype.setVisible=function(a){if(this.visible_!=a){this.visible_=a;var b=this.getSvgRoot();b&&(b.style.display=a?"block":"none",this.render_())}};Blockly.Field.prototype.setValidator=function(a){this.validator_=a};Blockly.Field.prototype.getValidator=function(){return this.validator_};Blockly.Field.prototype.getSvgRoot=function(){return this.fieldGroup_};
+Blockly.Field.prototype.setVisible=function(a){if(this.visible_!=a){this.visible_=a;var b=this.getSvgRoot();b&&(b.style.display=a?"block":"none",this.render_())}};Blockly.Field.prototype.setValidator=function(a){this.validator_=a};Blockly.Field.prototype.getValidator=function(){return this.validator_};
+Blockly.Field.prototype.callValidator=function(a){for(var b=[this.getValidator()],c=this.constructor;c;)b.unshift(c.classValidator),c=c.superClass_;for(c=0;cthis.maxDisplayLength&&(a=a.substring(0,this.maxDisplayLength-2)+"\u2026");goog.dom.removeChildren(this.textElement_);a=a.replace(/\s/g,Blockly.Field.NBSP);this.sourceBlock_.RTL&&a&&(a+="\u200f");a||(a=Blockly.Field.NBSP);a=document.createTextNode(a);this.textElement_.appendChild(a);this.size_.width=0}};Blockly.Field.prototype.getValue=function(){return this.getText()};
Blockly.Field.prototype.setValue=function(a){if(null!==a){var b=this.getValue();b!=a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.Change(this.sourceBlock_,"field",this.name,b,a)),this.setText(a))}};
-Blockly.Field.prototype.onMouseUp_=function(a){if(!goog.userAgent.IPHONE&&!goog.userAgent.IPAD||goog.userAgent.isVersionOrHigher("537.51.2")||0===a.layerX||0===a.layerY)Blockly.isRightButton(a)||Blockly.dragMode_!=Blockly.DRAG_FREE&&this.sourceBlock_.isEditable()&&this.showEditor_()};Blockly.Field.prototype.setTooltip=function(a){};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Tooltip={};Blockly.Tooltip.visible=!1;Blockly.Tooltip.LIMIT=50;Blockly.Tooltip.mouseOutPid_=0;Blockly.Tooltip.showPid_=0;Blockly.Tooltip.lastX_=0;Blockly.Tooltip.lastY_=0;Blockly.Tooltip.element_=null;Blockly.Tooltip.poisonedElement_=null;Blockly.Tooltip.OFFSET_X=0;Blockly.Tooltip.OFFSET_Y=10;Blockly.Tooltip.RADIUS_OK=10;Blockly.Tooltip.HOVER_MS=750;Blockly.Tooltip.MARGINS=5;Blockly.Tooltip.DIV=null;
+Blockly.Field.prototype.onMouseUp_=function(a){if(!goog.userAgent.IPHONE&&!goog.userAgent.IPAD||goog.userAgent.isVersionOrHigher("537.51.2")||0===a.layerX||0===a.layerY)Blockly.isRightButton(a)||this.sourceBlock_.workspace.isDragging()||this.sourceBlock_.isEditable()&&this.showEditor_()};Blockly.Field.prototype.setTooltip=function(a){};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Tooltip={};Blockly.Tooltip.visible=!1;Blockly.Tooltip.LIMIT=50;Blockly.Tooltip.mouseOutPid_=0;Blockly.Tooltip.showPid_=0;Blockly.Tooltip.lastX_=0;Blockly.Tooltip.lastY_=0;Blockly.Tooltip.element_=null;Blockly.Tooltip.poisonedElement_=null;Blockly.Tooltip.OFFSET_X=0;Blockly.Tooltip.OFFSET_Y=10;Blockly.Tooltip.RADIUS_OK=10;Blockly.Tooltip.HOVER_MS=750;Blockly.Tooltip.MARGINS=5;Blockly.Tooltip.DIV=null;
Blockly.Tooltip.createDom=function(){Blockly.Tooltip.DIV||(Blockly.Tooltip.DIV=goog.dom.createDom("div","blocklyTooltipDiv"),document.body.appendChild(Blockly.Tooltip.DIV))};Blockly.Tooltip.bindMouseEvents=function(a){Blockly.bindEvent_(a,"mouseover",null,Blockly.Tooltip.onMouseOver_);Blockly.bindEvent_(a,"mouseout",null,Blockly.Tooltip.onMouseOut_);Blockly.bindEvent_(a,"mousemove",null,Blockly.Tooltip.onMouseMove_)};
Blockly.Tooltip.onMouseOver_=function(a){for(a=a.target;!goog.isString(a.tooltip)&&!goog.isFunction(a.tooltip);)a=a.tooltip;Blockly.Tooltip.element_!=a&&(Blockly.Tooltip.hide(),Blockly.Tooltip.poisonedElement_=null,Blockly.Tooltip.element_=a);clearTimeout(Blockly.Tooltip.mouseOutPid_)};Blockly.Tooltip.onMouseOut_=function(a){Blockly.Tooltip.mouseOutPid_=setTimeout(function(){Blockly.Tooltip.element_=null;Blockly.Tooltip.poisonedElement_=null;Blockly.Tooltip.hide()},1);clearTimeout(Blockly.Tooltip.showPid_)};
Blockly.Tooltip.onMouseMove_=function(a){if(Blockly.Tooltip.element_&&Blockly.Tooltip.element_.tooltip&&Blockly.dragMode_==Blockly.DRAG_NONE&&!Blockly.WidgetDiv.isVisible())if(Blockly.Tooltip.visible){var b=Blockly.Tooltip.lastX_-a.pageX;a=Blockly.Tooltip.lastY_-a.pageY;Math.sqrt(b*b+a*a)>Blockly.Tooltip.RADIUS_OK&&Blockly.Tooltip.hide()}else Blockly.Tooltip.poisonedElement_!=Blockly.Tooltip.element_&&(clearTimeout(Blockly.Tooltip.showPid_),Blockly.Tooltip.lastX_=a.pageX,Blockly.Tooltip.lastY_=a.pageY,
@@ -997,13 +998,13 @@ Blockly.Xml.domToPrettyText=function(a){a=Blockly.Xml.domToText(a).split("<");fo
Blockly.Xml.textToDom=function(a){(a=(new DOMParser).parseFromString(a,"text/xml"))&&a.firstChild&&"xml"==a.firstChild.nodeName.toLowerCase()&&a.firstChild===a.lastChild||goog.asserts.fail("Blockly.Xml.textToDom did not obtain a valid XML tree.");return a.firstChild};
Blockly.Xml.domToWorkspace=function(a,b){if(a instanceof Blockly.Workspace){var c=a;a=b;b=c;console.warn("Deprecated call to Blockly.Xml.domToWorkspace, swap the arguments.")}var d;b.RTL&&(d=b.getWidth());Blockly.Field.startCache();var c=a.childNodes.length,e=Blockly.Events.getGroup();e||Blockly.Events.setGroup(!0);for(var f=0;f=this.remainingCapacity())){Blockly.terminateDrag_();Blockly.Events.disable();var b=Blockly.Xml.domToBlock(a,this),c=parseInt(a.getAttribute("x"),10);a=parseInt(a.getAttribute("y"),10);if(!isNaN(c)&&!isNaN(a)){this.RTL&&(c=-c);do{for(var d=!1,e=this.getAllBlocks(),f=0,g;g=e[f];f++)if(g=g.getRelativeToSurfaceXY(),1>=Math.abs(c-g.x)&&1>=Math.abs(a-g.y)){d=!0;break}if(!d)for(e=b.getConnections_(!1),
-f=0;g=e[f];f++)if(g.closest(Blockly.SNAP_RADIUS,new goog.math.Coordinate(c,a)).connection){d=!0;break}d&&(c=this.RTL?c-Blockly.SNAP_RADIUS:c+Blockly.SNAP_RADIUS,a+=2*Blockly.SNAP_RADIUS)}while(d);b.moveBy(c,a)}Blockly.Events.enable();Blockly.Events.isEnabled()&&!b.isShadow()&&Blockly.Events.fire(new Blockly.Events.Create(b));b.select()}};
+Blockly.WorkspaceSvg.prototype.paste=function(a){if(this.rendered&&!(a.getElementsByTagName("block").length>=this.remainingCapacity())){Blockly.terminateDrag_();Blockly.Events.disable();try{var b=Blockly.Xml.domToBlock(a,this),c=parseInt(a.getAttribute("x"),10),d=parseInt(a.getAttribute("y"),10);if(!isNaN(c)&&!isNaN(d)){this.RTL&&(c=-c);do{a=!1;for(var e=this.getAllBlocks(),f=0,g;g=e[f];f++){var h=g.getRelativeToSurfaceXY();if(1>=Math.abs(c-h.x)&&1>=Math.abs(d-h.y)){a=!0;break}}if(!a)for(var k=b.getConnections_(!1),
+f=0,m;m=k[f];f++)if(m.closest(Blockly.SNAP_RADIUS,new goog.math.Coordinate(c,d)).connection){a=!0;break}a&&(c=this.RTL?c-Blockly.SNAP_RADIUS:c+Blockly.SNAP_RADIUS,d+=2*Blockly.SNAP_RADIUS)}while(a);b.moveBy(c,d)}}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&!b.isShadow()&&Blockly.Events.fire(new Blockly.Events.Create(b));b.select()}};
Blockly.WorkspaceSvg.prototype.recordDeleteAreas=function(){this.deleteAreaTrash_=this.trashcan?this.trashcan.getClientRect():null;this.deleteAreaToolbox_=this.flyout_?this.flyout_.getClientRect():this.toolbox_?this.toolbox_.getClientRect():null};
Blockly.WorkspaceSvg.prototype.isDeleteArea=function(a){a=new goog.math.Coordinate(a.clientX,a.clientY);if(this.deleteAreaTrash_){if(this.deleteAreaTrash_.contains(a))return this.trashcan.setOpen_(!0),Blockly.Css.setCursor(Blockly.Css.Cursor.DELETE),!0;this.trashcan.setOpen_(!1)}if(this.deleteAreaToolbox_&&this.deleteAreaToolbox_.contains(a))return Blockly.Css.setCursor(Blockly.Css.Cursor.DELETE),!0;Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED);return!1};
Blockly.WorkspaceSvg.prototype.onMouseDown_=function(a){this.markFocused();Blockly.isTargetInput_(a)||(Blockly.terminateDrag_(),Blockly.hideChaff(),a.target&&a.target.nodeName&&("svg"==a.target.nodeName.toLowerCase()||a.target==this.svgBackground_)&&Blockly.selected&&!this.options.readOnly&&Blockly.selected.unselect(),Blockly.isRightButton(a)?this.showContextMenu_(a):this.scrollbar&&(this.isScrolling=!0,this.startDragMouseX=a.clientX,this.startDragMouseY=a.clientY,this.startDragMetrics=this.getMetrics(),
this.startScrollX=this.scrollX,this.startScrollY=this.scrollY,"mouseup"in Blockly.bindEvent_.TOUCH_MAP&&(Blockly.onTouchUpWrapper_=Blockly.onTouchUpWrapper_||[],Blockly.onTouchUpWrapper_=Blockly.onTouchUpWrapper_.concat(Blockly.bindEvent_(document,"mouseup",null,Blockly.onMouseUp_))),Blockly.onMouseMoveWrapper_=Blockly.onMouseMoveWrapper_||[],Blockly.onMouseMoveWrapper_=Blockly.onMouseMoveWrapper_.concat(Blockly.bindEvent_(document,"mousemove",null,Blockly.onMouseMove_))),a.stopPropagation(),a.preventDefault())};
Blockly.WorkspaceSvg.prototype.startDrag=function(a,b){var c=Blockly.mouseToSvg(a,this.getParentSvg(),this.getInverseScreenCTM());c.x/=this.scale;c.y/=this.scale;this.dragDeltaXY_=goog.math.Coordinate.difference(b,c)};Blockly.WorkspaceSvg.prototype.moveDrag=function(a){a=Blockly.mouseToSvg(a,this.getParentSvg(),this.getInverseScreenCTM());a.x/=this.scale;a.y/=this.scale;return goog.math.Coordinate.sum(this.dragDeltaXY_,a)};
-Blockly.WorkspaceSvg.prototype.onMouseWheel_=function(a){Blockly.terminateDrag_();var b=0b.bottomRight.x&&(b.bottomRight.x=d.bottomRight.x);d.topLeft.yb.bottomRight.y&&(b.bottomRight.y=d.bottomRight.y)}return{x:b.topLeft.x,y:b.topLeft.y,width:b.bottomRight.x-
+Blockly.WorkspaceSvg.prototype.isDragging=function(){return Blockly.dragMode_==Blockly.DRAG_FREE||this.isScrolling};Blockly.WorkspaceSvg.prototype.onMouseWheel_=function(a){Blockly.terminateDrag_();var b=0b.bottomRight.x&&(b.bottomRight.x=d.bottomRight.x);d.topLeft.yb.bottomRight.y&&(b.bottomRight.y=d.bottomRight.y)}return{x:b.topLeft.x,y:b.topLeft.y,width:b.bottomRight.x-
b.topLeft.x,height:b.bottomRight.y-b.topLeft.y}};Blockly.WorkspaceSvg.prototype.cleanUp_=function(){Blockly.Events.setGroup(!0);for(var a=this.getTopBlocks(!0),b=0,c=0,d;d=a[c];c++){var e=d.getRelativeToSurfaceXY();d.moveBy(-e.x,b-e.y);d.snapToGrid();b=d.getRelativeToSurfaceXY().y+d.getHeightWidth().height+Blockly.BlockSvg.MIN_BLOCK_Y}Blockly.Events.setGroup(!1);Blockly.resizeSvgContents(this)};
Blockly.WorkspaceSvg.prototype.showContextMenu_=function(a){function b(a){if(a.isDeletable())l=l.concat(a.getDescendants());else{a=a.getChildren();for(var c=0;c=b.height&&(k-=f.height);c?f.width>=a.clientX&&(g+=f.width):a.clientX+f.width>=b.width&&(g-=f.width);Blockly.WidgetDiv.position(g,k,b,e,c);d.setAllowAutoFocus(!0);setTimeout(function(){h.focus()},1);Blockly.ContextMenu.currentBlock=null}else Blockly.ContextMenu.hide()};
Blockly.ContextMenu.hide=function(){Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu);Blockly.ContextMenu.currentBlock=null};
-Blockly.ContextMenu.callbackFactory=function(a,b){return function(){Blockly.Events.disable();var c=Blockly.Xml.domToBlock(b,a.workspace),d=a.getRelativeToSurfaceXY();d.x=a.RTL?d.x-Blockly.SNAP_RADIUS:d.x+Blockly.SNAP_RADIUS;d.y+=2*Blockly.SNAP_RADIUS;c.moveBy(d.x,d.y);Blockly.Events.enable();Blockly.Events.isEnabled()&&!c.isShadow()&&Blockly.Events.fire(new Blockly.Events.Create(c));c.select()}};Blockly.RenderedConnection=function(a,b){Blockly.RenderedConnection.superClass_.constructor.call(this,a,b);this.offsetInBlock_=new goog.math.Coordinate(0,0)};goog.inherits(Blockly.RenderedConnection,Blockly.Connection);Blockly.RenderedConnection.prototype.distanceFrom=function(a){var b=this.x_-a.x_;a=this.y_-a.y_;return Math.sqrt(b*b+a*a)};
+Blockly.ContextMenu.callbackFactory=function(a,b){return function(){Blockly.Events.disable();try{var c=Blockly.Xml.domToBlock(b,a.workspace),d=a.getRelativeToSurfaceXY();d.x=a.RTL?d.x-Blockly.SNAP_RADIUS:d.x+Blockly.SNAP_RADIUS;d.y+=2*Blockly.SNAP_RADIUS;c.moveBy(d.x,d.y)}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&!c.isShadow()&&Blockly.Events.fire(new Blockly.Events.Create(c));c.select()}};Blockly.RenderedConnection=function(a,b){Blockly.RenderedConnection.superClass_.constructor.call(this,a,b);this.offsetInBlock_=new goog.math.Coordinate(0,0)};goog.inherits(Blockly.RenderedConnection,Blockly.Connection);Blockly.RenderedConnection.prototype.distanceFrom=function(a){var b=this.x_-a.x_;a=this.y_-a.y_;return Math.sqrt(b*b+a*a)};
Blockly.RenderedConnection.prototype.bumpAwayFrom_=function(a){if(Blockly.dragMode_==Blockly.DRAG_NONE){var b=this.sourceBlock_.getRootBlock();if(!b.isInFlyout){var c=!1;if(!b.isMovable()){b=a.getSourceBlock().getRootBlock();if(!b.isMovable())return;a=this;c=!0}var d=Blockly.selected==b;d||b.select();var e=a.x_+Blockly.SNAP_RADIUS-this.x_;a=a.y_+Blockly.SNAP_RADIUS-this.y_;c&&(a=-a);b.RTL&&(e=-e);b.moveBy(e,a);d||b.unselect()}}};
Blockly.RenderedConnection.prototype.moveTo=function(a,b){this.inDB_&&this.db_.removeConnection_(this);this.x_=a;this.y_=b;this.hidden_||this.db_.addConnection(this)};Blockly.RenderedConnection.prototype.moveBy=function(a,b){this.moveTo(this.x_+a,this.y_+b)};Blockly.RenderedConnection.prototype.moveToOffset=function(a){this.moveTo(a.x+this.offsetInBlock_.x,a.y+this.offsetInBlock_.y)};
Blockly.RenderedConnection.prototype.setOffsetInBlock=function(a,b){this.offsetInBlock_.x=a;this.offsetInBlock_.y=b};Blockly.RenderedConnection.prototype.tighten_=function(){var a=this.targetConnection.x_-this.x_,b=this.targetConnection.y_-this.y_;if(0!=a||0!=b){var c=this.targetBlock(),d=c.getSvgRoot();if(!d)throw"block is not rendered.";d=Blockly.getRelativeXY_(d);c.getSvgRoot().setAttribute("transform","translate("+(d.x-a)+","+(d.y-b)+")");c.moveConnections_(-a,-b)}};
@@ -1120,13 +1121,14 @@ Blockly.RenderedConnection.prototype.closest=function(a,b,c){return this.dbOppos
Blockly.RenderedConnection.prototype.highlight=function(){var a;a=this.type==Blockly.INPUT_VALUE||this.type==Blockly.OUTPUT_VALUE?"m 0,0 "+Blockly.BlockSvg.TAB_PATH_DOWN+" v 5":"m -20,0 h 5 "+Blockly.BlockSvg.NOTCH_PATH_LEFT+" h 5";var b=this.sourceBlock_.getRelativeToSurfaceXY();Blockly.Connection.highlightedPath_=Blockly.createSvgElement("path",{"class":"blocklyHighlightedConnectionPath",d:a,transform:"translate("+(this.x_-b.x)+","+(this.y_-b.y)+")"+(this.sourceBlock_.RTL?" scale(-1 1)":"")},this.sourceBlock_.getSvgRoot())};
Blockly.RenderedConnection.prototype.unhideAll=function(){this.setHidden(!1);var a=[];if(this.type!=Blockly.INPUT_VALUE&&this.type!=Blockly.NEXT_STATEMENT)return a;var b=this.targetBlock();if(b){var c;b.isCollapsed()?(c=[],b.outputConnection&&c.push(b.outputConnection),b.nextConnection&&c.push(b.nextConnection),b.previousConnection&&c.push(b.previousConnection)):c=b.getConnections_(!0);for(var d=0;db?!1:Blockly.RenderedConnection.superClass_.isConnectionAllowed.call(this,a)};
+Blockly.RenderedConnection.prototype.hideAll=function(){this.setHidden(!0);if(this.targetConnection)for(var a=this.targetBlock().getDescendants(),b=0;bb?!1:Blockly.RenderedConnection.superClass_.isConnectionAllowed.call(this,a)};
Blockly.RenderedConnection.prototype.disconnectInternal_=function(a,b){Blockly.RenderedConnection.superClass_.disconnectInternal_.call(this,a,b);a.rendered&&a.render();b.rendered&&(b.updateDisabled(),b.render())};
Blockly.RenderedConnection.prototype.respawnShadow_=function(){var a=this.getSourceBlock(),b=this.getShadowDom();if(a.workspace&&b&&Blockly.Events.recordUndo){Blockly.RenderedConnection.superClass_.respawnShadow_.call(this);b=this.targetBlock();if(!b)throw"Couldn't respawn the shadow block that should exist here.";b.initSvg();b.render(!1);a.rendered&&a.render()}};Blockly.RenderedConnection.prototype.neighbours_=function(a){return this.dbOpposite_.getNeighbours(this,a)};
Blockly.RenderedConnection.prototype.connect_=function(a){Blockly.RenderedConnection.superClass_.connect_.call(this,a);var b=this.getSourceBlock();a=a.getSourceBlock();b.rendered&&b.updateDisabled();a.rendered&&a.updateDisabled();b.rendered&&a.rendered&&(this.type==Blockly.NEXT_STATEMENT||this.type==Blockly.PREVIOUS_STATEMENT?a.render():b.render())};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.createSvgElement("g",{},null);this.svgPathDark_=Blockly.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;Blockly.Tooltip.bindMouseEvents(this.svgPath_);Blockly.BlockSvg.superClass_.constructor.call(this,
a,b,c)};goog.inherits(Blockly.BlockSvg,Blockly.Block);Blockly.BlockSvg.prototype.height=0;Blockly.BlockSvg.prototype.width=0;Blockly.BlockSvg.prototype.dragStartXY_=null;Blockly.BlockSvg.INLINE=-1;
Blockly.BlockSvg.prototype.initSvg=function(){goog.asserts.assert(this.workspace.rendered,"Workspace is headless.");for(var a=0,b;b=this.inputList[a];a++)b.init();b=this.getIcons();for(a=0;ac;c+=15)Blockly.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS-
(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);a.style.marginLeft=15-Blockly.FieldAngle.RADIUS+"px";this.clickWrapper_=Blockly.bindEvent_(a,"click",this,Blockly.WidgetDiv.hide);this.moveWrapper1_=Blockly.bindEvent_(b,"mousemove",this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()}};
@@ -1253,40 +1253,37 @@ Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGE
b,this.setValue(b),this.validate_(),this.resizeEditor_())};Blockly.FieldAngle.prototype.setText=function(a){Blockly.FieldAngle.superClass_.setText.call(this,a);this.textElement_&&(this.updateGraph_(),this.sourceBlock_.RTL?this.textElement_.insertBefore(this.symbol_,this.textElement_.firstChild):this.textElement_.appendChild(this.symbol_),this.size_.width=0)};
Blockly.FieldAngle.prototype.updateGraph_=function(){if(this.gauge_){var a=Number(this.getText())+Blockly.FieldAngle.OFFSET,b=goog.math.toRadians(a),a=["M ",Blockly.FieldAngle.HALF,",",Blockly.FieldAngle.HALF],c=Blockly.FieldAngle.HALF,d=Blockly.FieldAngle.HALF;if(!isNaN(b)){var e=goog.math.toRadians(Blockly.FieldAngle.OFFSET),f=Math.cos(e)*Blockly.FieldAngle.RADIUS,g=Math.sin(e)*-Blockly.FieldAngle.RADIUS;Blockly.FieldAngle.CLOCKWISE&&(b=2*e-b);c+=Math.cos(b)*Blockly.FieldAngle.RADIUS;d-=Math.sin(b)*
Blockly.FieldAngle.RADIUS;b=Math.abs(Math.floor((b-e)/Math.PI)%2);Blockly.FieldAngle.CLOCKWISE&&(b=1-b);a.push(" l ",f,",",g," A ",Blockly.FieldAngle.RADIUS,",",Blockly.FieldAngle.RADIUS," 0 ",b," ",Number(Blockly.FieldAngle.CLOCKWISE)," ",c,",",d," z")}this.gauge_.setAttribute("d",a.join(""));this.line_.setAttribute("x2",c);this.line_.setAttribute("y2",d)}};
-Blockly.FieldAngle.angleValidator=function(a){if(null===a)return null;a=parseFloat(a||0);if(isNaN(a))return null;a%=360;0>a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return String(a)};Blockly.FieldCheckbox=function(a,b){Blockly.FieldCheckbox.superClass_.constructor.call(this,"",b);this.setValue(a)};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.prototype.CURSOR="default";
+Blockly.FieldAngle.classValidator=function(a){if(null===a)return null;a=parseFloat(a||0);if(isNaN(a))return null;a%=360;0>a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return String(a)};Blockly.FieldCheckbox=function(a,b){Blockly.FieldCheckbox.superClass_.constructor.call(this,"",b);this.setValue(a)};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.prototype.CURSOR="default";
Blockly.FieldCheckbox.prototype.init=function(){if(!this.fieldGroup_){Blockly.FieldCheckbox.superClass_.init.call(this);this.checkElement_=Blockly.createSvgElement("text",{"class":"blocklyText blocklyCheckbox",x:-3,y:14},this.fieldGroup_);var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.checkElement_.appendChild(a);this.checkElement_.style.display=this.state_?"block":"none"}};Blockly.FieldCheckbox.prototype.getValue=function(){return String(this.state_).toUpperCase()};
-Blockly.FieldCheckbox.prototype.setValue=function(a){a="TRUE"==a;this.state_!==a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.Change(this.sourceBlock_,"field",this.name,this.state_,a)),this.state_=a,this.checkElement_&&(this.checkElement_.style.display=a?"block":"none"))};Blockly.FieldCheckbox.prototype.showEditor_=function(){var a=!this.state_;if(this.sourceBlock_&&this.validator_){var b=this.validator_(a);void 0!==b&&(a=b)}null!==a&&this.setValue(String(a).toUpperCase())};Blockly.FieldColour=function(a,b){Blockly.FieldColour.superClass_.constructor.call(this,a,b);this.setText(Blockly.Field.NBSP+Blockly.Field.NBSP+Blockly.Field.NBSP)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.prototype.colours_=null;Blockly.FieldColour.prototype.columns_=0;Blockly.FieldColour.prototype.init=function(){Blockly.FieldColour.superClass_.init.call(this);this.borderRect_.style.fillOpacity=1;this.setValue(this.getValue())};Blockly.FieldColour.prototype.CURSOR="default";
+Blockly.FieldCheckbox.prototype.setValue=function(a){a="TRUE"==a;this.state_!==a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.Change(this.sourceBlock_,"field",this.name,this.state_,a)),this.state_=a,this.checkElement_&&(this.checkElement_.style.display=a?"block":"none"))};Blockly.FieldCheckbox.prototype.showEditor_=function(){var a=!this.state_;this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(String(a).toUpperCase())};Blockly.FieldColour=function(a,b){Blockly.FieldColour.superClass_.constructor.call(this,a,b);this.setText(Blockly.Field.NBSP+Blockly.Field.NBSP+Blockly.Field.NBSP)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.prototype.colours_=null;Blockly.FieldColour.prototype.columns_=0;Blockly.FieldColour.prototype.init=function(){Blockly.FieldColour.superClass_.init.call(this);this.borderRect_.style.fillOpacity=1;this.setValue(this.getValue())};Blockly.FieldColour.prototype.CURSOR="default";
Blockly.FieldColour.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldColour.superClass_.dispose.call(this)};Blockly.FieldColour.prototype.getValue=function(){return this.colour_};Blockly.FieldColour.prototype.setValue=function(a){this.sourceBlock_&&Blockly.Events.isEnabled()&&this.colour_!=a&&Blockly.Events.fire(new Blockly.Events.Change(this.sourceBlock_,"field",this.name,this.colour_,a));this.colour_=a;this.borderRect_&&(this.borderRect_.style.fill=a)};
Blockly.FieldColour.prototype.getText=function(){var a=this.colour_,b=a.match(/^#(.)\1(.)\2(.)\3$/);b&&(a="#"+b[1]+b[2]+b[3]);return a};Blockly.FieldColour.COLOURS=goog.ui.ColorPicker.SIMPLE_GRID_COLORS;Blockly.FieldColour.COLUMNS=7;Blockly.FieldColour.prototype.setColours=function(a){this.colours_=a;return this};Blockly.FieldColour.prototype.setColumns=function(a){this.columns_=a;return this};
Blockly.FieldColour.prototype.showEditor_=function(){Blockly.WidgetDiv.show(this,this.sourceBlock_.RTL,Blockly.FieldColour.widgetDispose_);var a=new goog.ui.ColorPicker;a.setSize(this.columns_||Blockly.FieldColour.COLUMNS);a.setColors(this.colours_||Blockly.FieldColour.COLOURS);var b=goog.dom.getViewportSize(),c=goog.style.getViewportPageOffset(document),d=this.getAbsoluteXY_(),e=this.getScaledBBox_();a.render(Blockly.WidgetDiv.DIV);a.setSelectedColor(this.getValue());var f=goog.style.getSize(a.getElement());
-d.y=d.y+f.height+e.height>=b.height+c.y?d.y-(f.height-1):d.y+(e.height-1);this.sourceBlock_.RTL?(d.x+=e.width,d.x-=f.width,d.xb.width+c.x-f.width&&(d.x=b.width+c.x-f.width);Blockly.WidgetDiv.position(d.x,d.y,b,c,this.sourceBlock_.RTL);var g=this;Blockly.FieldColour.changeEventKey_=goog.events.listen(a,goog.ui.ColorPicker.EventType.CHANGE,function(a){a=a.target.getSelectedColor()||"#000000";Blockly.WidgetDiv.hide();if(g.sourceBlock_&&g.validator_){var b=g.validator_(a);void 0!==
-b&&(a=b)}null!==a&&g.setValue(a)})};Blockly.FieldColour.widgetDispose_=function(){Blockly.FieldColour.changeEventKey_&&goog.events.unlistenByKey(Blockly.FieldColour.changeEventKey_)};Blockly.FieldDropdown=function(a,b){this.menuGenerator_=a;this.trimOptions_();var c=this.getOptions_()[0];Blockly.FieldDropdown.superClass_.constructor.call(this,c[1],b)};goog.inherits(Blockly.FieldDropdown,Blockly.Field);Blockly.FieldDropdown.CHECKMARK_OVERHANG=25;Blockly.FieldDropdown.ARROW_CHAR=goog.userAgent.ANDROID?"\u25bc":"\u25be";Blockly.FieldDropdown.prototype.CURSOR="default";
+d.y=d.y+f.height+e.height>=b.height+c.y?d.y-(f.height-1):d.y+(e.height-1);this.sourceBlock_.RTL?(d.x+=e.width,d.x-=f.width,d.xb.width+c.x-f.width&&(d.x=b.width+c.x-f.width);Blockly.WidgetDiv.position(d.x,d.y,b,c,this.sourceBlock_.RTL);var g=this;Blockly.FieldColour.changeEventKey_=goog.events.listen(a,goog.ui.ColorPicker.EventType.CHANGE,function(a){a=a.target.getSelectedColor()||"#000000";Blockly.WidgetDiv.hide();g.sourceBlock_&&(a=g.callValidator(a));null!==a&&g.setValue(a)})};
+Blockly.FieldColour.widgetDispose_=function(){Blockly.FieldColour.changeEventKey_&&goog.events.unlistenByKey(Blockly.FieldColour.changeEventKey_)};Blockly.FieldDropdown=function(a,b){this.menuGenerator_=a;this.trimOptions_();var c=this.getOptions_()[0];Blockly.FieldDropdown.superClass_.constructor.call(this,c[1],b)};goog.inherits(Blockly.FieldDropdown,Blockly.Field);Blockly.FieldDropdown.CHECKMARK_OVERHANG=25;Blockly.FieldDropdown.ARROW_CHAR=goog.userAgent.ANDROID?"\u25bc":"\u25be";Blockly.FieldDropdown.prototype.CURSOR="default";
Blockly.FieldDropdown.prototype.init=function(){if(!this.fieldGroup_){this.arrow_=Blockly.createSvgElement("tspan",{},null);this.arrow_.appendChild(document.createTextNode(this.sourceBlock_.RTL?Blockly.FieldDropdown.ARROW_CHAR+" ":" "+Blockly.FieldDropdown.ARROW_CHAR));Blockly.FieldDropdown.superClass_.init.call(this);var a=this.text_;this.text_=null;this.setText(a)}};
-Blockly.FieldDropdown.prototype.showEditor_=function(){Blockly.WidgetDiv.show(this,this.sourceBlock_.RTL,null);var a=this,b=new goog.ui.Menu;b.setRightToLeft(this.sourceBlock_.RTL);for(var c=this.getOptions_(),d=0;d=c.height+d.y?e.y-(h.height+2):e.y+f.height;this.sourceBlock_.RTL?(e.x+=f.width,e.x+=Blockly.FieldDropdown.CHECKMARK_OVERHANG,e.xc.width+d.x-h.width&&(e.x=c.width+d.x-h.width));Blockly.WidgetDiv.position(e.x,e.y,c,d,this.sourceBlock_.RTL);b.setAllowAutoFocus(!0);
-g.focus()};
-Blockly.FieldDropdown.prototype.trimOptions_=function(){this.suffixField=this.prefixField=null;var a=this.menuGenerator_;if(goog.isArray(a)&&!(2>a.length)){var b=a.map(function(a){return a[0]}),c=Blockly.shortestStringLength(b),d=Blockly.commonWordPrefix(b,c),e=Blockly.commonWordSuffix(b,c);if((d||e)&&!(c<=d+e)){d&&(this.prefixField=b[0].substring(0,d-1));e&&(this.suffixField=b[0].substr(1-e));b=[];for(c=0;c=c.height+d.y?e.y-(h.height+2):e.y+f.height;this.sourceBlock_.RTL?(e.x+=f.width,e.x+=Blockly.FieldDropdown.CHECKMARK_OVERHANG,e.xc.width+d.x-h.width&&(e.x=c.width+d.x-h.width));Blockly.WidgetDiv.position(e.x,e.y,c,d,this.sourceBlock_.RTL);b.setAllowAutoFocus(!0);g.focus()};
+Blockly.FieldDropdown.prototype.trimOptions_=function(){this.suffixField=this.prefixField=null;var a=this.menuGenerator_;if(goog.isArray(a)&&!(2>a.length)){var b=a.map(function(a){return a[0]}),c=Blockly.shortestStringLength(b),d=Blockly.commonWordPrefix(b,c),e=Blockly.commonWordSuffix(b,c);if((d||e)&&!(c<=d+e)){d&&(this.prefixField=b[0].substring(0,d-1));e&&(this.suffixField=b[0].substr(1-e));b=[];for(c=0;cb.contentWidth-b.viewWidth)){var c=a.clientX-this.startDragMouseX_;this.startDragMouseX_=a.clientX;a=b.viewLeft-c;a=goog.math.clamp(a,0,b.contentWidth-b.viewWidth);this.scrollbar_.set(a)}}else 0>b.contentHeight-b.viewHeight||(c=a.clientY-this.startDragMouseY_,this.startDragMouseY_=a.clientY,a=b.viewTop-c,a=goog.math.clamp(a,0,b.contentHeight-b.viewHeight),this.scrollbar_.set(a))};
-Blockly.Flyout.prototype.onMouseMoveBlock_=function(a){if("mousemove"==a.type&&1>=a.clientX&&0==a.clientY&&0==a.button)a.stopPropagation();else{var b=a.clientX-Blockly.Flyout.startDownEvent_.clientX;a=a.clientY-Blockly.Flyout.startDownEvent_.clientY;Math.sqrt(b*b+a*a)>Blockly.DRAG_RADIUS&&Blockly.Flyout.startFlyout_.createBlockFunc_(Blockly.Flyout.startBlock_)(Blockly.Flyout.startDownEvent_)}};
-Blockly.Flyout.prototype.createBlockFunc_=function(a){var b=this;return function(c){if(!Blockly.isRightButton(c)&&!a.disabled){Blockly.Events.disable();var d=b.placeNewBlock_(a);Blockly.Events.enable();Blockly.Events.isEnabled()&&(Blockly.Events.setGroup(!0),Blockly.Events.fire(new Blockly.Events.Create(d)));b.autoClose?b.hide():b.filterForCapacity_();d.onMouseDown_(c);Blockly.dragMode_=Blockly.DRAG_FREE;d.setDragging_(!0)}}};
+Blockly.Flyout.prototype.onMouseMoveBlock_=function(a){if(!("mousemove"==a.type&&1>=a.clientX&&0==a.clientY&&0==a.button))if(this.determineDragIntention_(a.clientX-Blockly.Flyout.startDownEvent_.clientX,a.clientY-Blockly.Flyout.startDownEvent_.clientY))this.createBlockFunc_(Blockly.Flyout.startBlock_)(Blockly.Flyout.startDownEvent_);else if(this.dragMode_==Blockly.DRAG_FREE)this.onMouseMove_(a);a.stopPropagation()};
+Blockly.Flyout.prototype.determineDragIntention_=function(a,b){if(this.dragMode_==Blockly.DRAG_FREE)return!1;if(Math.sqrt(a*a+b*b)90-e&&(d=!0):c>-90-e&&c<-90+e&&(d=!0);else if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)c-e&&(d=!0);else if(c<-180+e||c>180-e)d=!0;return d};
+Blockly.Flyout.prototype.createBlockFunc_=function(a){var b=this;return function(c){if(!Blockly.isRightButton(c)&&!a.disabled){Blockly.Events.disable();try{var d=b.placeNewBlock_(a)}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&(Blockly.Events.setGroup(!0),Blockly.Events.fire(new Blockly.Events.Create(d)));b.autoClose?b.hide():b.filterForCapacity_();d.onMouseDown_(c);Blockly.dragMode_=Blockly.DRAG_FREE;d.setDragging_(!0)}}};
Blockly.Flyout.prototype.placeNewBlock_=function(a){var b=this.targetWorkspace_,c=a.getSvgRoot();if(!c)throw"originBlock is not rendered.";var c=Blockly.getSvgXY_(c,b),d=this.workspace_.scrollX,e=this.workspace_.scale;c.x+=d/e-d;this.toolboxPosition_==Blockly.TOOLBOX_AT_RIGHT&&(d=b.getMetrics().viewWidth-this.width_,e=b.scale,c.x+=d/e-d);d=this.workspace_.scrollY;e=this.workspace_.scale;c.y+=d/e-d;this.toolboxPosition_==Blockly.TOOLBOX_AT_BOTTOM&&(d=b.getMetrics().viewHeight-this.height_,e=b.scale,
c.y+=d/e-d);a=Blockly.Xml.blockToDom(a);a=Blockly.Xml.domToBlock(a,b);e=a.getSvgRoot();if(!e)throw"block is not rendered.";e=Blockly.getSvgXY_(e,b);e.x+=b.scrollX/b.scale-b.scrollX;e.y+=b.scrollY/b.scale-b.scrollY;b.toolbox_&&!b.scrollbar&&(e.x+=b.toolbox_.getWidth()/b.scale,e.y+=b.toolbox_.getHeight()/b.scale);a.moveBy(c.x-e.x,c.y-e.y);return a};
Blockly.Flyout.prototype.filterForCapacity_=function(){for(var a=this.targetWorkspace_.remainingCapacity(),b=this.workspace_.getTopBlocks(!1),c=0,d;d=b[c];c++)if(-1==this.permanentlyDisabled_.indexOf(d)){var e=d.getDescendants();d.setDisabled(e.length>a)}};
Blockly.Flyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left,c=a.top,d=a.width,a=a.height;return this.toolboxPosition_==Blockly.TOOLBOX_AT_TOP?new goog.math.Rect(-1E9,c-1E9,2E9,1E9+a):this.toolboxPosition_==Blockly.TOOLBOX_AT_BOTTOM?new goog.math.Rect(-1E9,c,2E9,1E9+a):this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT?new goog.math.Rect(b-1E9,-1E9,1E9+d,2E9):new goog.math.Rect(b,-1E9,1E9+d,2E9)};
-Blockly.Flyout.terminateDrag_=function(){Blockly.Flyout.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseUpWrapper_),Blockly.Flyout.onMouseUpWrapper_=null);Blockly.Flyout.onMouseMoveBlockWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseMoveBlockWrapper_),Blockly.Flyout.onMouseMoveBlockWrapper_=null);Blockly.Flyout.onMouseMoveWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseMoveWrapper_),Blockly.Flyout.onMouseMoveWrapper_=null);Blockly.Flyout.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseUpWrapper_),
-Blockly.Flyout.onMouseUpWrapper_=null);Blockly.Flyout.startDownEvent_=null;Blockly.Flyout.startBlock_=null;Blockly.Flyout.startFlyout_=null};
+Blockly.Flyout.terminateDrag_=function(){Blockly.Flyout.startFlyout_&&(Blockly.Flyout.startFlyout_.dragMode_=Blockly.DRAG_NONE);Blockly.Flyout.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseUpWrapper_),Blockly.Flyout.onMouseUpWrapper_=null);Blockly.Flyout.onMouseMoveBlockWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseMoveBlockWrapper_),Blockly.Flyout.onMouseMoveBlockWrapper_=null);Blockly.Flyout.onMouseMoveWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseMoveWrapper_),
+Blockly.Flyout.onMouseMoveWrapper_=null);Blockly.Flyout.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseUpWrapper_),Blockly.Flyout.onMouseUpWrapper_=null);Blockly.Flyout.startDownEvent_=null;Blockly.Flyout.startBlock_=null;Blockly.Flyout.startFlyout_=null};
Blockly.Flyout.prototype.reflowHorizontal=function(a){this.workspace_.scale=this.targetWorkspace_.scale;for(var b=0,c=0,d;d=a[c];c++)b=Math.max(b,d.getHeightWidth().height);b+=1.5*this.MARGIN;b*=this.workspace_.scale;b+=Blockly.Scrollbar.scrollbarThickness;if(this.height_!=b){for(c=0;d=a[c];c++){var e=d.getHeightWidth();if(d.flyoutRect_){d.flyoutRect_.setAttribute("width",e.width);d.flyoutRect_.setAttribute("height",e.height);var f=d.outputConnection?Blockly.BlockSvg.TAB_WIDTH:0,g=d.getRelativeToSurfaceXY();
d.flyoutRect_.setAttribute("y",g.y);d.flyoutRect_.setAttribute("x",this.RTL?g.x-e.width+f:g.x-f);(e=d.startHat_?Blockly.BlockSvg.START_HAT_HEIGHT:0)&&d.moveBy(0,e);d.flyoutRect_.setAttribute("y",g.y)}}this.height_=b;this.targetWorkspace_.resize()}};
Blockly.Flyout.prototype.reflowVertical=function(a){this.workspace_.scale=this.targetWorkspace_.scale;for(var b=0,c=0,d;d=a[c];c++){var e=d.getHeightWidth().width;d.outputConnection&&(e-=Blockly.BlockSvg.TAB_WIDTH);b=Math.max(b,e)}b+=1.5*this.MARGIN+Blockly.BlockSvg.TAB_WIDTH;b*=this.workspace_.scale;b+=Blockly.Scrollbar.scrollbarThickness;if(this.width_!=b){for(c=0;d=a[c];c++){e=d.getHeightWidth();if(this.RTL){var f=d.getRelativeToSurfaceXY().x,g=b/this.workspace_.scale-this.MARGIN,g=g-Blockly.BlockSvg.TAB_WIDTH;
@@ -1346,10 +1346,10 @@ Blockly.Toolbox.prototype.init=function(){var a=this.workspace_;this.HtmlDiv=goo
toolboxPosition:a.options.toolboxPosition});goog.dom.insertSiblingAfter(this.flyout_.createDom(),a.svgGroup_);this.flyout_.init(a);this.config_.cleardotPath=a.options.pathToMedia+"1x1.gif";this.config_.cssCollapsedFolderIcon="blocklyTreeIconClosed"+(a.RTL?"Rtl":"Ltr");var b=new Blockly.Toolbox.TreeControl(this,this.config_);this.tree_=b;b.setShowRootNode(!1);b.setShowLines(!1);b.setShowExpandIcons(!1);b.setSelectedItem(null);this.populate_(a.options.languageTree);b.render(this.HtmlDiv);this.addColour_();
this.position()};Blockly.Toolbox.prototype.dispose=function(){this.flyout_.dispose();this.tree_.dispose();goog.dom.removeNode(this.HtmlDiv);this.lastCategory_=this.workspace_=null};Blockly.Toolbox.prototype.getWidth=function(){return this.width};Blockly.Toolbox.prototype.getHeight=function(){return this.height};
Blockly.Toolbox.prototype.position=function(){var a=this.HtmlDiv;if(a){var b=this.workspace_.getParentSvg(),c=goog.style.getPageOffset(b),b=Blockly.svgSize(b);this.horizontalLayout_?(a.style.left=c.x+"px",a.style.height="auto",a.style.width=b.width+"px",this.height=a.offsetHeight,a.style.top=this.toolboxPosition==Blockly.TOOLBOX_AT_TOP?c.y+"px":c.y+b.height-a.offsetHeight+"px"):(a.style.left=this.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT?c.x+b.width-a.offsetWidth+"px":c.x+"px",a.style.height=b.height+
-"px",a.style.top=c.y+"px",this.width=a.offsetWidth,this.toolboxPosition==Blockly.TOOLBOX_AT_LEFT&&--this.width);this.flyout_.position()}};
-Blockly.Toolbox.prototype.populate_=function(a){function b(a,g,h){for(var k=null,m=0,p;p=a.childNodes[m];m++)if(p.tagName)switch(p.tagName.toUpperCase()){case "CATEGORY":k=c.createNode(p.getAttribute("name"));k.blocks=[];g.add(k);var l=p.getAttribute("custom");l?k.blocks=l:b(p,k,h);l=p.getAttribute("colour");goog.isString(l)?(l.match(/^#[0-9a-fA-F]{6}$/)?k.hexColour=l:k.hexColour=Blockly.hueToRgb(l),e=!0):k.hexColour="";"true"==p.getAttribute("expanded")?(k.blocks.length&&c.setSelectedItem(k),k.setExpanded(!0)):
-k.setExpanded(!1);k=p;break;case "SEP":k&&("CATEGORY"==k.tagName.toUpperCase()?g.add(new Blockly.Toolbox.TreeSeparator(d.treeSeparatorConfig_)):(p=parseFloat(p.getAttribute("gap")),isNaN(p)||(l=parseFloat(k.getAttribute("gap")),p=isNaN(l)?p:l+p,k.setAttribute("gap",p))));break;case "BLOCK":case "SHADOW":g.blocks.push(p),k=p}}var c=this.tree_,d=this;c.removeChildren();c.blocks=[];var e=!1;b(a,this.tree_,this.workspace_.options.pathToMedia);this.hasColours_=e;if(c.blocks.length)throw"Toolbox cannot have both blocks and categories in the root level.";
-Blockly.resizeSvgContents(this.workspace_)};Blockly.Toolbox.prototype.addColour_=function(a){a=(a||this.tree_).getChildren();for(var b=0,c;c=a[b];b++){var d=c.getRowElement();if(d){var e=this.hasColours_?"8px solid "+(c.hexColour||"#ddd"):"none";this.workspace_.RTL?d.style.borderRight=e:d.style.borderLeft=e}this.addColour_(c)}};Blockly.Toolbox.prototype.clearSelection=function(){this.tree_.setSelectedItem(null)};
+"px",a.style.top=c.y+"px",this.width=a.offsetWidth,this.toolboxPosition==Blockly.TOOLBOX_AT_LEFT&&--this.width);this.flyout_.position()}};Blockly.Toolbox.prototype.populate_=function(a){this.tree_.removeChildren();this.tree_.blocks=[];this.hasColours_=!1;this.syncTrees_(a,this.tree_,this.workspace_.options.pathToMedia);if(this.tree_.blocks.length)throw"Toolbox cannot have both blocks and categories in the root level.";Blockly.resizeSvgContents(this.workspace_)};
+Blockly.Toolbox.prototype.syncTrees_=function(a,b,c){for(var d=null,e=0,f;f=a.childNodes[e];e++)if(f.tagName)switch(f.tagName.toUpperCase()){case "CATEGORY":d=this.tree_.createNode(f.getAttribute("name"));d.blocks=[];b.add(d);var g=f.getAttribute("custom");g?d.blocks=g:this.syncTrees_(f,d,c);g=f.getAttribute("colour");goog.isString(g)?(g.match(/^#[0-9a-fA-F]{6}$/)?d.hexColour=g:d.hexColour=Blockly.hueToRgb(g),this.hasColours_=!0):d.hexColour="";"true"==f.getAttribute("expanded")?(d.blocks.length&&
+this.tree_.setSelectedItem(d),d.setExpanded(!0)):d.setExpanded(!1);d=f;break;case "SEP":d&&("CATEGORY"==d.tagName.toUpperCase()?b.add(new Blockly.Toolbox.TreeSeparator(this.treeSeparatorConfig_)):(f=parseFloat(f.getAttribute("gap")),isNaN(f)||(g=parseFloat(d.getAttribute("gap")),f=isNaN(g)?f:g+f,d.setAttribute("gap",f))));break;case "BLOCK":case "SHADOW":b.blocks.push(f),d=f}};
+Blockly.Toolbox.prototype.addColour_=function(a){a=(a||this.tree_).getChildren();for(var b=0,c;c=a[b];b++){var d=c.getRowElement();if(d){var e=this.hasColours_?"8px solid "+(c.hexColour||"#ddd"):"none";this.workspace_.RTL?d.style.borderRight=e:d.style.borderLeft=e}this.addColour_(c)}};Blockly.Toolbox.prototype.clearSelection=function(){this.tree_.setSelectedItem(null)};
Blockly.Toolbox.prototype.getClientRect=function(){if(!this.HtmlDiv)return null;var a=this.HtmlDiv.getBoundingClientRect(),b=a.left,c=a.top,d=a.width,a=a.height;return this.toolboxPosition==Blockly.TOOLBOX_AT_LEFT?new goog.math.Rect(-1E7,-1E7,1E7+b+d,2E7):this.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT?new goog.math.Rect(b,-1E7,1E7+d,2E7):this.toolboxPosition==Blockly.TOOLBOX_AT_TOP?new goog.math.Rect(-1E7,-1E7,2E7,1E7+c+a):new goog.math.Rect(0,c,2E7,1E7+d)};
Blockly.Toolbox.TreeControl=function(a,b){this.toolbox_=a;goog.ui.tree.TreeControl.call(this,goog.html.SafeHtml.EMPTY,b)};goog.inherits(Blockly.Toolbox.TreeControl,goog.ui.tree.TreeControl);Blockly.Toolbox.TreeControl.prototype.enterDocument=function(){Blockly.Toolbox.TreeControl.superClass_.enterDocument.call(this);if(goog.events.BrowserFeature.TOUCH_ENABLED){var a=this.getElement();Blockly.bindEvent_(a,goog.events.EventType.TOUCHSTART,this,this.handleTouchEvent_)}};
Blockly.Toolbox.TreeControl.prototype.handleTouchEvent_=function(a){a.preventDefault();var b=this.getNodeFromEvent_(a);b&&a.type===goog.events.EventType.TOUCHSTART&&setTimeout(function(){b.onMouseDown(a)},1)};Blockly.Toolbox.TreeControl.prototype.createNode=function(a){return new Blockly.Toolbox.TreeNode(this.toolbox_,a?goog.html.SafeHtml.htmlEscape(a):goog.html.SafeHtml.EMPTY,this.getConfig(),this.getDomHelper())};
@@ -1412,8 +1412,8 @@ Blockly.onMouseUp_=function(a){a=Blockly.getMainWorkspace();Blockly.Css.setCurso
Blockly.onMouseMove_=function(a){if(!(a.touches&&2<=a.touches.length)){var b=Blockly.getMainWorkspace();if(b.isScrolling){var c=a.clientX-b.startDragMouseX,d=a.clientY-b.startDragMouseY,e=b.startDragMetrics,f=b.startScrollX+c,g=b.startScrollY+d,f=Math.min(f,-e.contentLeft),g=Math.min(g,-e.contentTop),f=Math.max(f,e.viewWidth-e.contentLeft-e.contentWidth),g=Math.max(g,e.viewHeight-e.contentTop-e.contentHeight);b.scrollbar.set(-f-e.contentLeft,-g-e.contentTop);Math.sqrt(c*c+d*d)>Blockly.DRAG_RADIUS&&
Blockly.longStop_();a.stopPropagation();a.preventDefault()}}};
Blockly.onKeyDown_=function(a){if(!Blockly.mainWorkspace.options.readOnly&&!Blockly.isTargetInput_(a)){var b=!1;if(27==a.keyCode)Blockly.hideChaff();else if(8==a.keyCode||46==a.keyCode)a.preventDefault(),Blockly.selected&&Blockly.selected.isDeletable()&&(b=!0);else if(a.altKey||a.ctrlKey||a.metaKey)Blockly.selected&&Blockly.selected.isDeletable()&&Blockly.selected.isMovable()&&(67==a.keyCode?(Blockly.hideChaff(),Blockly.copy_(Blockly.selected)):88==a.keyCode&&(Blockly.copy_(Blockly.selected),b=!0)),
-86==a.keyCode?Blockly.clipboardXml_&&Blockly.clipboardSource_.paste(Blockly.clipboardXml_):90==a.keyCode&&(Blockly.hideChaff(),Blockly.mainWorkspace.undo(a.shiftKey));b&&(Blockly.Events.setGroup(!0),Blockly.hideChaff(),Blockly.selected.dispose(Blockly.dragMode_!=Blockly.DRAG_FREE,!0),Blockly.highlightedConnection_&&(Blockly.highlightedConnection_.unhighlight(),Blockly.highlightedConnection_=null),Blockly.Events.setGroup(!1))}};Blockly.terminateDrag_=function(){Blockly.BlockSvg.terminateDrag();Blockly.Flyout.terminateDrag_()};
-Blockly.longPid_=0;Blockly.longStart_=function(a,b){Blockly.longStop_();Blockly.longPid_=setTimeout(function(){a.button=2;b.onMouseDown_(a)},Blockly.LONGPRESS)};Blockly.longStop_=function(){Blockly.longPid_&&(clearTimeout(Blockly.longPid_),Blockly.longPid_=0)};
+86==a.keyCode?Blockly.clipboardXml_&&(Blockly.Events.setGroup(!0),Blockly.clipboardSource_.paste(Blockly.clipboardXml_),Blockly.Events.setGroup(!1)):90==a.keyCode&&(Blockly.hideChaff(),Blockly.mainWorkspace.undo(a.shiftKey));b&&(Blockly.Events.setGroup(!0),Blockly.hideChaff(),Blockly.selected.dispose(Blockly.dragMode_!=Blockly.DRAG_FREE,!0),Blockly.highlightedConnection_&&(Blockly.highlightedConnection_.unhighlight(),Blockly.highlightedConnection_=null),Blockly.Events.setGroup(!1))}};
+Blockly.terminateDrag_=function(){Blockly.BlockSvg.terminateDrag();Blockly.Flyout.terminateDrag_()};Blockly.longPid_=0;Blockly.longStart_=function(a,b){Blockly.longStop_();Blockly.longPid_=setTimeout(function(){a.button=2;b.onMouseDown_(a)},Blockly.LONGPRESS)};Blockly.longStop_=function(){Blockly.longPid_&&(clearTimeout(Blockly.longPid_),Blockly.longPid_=0)};
Blockly.copy_=function(a){var b=Blockly.Xml.blockToDom(a);Blockly.dragMode_!=Blockly.DRAG_FREE&&Blockly.Xml.deleteNext(b);var c=a.getRelativeToSurfaceXY();b.setAttribute("x",a.RTL?-c.x:c.x);b.setAttribute("y",c.y);Blockly.clipboardXml_=b;Blockly.clipboardSource_=a.workspace};Blockly.duplicate_=function(a){var b=Blockly.clipboardXml_,c=Blockly.clipboardSource_;Blockly.copy_(a);a.workspace.paste(Blockly.clipboardXml_);Blockly.clipboardXml_=b;Blockly.clipboardSource_=c};
Blockly.onContextMenu_=function(a){Blockly.isTargetInput_(a)||a.preventDefault()};Blockly.hideChaff=function(a){Blockly.Tooltip.hide();Blockly.WidgetDiv.hide();a||(a=Blockly.getMainWorkspace(),a.toolbox_&&a.toolbox_.flyout_&&a.toolbox_.flyout_.autoClose&&a.toolbox_.clearSelection())};
Blockly.getMainWorkspaceMetrics_=function(){var a=Blockly.svgSize(this.getParentSvg());if(this.toolbox_)if(this.toolboxPosition==Blockly.TOOLBOX_AT_TOP||this.toolboxPosition==Blockly.TOOLBOX_AT_BOTTOM)a.height-=this.toolbox_.getHeight();else if(this.toolboxPosition==Blockly.TOOLBOX_AT_LEFT||this.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT)a.width-=this.toolbox_.getWidth();var b=Blockly.Flyout.prototype.CORNER_RADIUS-1,c=a.width-b,d=a.height-b,e=this.getBlocksBoundingBox(),f=e.width*this.scale,g=e.height*
diff --git a/blocks/lists.js b/blocks/lists.js
index af0f6624a..0d23db05f 100644
--- a/blocks/lists.js
+++ b/blocks/lists.js
@@ -300,7 +300,9 @@ Blockly.Blocks['lists_indexOf'] = {
this.appendValueInput('FIND')
.appendField(new Blockly.FieldDropdown(OPERATORS), 'END');
this.setInputsInline(true);
- this.setTooltip(Blockly.Msg.LISTS_INDEX_OF_TOOLTIP);
+ var tooltip = Blockly.Msg.LISTS_INDEX_OF_TOOLTIP
+ .replace('%1', Blockly.Blocks.ONE_BASED_INDEXING ? '0' : '-1');
+ this.setTooltip(tooltip);
}
};
@@ -343,9 +345,58 @@ Blockly.Blocks['lists_getIndex'] = {
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function() {
- var combo = thisBlock.getFieldValue('MODE') + '_' +
- thisBlock.getFieldValue('WHERE');
- return Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_' + combo];
+ var mode = thisBlock.getFieldValue('MODE');
+ var where = thisBlock.getFieldValue('WHERE');
+ var tooltip = '';
+ switch (mode + ' ' + where) {
+ case 'GET FROM_START':
+ case 'GET FROM_END':
+ tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FROM;
+ break;
+ case 'GET FIRST':
+ tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FIRST;
+ break;
+ case 'GET LAST':
+ tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_LAST;
+ break;
+ case 'GET RANDOM':
+ tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_RANDOM;
+ break;
+ case 'GET_REMOVE FROM_START':
+ case 'GET_REMOVE FROM_END':
+ tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM;
+ break;
+ case 'GET_REMOVE FIRST':
+ tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST;
+ break;
+ case 'GET_REMOVE LAST':
+ tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST;
+ break;
+ case 'GET_REMOVE RANDOM':
+ tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM;
+ break;
+ case 'REMOVE FROM_START':
+ case 'REMOVE FROM_END':
+ tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM;
+ break;
+ case 'REMOVE FIRST':
+ tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST;
+ break;
+ case 'REMOVE LAST':
+ tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST;
+ break;
+ case 'REMOVE RANDOM':
+ tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM;
+ break;
+ }
+ if (where == 'FROM_START') {
+ tooltip += ' ' + Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP
+ .replace('%1', Blockly.Blocks.ONE_BASED_INDEXING ? '#1' : '#0');
+ } else if (where == 'FROM_END') {
+ tooltip += ' ' + Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP
+ .replace('%1', '#1'); // The end is always 1-indexed.
+ }
+ return tooltip;
});
},
/**
@@ -470,9 +521,45 @@ Blockly.Blocks['lists_setIndex'] = {
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function() {
- var combo = thisBlock.getFieldValue('MODE') + '_' +
- thisBlock.getFieldValue('WHERE');
- return Blockly.Msg['LISTS_SET_INDEX_TOOLTIP_' + combo];
+ var mode = thisBlock.getFieldValue('MODE');
+ var where = thisBlock.getFieldValue('WHERE');
+ var tooltip = '';
+ switch (mode + ' ' + where) {
+ case 'SET FROM_START':
+ case 'SET FROM_END':
+ tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FROM;
+ break;
+ case 'SET FIRST':
+ tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FIRST;
+ break;
+ case 'SET LAST':
+ tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_LAST;
+ break;
+ case 'SET RANDOM':
+ tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_RANDOM;
+ break;
+ case 'INSERT FROM_START':
+ case 'INSERT FROM_END':
+ tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FROM;
+ break;
+ case 'INSERT FIRST':
+ tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST;
+ break;
+ case 'INSERT LAST':
+ tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_LAST;
+ break;
+ case 'INSERT RANDOM':
+ tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM;
+ break;
+ }
+ if (where == 'FROM_START') {
+ tooltip += ' ' + Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP
+ .replace('%1', Blockly.Blocks.ONE_BASED_INDEXING ? '#1' : '#0');
+ } else if (where == 'FROM_END') {
+ tooltip += ' ' + Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP
+ .replace('%1', '#1'); // The end is always 1-indexed.
+ }
+ return tooltip;
});
},
/**
diff --git a/blocks/procedures.js b/blocks/procedures.js
index 7eb785509..82b383b51 100644
--- a/blocks/procedures.js
+++ b/blocks/procedures.js
@@ -59,16 +59,6 @@ Blockly.Blocks['procedures_defnoreturn'] = {
this.setStatements_(true);
this.statementConnection_ = null;
},
- /**
- * Initialization of the block has completed, clean up anything that may be
- * inconsistent as a result of the XML loading.
- * @this Blockly.Block
- */
- validate: function() {
- var name = Blockly.Procedures.findLegalName(
- this.getFieldValue('NAME'), this);
- this.setFieldValue(name, 'NAME');
- },
/**
* Add or remove the statement block from this function definition.
* @param {boolean} hasStatements True if a statement block is needed.
@@ -247,16 +237,6 @@ Blockly.Blocks['procedures_defnoreturn'] = {
}
}
},
- /**
- * Dispose of any callers.
- * @this Blockly.Block
- */
- dispose: function() {
- var name = this.getFieldValue('NAME');
- Blockly.Procedures.disposeCallers(name, this.workspace);
- // Call parent's destructor.
- this.constructor.prototype.dispose.apply(this, arguments);
- },
/**
* Return the signature of this procedure definition.
* @return {!Array} Tuple containing three elements:
@@ -374,13 +354,11 @@ Blockly.Blocks['procedures_defreturn'] = {
this.statementConnection_ = null;
},
setStatements_: Blockly.Blocks['procedures_defnoreturn'].setStatements_,
- validate: Blockly.Blocks['procedures_defnoreturn'].validate,
updateParams_: Blockly.Blocks['procedures_defnoreturn'].updateParams_,
mutationToDom: Blockly.Blocks['procedures_defnoreturn'].mutationToDom,
domToMutation: Blockly.Blocks['procedures_defnoreturn'].domToMutation,
decompose: Blockly.Blocks['procedures_defnoreturn'].decompose,
compose: Blockly.Blocks['procedures_defnoreturn'].compose,
- dispose: Blockly.Blocks['procedures_defnoreturn'].dispose,
/**
* Return the signature of this procedure definition.
* @return {!Array} Tuple containing three elements:
@@ -674,6 +652,72 @@ Blockly.Blocks['procedures_callnoreturn'] = {
}
}
},
+ /**
+ * Procedure calls cannot exist without the corresponding procedure
+ * definition. Enforce this link whenever an event is fired.
+ * @this Blockly.Block
+ */
+ onchange: function(event) {
+ if (!this.workspace || this.workspace.isFlyout) {
+ // Block is deleted or is in a flyout.
+ return;
+ }
+ if (event.type == Blockly.Events.CREATE &&
+ event.ids.indexOf(this.id) != -1) {
+ // Look for the case where a procedure call was created (usually through
+ // paste) and there is no matching definition. In this case, create
+ // an empty definition block with the correct signature.
+ var name = this.getProcedureCall();
+ var def = Blockly.Procedures.getDefinition(name, this.workspace);
+ if (def && (def.type != this.defType_ ||
+ JSON.stringify(def.arguments_) != JSON.stringify(this.arguments_))) {
+ // The signatures don't match.
+ def = null;
+ }
+ if (!def) {
+ Blockly.Events.setGroup(event.group);
+ /**
+ * Create matching definition block.
+ *
+ *
+ *
+ *
+ *
+ * test
+ *
+ *
+ */
+ var xml = goog.dom.createDom('xml');
+ var block = goog.dom.createDom('block');
+ block.setAttribute('type', this.defType_);
+ var xy = this.getRelativeToSurfaceXY();
+ var x = xy.x + Blockly.SNAP_RADIUS * (this.RTL ? -1 : 1);
+ var y = xy.y + Blockly.SNAP_RADIUS * 2;
+ block.setAttribute('x', x);
+ block.setAttribute('y', y);
+ var mutation = this.mutationToDom();
+ block.appendChild(mutation);
+ var field = goog.dom.createDom('field');
+ field.setAttribute('name', 'NAME');
+ field.appendChild(document.createTextNode(this.getProcedureCall()));
+ block.appendChild(field);
+ xml.appendChild(block);
+ Blockly.Xml.domToWorkspace(xml, this.workspace);
+ Blockly.Events.setGroup(false);
+ }
+ } else if (event.type == Blockly.Events.DELETE) {
+ // Look for the case where a procedure definition has been deleted,
+ // leaving this block (a procedure call) orphaned. In this case, delete
+ // the orphan.
+ var name = this.getProcedureCall();
+ var def = Blockly.Procedures.getDefinition(name, this.workspace);
+ if (!def) {
+ Blockly.Events.setGroup(event.group);
+ this.dispose(true, false);
+ Blockly.Events.setGroup(false);
+ }
+ }
+ },
/**
* Add menu option to find the definition block for this call.
* @param {!Array} options List of menu options to add to.
@@ -689,7 +733,8 @@ Blockly.Blocks['procedures_callnoreturn'] = {
def && def.select();
};
options.push(option);
- }
+ },
+ defType_: 'procedures_defnoreturn'
};
Blockly.Blocks['procedures_callreturn'] = {
@@ -716,7 +761,10 @@ Blockly.Blocks['procedures_callreturn'] = {
mutationToDom: Blockly.Blocks['procedures_callnoreturn'].mutationToDom,
domToMutation: Blockly.Blocks['procedures_callnoreturn'].domToMutation,
renameVar: Blockly.Blocks['procedures_callnoreturn'].renameVar,
- customContextMenu: Blockly.Blocks['procedures_callnoreturn'].customContextMenu
+ onchange: Blockly.Blocks['procedures_callnoreturn'].onchange,
+ customContextMenu:
+ Blockly.Blocks['procedures_callnoreturn'].customContextMenu,
+ defType_: 'procedures_defreturn'
};
Blockly.Blocks['procedures_ifreturn'] = {
diff --git a/blocks/text.js b/blocks/text.js
index 030940add..23ff52b32 100644
--- a/blocks/text.js
+++ b/blocks/text.js
@@ -322,7 +322,9 @@ Blockly.Blocks['text_indexOf'] = {
this.appendDummyInput().appendField(Blockly.Msg.TEXT_INDEXOF_TAIL);
}
this.setInputsInline(true);
- this.setTooltip(Blockly.Msg.TEXT_INDEXOF_TOOLTIP);
+ var tooltip = Blockly.Msg.TEXT_INDEXOF_TOOLTIP
+ .replace('%1', Blockly.Blocks.ONE_BASED_INDEXING ? '0' : '-1');
+ this.setTooltip(tooltip);
}
};
diff --git a/blocks_compressed.js b/blocks_compressed.js
index 042a84ad0..b4f2cd6d1 100644
--- a/blocks_compressed.js
+++ b/blocks_compressed.js
@@ -10,7 +10,7 @@ this.setOutput(!0,"Colour");this.setTooltip(Blockly.Msg.COLOUR_RGB_TOOLTIP)}};
Blockly.Blocks.colour_blend={init:function(){this.setHelpUrl(Blockly.Msg.COLOUR_BLEND_HELPURL);this.setColour(Blockly.Blocks.colour.HUE);this.appendValueInput("COLOUR1").setCheck("Colour").setAlign(Blockly.ALIGN_RIGHT).appendField(Blockly.Msg.COLOUR_BLEND_TITLE).appendField(Blockly.Msg.COLOUR_BLEND_COLOUR1);this.appendValueInput("COLOUR2").setCheck("Colour").setAlign(Blockly.ALIGN_RIGHT).appendField(Blockly.Msg.COLOUR_BLEND_COLOUR2);this.appendValueInput("RATIO").setCheck("Number").setAlign(Blockly.ALIGN_RIGHT).appendField(Blockly.Msg.COLOUR_BLEND_RATIO);
this.setOutput(!0,"Colour");this.setTooltip(Blockly.Msg.COLOUR_BLEND_TOOLTIP)}};Blockly.Blocks.lists={};Blockly.Blocks.lists.HUE=260;Blockly.Blocks.lists_create_empty={init:function(){this.jsonInit({message0:Blockly.Msg.LISTS_CREATE_EMPTY_TITLE,output:"Array",colour:Blockly.Blocks.lists.HUE,tooltip:Blockly.Msg.LISTS_CREATE_EMPTY_TOOLTIP,helpUrl:Blockly.Msg.LISTS_CREATE_EMPTY_HELPURL})}};
Blockly.Blocks.lists_create_with={init:function(){this.setHelpUrl(Blockly.Msg.LISTS_CREATE_WITH_HELPURL);this.setColour(Blockly.Blocks.lists.HUE);this.itemCount_=3;this.updateShape_();this.setOutput(!0,"Array");this.setMutator(new Blockly.Mutator(["lists_create_with_item"]));this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_TOOLTIP)},mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("items",this.itemCount_);return a},domToMutation:function(a){this.itemCount_=parseInt(a.getAttribute("items"),
-10);this.updateShape_()},decompose:function(a){var b=a.newBlock("lists_create_with_container");b.initSvg();for(var c=b.getInput("STACK").connection,d=0;d","LT"],["\u2265","LTE"],["<","GT"],["\u2264","GTE"]],b=[["=","EQ"],["\u2260","NEQ"],["<","LT"],["\u2264","LTE"],[">","GT"],["\u2265","GTE"]],a=this.RTL?a:b;this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL);this.setColour(Blockly.Blocks.logic.HUE);this.setOutput(!0,"Boolean");this.appendValueInput("A");this.appendValueInput("B").appendField(new Blockly.FieldDropdown(a),"OP");this.setInputsInline(!0);var c=this;this.setTooltip(function(){var a=
c.getFieldValue("OP");return{EQ:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ,NEQ:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ,LT:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT,LTE:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE,GT:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT,GTE:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE}[a]});this.prevBlocks_=[null,null]},onchange:function(a){var b=this.getInputTargetBlock("A"),c=this.getInputTargetBlock("B");if(b&&c&&!b.outputConnection.checkType_(c.outputConnection)){Blockly.Events.setGroup(a.group);for(a=0;a<
-this.prevBlocks_.length;a++){var d=this.prevBlocks_[a];if(d===b||d===c)d.unplug(),d.bumpNeighbours_()}Blockly.Events.setGroup(!1)}this.prevBlocks_[0]=b;this.prevBlocks_[1]=c}};
+this.prevBlocks_.length;a++){var e=this.prevBlocks_[a];if(e===b||e===c)e.unplug(),e.bumpNeighbours_()}Blockly.Events.setGroup(!1)}this.prevBlocks_[0]=b;this.prevBlocks_[1]=c}};
Blockly.Blocks.logic_operation={init:function(){var a=[[Blockly.Msg.LOGIC_OPERATION_AND,"AND"],[Blockly.Msg.LOGIC_OPERATION_OR,"OR"]];this.setHelpUrl(Blockly.Msg.LOGIC_OPERATION_HELPURL);this.setColour(Blockly.Blocks.logic.HUE);this.setOutput(!0,"Boolean");this.appendValueInput("A").setCheck("Boolean");this.appendValueInput("B").setCheck("Boolean").appendField(new Blockly.FieldDropdown(a),"OP");this.setInputsInline(!0);var b=this;this.setTooltip(function(){var a=b.getFieldValue("OP");return{AND:Blockly.Msg.LOGIC_OPERATION_TOOLTIP_AND,
OR:Blockly.Msg.LOGIC_OPERATION_TOOLTIP_OR}[a]})}};Blockly.Blocks.logic_negate={init:function(){this.jsonInit({message0:Blockly.Msg.LOGIC_NEGATE_TITLE,args0:[{type:"input_value",name:"BOOL",check:"Boolean"}],output:"Boolean",colour:Blockly.Blocks.logic.HUE,tooltip:Blockly.Msg.LOGIC_NEGATE_TOOLTIP,helpUrl:Blockly.Msg.LOGIC_NEGATE_HELPURL})}};
Blockly.Blocks.logic_boolean={init:function(){this.jsonInit({message0:"%1",args0:[{type:"field_dropdown",name:"BOOL",options:[[Blockly.Msg.LOGIC_BOOLEAN_TRUE,"TRUE"],[Blockly.Msg.LOGIC_BOOLEAN_FALSE,"FALSE"]]}],output:"Boolean",colour:Blockly.Blocks.logic.HUE,tooltip:Blockly.Msg.LOGIC_BOOLEAN_TOOLTIP,helpUrl:Blockly.Msg.LOGIC_BOOLEAN_HELPURL})}};
Blockly.Blocks.logic_null={init:function(){this.jsonInit({message0:Blockly.Msg.LOGIC_NULL,output:null,colour:Blockly.Blocks.logic.HUE,tooltip:Blockly.Msg.LOGIC_NULL_TOOLTIP,helpUrl:Blockly.Msg.LOGIC_NULL_HELPURL})}};
Blockly.Blocks.logic_ternary={init:function(){this.setHelpUrl(Blockly.Msg.LOGIC_TERNARY_HELPURL);this.setColour(Blockly.Blocks.logic.HUE);this.appendValueInput("IF").setCheck("Boolean").appendField(Blockly.Msg.LOGIC_TERNARY_CONDITION);this.appendValueInput("THEN").appendField(Blockly.Msg.LOGIC_TERNARY_IF_TRUE);this.appendValueInput("ELSE").appendField(Blockly.Msg.LOGIC_TERNARY_IF_FALSE);this.setOutput(!0);this.setTooltip(Blockly.Msg.LOGIC_TERNARY_TOOLTIP);this.prevParentConnection_=null},onchange:function(a){var b=
-this.getInputTargetBlock("THEN"),c=this.getInputTargetBlock("ELSE"),d=this.outputConnection.targetConnection;if((b||c)&&d)for(var e=0;2>e;e++){var f=1==e?b:c;f&&!f.outputConnection.checkType_(d)&&(Blockly.Events.setGroup(a.group),d===this.prevParentConnection_?(this.unplug(),d.getSourceBlock().bumpNeighbours_()):(f.unplug(),f.bumpNeighbours_()),Blockly.Events.setGroup(!1))}this.prevParentConnection_=d}};Blockly.Blocks.loops={};Blockly.Blocks.loops.HUE=120;Blockly.Blocks.controls_repeat_ext={init:function(){this.jsonInit({message0:Blockly.Msg.CONTROLS_REPEAT_TITLE,args0:[{type:"input_value",name:"TIMES",check:"Number"}],previousStatement:null,nextStatement:null,colour:Blockly.Blocks.loops.HUE,tooltip:Blockly.Msg.CONTROLS_REPEAT_TOOLTIP,helpUrl:Blockly.Msg.CONTROLS_REPEAT_HELPURL});this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO)}};
+this.getInputTargetBlock("THEN"),c=this.getInputTargetBlock("ELSE"),e=this.outputConnection.targetConnection;if((b||c)&&e)for(var d=0;2>d;d++){var f=1==d?b:c;f&&!f.outputConnection.checkType_(e)&&(Blockly.Events.setGroup(a.group),e===this.prevParentConnection_?(this.unplug(),e.getSourceBlock().bumpNeighbours_()):(f.unplug(),f.bumpNeighbours_()),Blockly.Events.setGroup(!1))}this.prevParentConnection_=e}};Blockly.Blocks.loops={};Blockly.Blocks.loops.HUE=120;Blockly.Blocks.controls_repeat_ext={init:function(){this.jsonInit({message0:Blockly.Msg.CONTROLS_REPEAT_TITLE,args0:[{type:"input_value",name:"TIMES",check:"Number"}],previousStatement:null,nextStatement:null,colour:Blockly.Blocks.loops.HUE,tooltip:Blockly.Msg.CONTROLS_REPEAT_TOOLTIP,helpUrl:Blockly.Msg.CONTROLS_REPEAT_HELPURL});this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO)}};
Blockly.Blocks.controls_repeat={init:function(){this.jsonInit({message0:Blockly.Msg.CONTROLS_REPEAT_TITLE,args0:[{type:"field_number",name:"TIMES",value:10,min:0,precision:1}],previousStatement:null,nextStatement:null,colour:Blockly.Blocks.loops.HUE,tooltip:Blockly.Msg.CONTROLS_REPEAT_TOOLTIP,helpUrl:Blockly.Msg.CONTROLS_REPEAT_HELPURL});this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO)}};
Blockly.Blocks.controls_whileUntil={init:function(){var a=[[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_WHILE,"WHILE"],[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_UNTIL,"UNTIL"]];this.setHelpUrl(Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL);this.setColour(Blockly.Blocks.loops.HUE);this.appendValueInput("BOOL").setCheck("Boolean").appendField(new Blockly.FieldDropdown(a),"MODE");this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO);this.setPreviousStatement(!0);this.setNextStatement(!0);
var b=this;this.setTooltip(function(){var a=b.getFieldValue("MODE");return{WHILE:Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_WHILE,UNTIL:Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL}[a]})}};
@@ -83,36 +88,37 @@ Blockly.Blocks.math_constrain={init:function(){this.jsonInit({message0:Blockly.M
Blockly.Blocks.math_random_int={init:function(){this.jsonInit({message0:Blockly.Msg.MATH_RANDOM_INT_TITLE,args0:[{type:"input_value",name:"FROM",check:"Number"},{type:"input_value",name:"TO",check:"Number"}],inputsInline:!0,output:"Number",colour:Blockly.Blocks.math.HUE,tooltip:Blockly.Msg.MATH_RANDOM_INT_TOOLTIP,helpUrl:Blockly.Msg.MATH_RANDOM_INT_HELPURL})}};
Blockly.Blocks.math_random_float={init:function(){this.jsonInit({message0:Blockly.Msg.MATH_RANDOM_FLOAT_TITLE_RANDOM,output:"Number",colour:Blockly.Blocks.math.HUE,tooltip:Blockly.Msg.MATH_RANDOM_FLOAT_TOOLTIP,helpUrl:Blockly.Msg.MATH_RANDOM_FLOAT_HELPURL})}};Blockly.Blocks.procedures={};Blockly.Blocks.procedures.HUE=290;
Blockly.Blocks.procedures_defnoreturn={init:function(){var a=new Blockly.FieldTextInput(Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE,Blockly.Procedures.rename);a.setSpellcheck(!1);this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE).appendField(a,"NAME").appendField("","PARAMS");this.setMutator(new Blockly.Mutator(["procedures_mutatorarg"]));Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT&&this.setCommentText(Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT);this.setColour(Blockly.Blocks.procedures.HUE);
-this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);this.arguments_=[];this.setStatements_(!0);this.statementConnection_=null},validate:function(){var a=Blockly.Procedures.findLegalName(this.getFieldValue("NAME"),this);this.setFieldValue(a,"NAME")},setStatements_:function(a){this.hasStatements_!==a&&(a?(this.appendStatementInput("STACK").appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO),this.getInput("RETURN")&&this.moveInputBefore("STACK",
-"RETURN")):this.removeInput("STACK",!0),this.hasStatements_=a)},updateParams_:function(){for(var a=!1,b={},c=0;c Blockly.DRAG_RADIUS) {
- // Create the block.
- Blockly.Flyout.startFlyout_.createBlockFunc_(Blockly.Flyout.startBlock_)(
+
+ var createBlock = this.determineDragIntention_(dx, dy);
+ if (createBlock) {
+ this.createBlockFunc_(Blockly.Flyout.startBlock_)(
Blockly.Flyout.startDownEvent_);
+ } else if (this.dragMode_ == Blockly.DRAG_FREE) {
+ // Do a scroll.
+ this.onMouseMove_(e);
}
+ e.stopPropagation();
+};
+
+/**
+ * Determine the intention of a drag.
+ * Updates dragMode_ based on a drag delta and the current mode,
+ * and returns true if we should create a new block.
+ * @param {number} dx X delta of the drag.
+ * @param {number} dy Y delta of the drag.
+ * @return {boolean} True if a new block should be created.
+ * @private
+ */
+Blockly.Flyout.prototype.determineDragIntention_ = function(dx, dy) {
+ if (this.dragMode_ == Blockly.DRAG_FREE) {
+ // Once in free mode, always stay in free mode and never create a block.
+ return false;
+ }
+ var dragDistance = Math.sqrt(dx * dx + dy * dy);
+ if (dragDistance < this.DRAG_RADIUS) {
+ // Still within the sticky drag radius.
+ this.dragMode_ = Blockly.DRAG_STICKY;
+ return false;
+ } else {
+ if (this.isDragTowardWorkspace_(dx, dy) || !this.scrollbar_.isVisible()) {
+ // Immediately create a block.
+ return true;
+ } else {
+ // Immediately move to free mode - the drag is away from the workspace.
+ this.dragMode_ = Blockly.DRAG_FREE;
+ return false;
+ }
+ }
+};
+
+/**
+ * Determine if a drag delta is toward the workspace, based on the position
+ * and orientation of the flyout. This is used in determineDragIntention_ to
+ * determine if a new block should be created or if the flyout should scroll.
+ * @param {number} dx X delta of the drag.
+ * @param {number} dy Y delta of the drag.
+ * @return {boolean} true if the drag is toward the workspace.
+ * @private
+ */
+Blockly.Flyout.prototype.isDragTowardWorkspace_ = function(dx, dy) {
+ // Direction goes from -180 to 180, with 0 toward the right and 90 on top.
+ var dragDirection = Math.atan2(dy, dx) / Math.PI * 180;
+
+ var draggingTowardWorkspace = false;
+ var range = this.dragAngleRange_;
+ if (this.horizontalLayout_) {
+ if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
+ // Horizontal at top.
+ if (dragDirection < 90 + range && dragDirection > 90 - range) {
+ draggingTowardWorkspace = true;
+ }
+ } else {
+ // Horizontal at bottom.
+ if (dragDirection > -90 - range && dragDirection < -90 + range) {
+ draggingTowardWorkspace = true;
+ }
+ }
+ } else {
+ if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
+ // Vertical at left.
+ if (dragDirection < range && dragDirection > -range) {
+ draggingTowardWorkspace = true;
+ }
+ } else {
+ // Vertical at right.
+ if (dragDirection < -180 + range || dragDirection > 180 - range) {
+ draggingTowardWorkspace = true;
+ }
+ }
+ }
+ return draggingTowardWorkspace;
};
/**
@@ -994,6 +1106,9 @@ Blockly.Flyout.prototype.getClientRect = function() {
* @private
*/
Blockly.Flyout.terminateDrag_ = function() {
+ if (Blockly.Flyout.startFlyout_) {
+ Blockly.Flyout.startFlyout_.dragMode_ = Blockly.DRAG_NONE;
+ }
if (Blockly.Flyout.onMouseUpWrapper_) {
Blockly.unbindEvent_(Blockly.Flyout.onMouseUpWrapper_);
Blockly.Flyout.onMouseUpWrapper_ = null;
diff --git a/core/generator.js b/core/generator.js
index 8ee110f86..fecc35531 100644
--- a/core/generator.js
+++ b/core/generator.js
@@ -132,7 +132,7 @@ Blockly.Generator.prototype.workspaceToCode = function(workspace) {
* @return {string} The prefixed lines of code.
*/
Blockly.Generator.prototype.prefixLines = function(text, prefix) {
- return prefix + text.replace(/\n(.)/g, '\n' + prefix + '$1');
+ return prefix + text.replace(/(?!\n$)\n/g, '\n' + prefix);
};
/**
@@ -143,8 +143,8 @@ Blockly.Generator.prototype.prefixLines = function(text, prefix) {
Blockly.Generator.prototype.allNestedComments = function(block) {
var comments = [];
var blocks = block.getDescendants();
- for (var x = 0; x < blocks.length; x++) {
- var comment = blocks[x].getCommentText();
+ for (var i = 0; i < blocks.length; i++) {
+ var comment = blocks[i].getCommentText();
if (comment) {
comments.push(comment);
}
diff --git a/core/icon.js b/core/icon.js
index 9d2cbeaad..395c98544 100644
--- a/core/icon.js
+++ b/core/icon.js
@@ -124,7 +124,7 @@ Blockly.Icon.prototype.isVisible = function() {
* @private
*/
Blockly.Icon.prototype.iconClick_ = function(e) {
- if (Blockly.dragMode_ == Blockly.DRAG_FREE) {
+ if (this.block_.workspace.isDragging()) {
// Drag operation is concluding. Don't open the editor.
return;
}
diff --git a/core/input.js b/core/input.js
index 346b053cb..4b4eb1df9 100644
--- a/core/input.js
+++ b/core/input.js
@@ -222,8 +222,8 @@ Blockly.Input.prototype.init = function() {
if (!this.sourceBlock_.workspace.rendered) {
return; // Headless blocks don't need fields initialized.
}
- for (var x = 0; x < this.fieldRow.length; x++) {
- this.fieldRow[x].init();
+ for (var i = 0; i < this.fieldRow.length; i++) {
+ this.fieldRow[i].init();
}
};
diff --git a/core/procedures.js b/core/procedures.js
index f98fbd92a..beb4a17b8 100644
--- a/core/procedures.js
+++ b/core/procedures.js
@@ -89,7 +89,7 @@ Blockly.Procedures.findLegalName = function(name, block) {
// Flyouts can have multiple procedures called 'do something'.
return name;
}
- while (!Blockly.Procedures.isLegalName(name, block.workspace, block)) {
+ while (!Blockly.Procedures.isLegalName_(name, block.workspace, block)) {
// Collision with another procedure.
var r = name.match(/^(.*?)(\d+)$/);
if (!r) {
@@ -109,8 +109,9 @@ Blockly.Procedures.findLegalName = function(name, block) {
* @param {Blockly.Block=} opt_exclude Optional block to exclude from
* comparisons (one doesn't want to collide with oneself).
* @return {boolean} True if the name is legal.
+ * @private
*/
-Blockly.Procedures.isLegalName = function(name, workspace, opt_exclude) {
+Blockly.Procedures.isLegalName_ = function(name, workspace, opt_exclude) {
var blocks = workspace.getAllBlocks();
// Iterate through every block and check the name.
for (var i = 0; i < blocks.length; i++) {
@@ -129,24 +130,27 @@ Blockly.Procedures.isLegalName = function(name, workspace, opt_exclude) {
/**
* Rename a procedure. Called by the editable field.
- * @param {string} text The proposed new name.
+ * @param {string} name The proposed new name.
* @return {string} The accepted name.
* @this {!Blockly.Field}
*/
-Blockly.Procedures.rename = function(text) {
+Blockly.Procedures.rename = function(name) {
// Strip leading and trailing whitespace. Beyond this, all names are legal.
- text = text.replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
+ name = name.replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
// Ensure two identically-named procedures don't exist.
- text = Blockly.Procedures.findLegalName(text, this.sourceBlock_);
- // Rename any callers.
- var blocks = this.sourceBlock_.workspace.getAllBlocks();
- for (var i = 0; i < blocks.length; i++) {
- if (blocks[i].renameProcedure) {
- blocks[i].renameProcedure(this.text_, text);
+ var legalName = Blockly.Procedures.findLegalName(name, this.sourceBlock_);
+ var oldName = this.text_;
+ if (oldName != name && oldName != legalName) {
+ // Rename any callers.
+ var blocks = this.sourceBlock_.workspace.getAllBlocks();
+ for (var i = 0; i < blocks.length; i++) {
+ if (blocks[i].renameProcedure) {
+ blocks[i].renameProcedure(oldName, legalName);
+ }
}
}
- return text;
+ return legalName;
};
/**
@@ -197,9 +201,9 @@ Blockly.Procedures.flyoutCategory = function(workspace) {
var mutation = goog.dom.createDom('mutation');
mutation.setAttribute('name', name);
block.appendChild(mutation);
- for (var t = 0; t < args.length; t++) {
+ for (var j = 0; j < args.length; j++) {
var arg = goog.dom.createDom('arg');
- arg.setAttribute('name', args[t]);
+ arg.setAttribute('name', args[j]);
mutation.appendChild(arg);
}
xmlList.push(block);
@@ -234,19 +238,6 @@ Blockly.Procedures.getCallers = function(name, workspace) {
return callers;
};
-/**
- * When a procedure definition is disposed of, find and dispose of all its
- * callers.
- * @param {string} name Name of deleted procedure definition.
- * @param {!Blockly.Workspace} workspace The workspace to delete callers from.
- */
-Blockly.Procedures.disposeCallers = function(name, workspace) {
- var callers = Blockly.Procedures.getCallers(name, workspace);
- for (var i = 0; i < callers.length; i++) {
- callers[i].dispose(true, false);
- }
-};
-
/**
* When a procedure definition changes its parameters, find and edit all its
* callers.
@@ -282,7 +273,8 @@ Blockly.Procedures.mutateCallers = function(defBlock) {
* @return {Blockly.Block} The procedure definition block, or null not found.
*/
Blockly.Procedures.getDefinition = function(name, workspace) {
- var blocks = workspace.getAllBlocks();
+ // Assume that a procedure definition is a top block.
+ var blocks = workspace.getTopBlocks(false);
for (var i = 0; i < blocks.length; i++) {
if (blocks[i].getProcedureDef) {
var tuple = blocks[i].getProcedureDef();
diff --git a/core/rendered_connection.js b/core/rendered_connection.js
index ef7130dc6..552248526 100644
--- a/core/rendered_connection.js
+++ b/core/rendered_connection.js
@@ -234,8 +234,8 @@ Blockly.RenderedConnection.prototype.unhideAll = function() {
// Show all connections of this block.
connections = block.getConnections_(true);
}
- for (var c = 0; c < connections.length; c++) {
- renderList.push.apply(renderList, connections[c].unhideAll());
+ for (var i = 0; i < connections.length; i++) {
+ renderList.push.apply(renderList, connections[i].unhideAll());
}
if (!renderList.length) {
// Leaf block.
@@ -275,17 +275,17 @@ Blockly.RenderedConnection.prototype.hideAll = function() {
this.setHidden(true);
if (this.targetConnection) {
var blocks = this.targetBlock().getDescendants();
- for (var b = 0; b < blocks.length; b++) {
- var block = blocks[b];
+ for (var i = 0; i < blocks.length; i++) {
+ var block = blocks[i];
// Hide all connections of all children.
var connections = block.getConnections_(true);
- for (var c = 0; c < connections.length; c++) {
- connections[c].setHidden(true);
+ for (var j = 0; j < connections.length; j++) {
+ connections[j].setHidden(true);
}
// Close all bubbles of all children.
var icons = block.getIcons();
- for (var i = 0; i < icons.length; i++) {
- icons[i].setVisible(false);
+ for (var j = 0; j < icons.length; j++) {
+ icons[j].setVisible(false);
}
}
}
diff --git a/core/variables.js b/core/variables.js
index 9399177fe..450d33fcf 100644
--- a/core/variables.js
+++ b/core/variables.js
@@ -54,10 +54,10 @@ Blockly.Variables.allVariables = function(root) {
}
var variableHash = Object.create(null);
// Iterate through every block and add each variable to the hash.
- for (var x = 0; x < blocks.length; x++) {
- var blockVariables = blocks[x].getVars();
- for (var y = 0; y < blockVariables.length; y++) {
- var varName = blockVariables[y];
+ for (var i = 0; i < blocks.length; i++) {
+ var blockVariables = blocks[i].getVars();
+ for (var j = 0; j < blockVariables.length; j++) {
+ var varName = blockVariables[j];
// Variable name may be null if the block is only half-built.
if (varName) {
variableHash[varName.toLowerCase()] = varName;
diff --git a/core/workspace_svg.js b/core/workspace_svg.js
index 251d5ef10..4c2d85661 100644
--- a/core/workspace_svg.js
+++ b/core/workspace_svg.js
@@ -713,6 +713,14 @@ Blockly.WorkspaceSvg.prototype.moveDrag = function(e) {
return goog.math.Coordinate.sum(this.dragDeltaXY_, point);
};
+/**
+ * Is the user currently dragging a block or scrolling the workspace?
+ * @return {boolean} True if currently dragging or scrolling.
+ */
+Blockly.WorkspaceSvg.prototype.isDragging = function() {
+ return Blockly.dragMode_ == Blockly.DRAG_FREE || this.isScrolling;
+};
+
/**
* Handle a mouse-wheel on SVG drawing surface.
* @param {!Event} e Mouse wheel event.
@@ -735,7 +743,7 @@ Blockly.WorkspaceSvg.prototype.onMouseWheel_ = function(e) {
* containing the blocks on the workspace.
*/
Blockly.WorkspaceSvg.prototype.getBlocksBoundingBox = function() {
- var topBlocks = this.getTopBlocks();
+ var topBlocks = this.getTopBlocks(false);
// There are no blocks, return empty rectangle.
if (!topBlocks.length) {
return {x: 0, y: 0, width: 0, height: 0};
diff --git a/core/xml.js b/core/xml.js
index 7f096956a..95e6471c2 100644
--- a/core/xml.js
+++ b/core/xml.js
@@ -535,10 +535,6 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) {
}
block.setShadow(true);
}
- // Give the block a chance to clean up any initial inputs.
- if (block.validate) {
- block.validate();
- }
return block;
};
diff --git a/dart_compressed.js b/dart_compressed.js
index 963bbc380..20a2cafa1 100644
--- a/dart_compressed.js
+++ b/dart_compressed.js
@@ -4,33 +4,38 @@
// Copyright 2014 Google Inc. Apache License 2.0
Blockly.Dart=new Blockly.Generator("Dart");Blockly.Dart.addReservedWords("assert,break,case,catch,class,const,continue,default,do,else,enum,extends,false,final,finally,for,if,in,is,new,null,rethrow,return,super,switch,this,throw,true,try,var,void,while,with,print,identityHashCode,identical,BidirectionalIterator,Comparable,double,Function,int,Invocation,Iterable,Iterator,List,Map,Match,num,Pattern,RegExp,Set,StackTrace,String,StringSink,Type,bool,DateTime,Deprecated,Duration,Expando,Null,Object,RuneIterator,Runes,Stopwatch,StringBuffer,Symbol,Uri,Comparator,AbstractClassInstantiationError,ArgumentError,AssertionError,CastError,ConcurrentModificationError,CyclicInitializationError,Error,Exception,FallThroughError,FormatException,IntegerDivisionByZeroException,NoSuchMethodError,NullThrownError,OutOfMemoryError,RangeError,StackOverflowError,StateError,TypeError,UnimplementedError,UnsupportedError");
-Blockly.Dart.ORDER_ATOMIC=0;Blockly.Dart.ORDER_UNARY_POSTFIX=1;Blockly.Dart.ORDER_UNARY_PREFIX=2;Blockly.Dart.ORDER_MULTIPLICATIVE=3;Blockly.Dart.ORDER_ADDITIVE=4;Blockly.Dart.ORDER_SHIFT=5;Blockly.Dart.ORDER_BITWISE_AND=6;Blockly.Dart.ORDER_BITWISE_XOR=7;Blockly.Dart.ORDER_BITWISE_OR=8;Blockly.Dart.ORDER_RELATIONAL=9;Blockly.Dart.ORDER_EQUALITY=10;Blockly.Dart.ORDER_LOGICAL_AND=11;Blockly.Dart.ORDER_LOGICAL_OR=12;Blockly.Dart.ORDER_CONDITIONAL=13;Blockly.Dart.ORDER_CASCADE=14;
-Blockly.Dart.ORDER_ASSIGNMENT=15;Blockly.Dart.ORDER_NONE=99;
+Blockly.Dart.ORDER_ATOMIC=0;Blockly.Dart.ORDER_UNARY_POSTFIX=1;Blockly.Dart.ORDER_UNARY_PREFIX=2;Blockly.Dart.ORDER_MULTIPLICATIVE=3;Blockly.Dart.ORDER_ADDITIVE=4;Blockly.Dart.ORDER_SHIFT=5;Blockly.Dart.ORDER_BITWISE_AND=6;Blockly.Dart.ORDER_BITWISE_XOR=7;Blockly.Dart.ORDER_BITWISE_OR=8;Blockly.Dart.ORDER_RELATIONAL=9;Blockly.Dart.ORDER_EQUALITY=10;Blockly.Dart.ORDER_LOGICAL_AND=11;Blockly.Dart.ORDER_LOGICAL_OR=12;Blockly.Dart.ORDER_IF_NULL=13;Blockly.Dart.ORDER_CONDITIONAL=14;
+Blockly.Dart.ORDER_CASCADE=15;Blockly.Dart.ORDER_ASSIGNMENT=16;Blockly.Dart.ORDER_NONE=99;Blockly.Dart.ONE_BASED_INDEXING=!0;
Blockly.Dart.init=function(a){Blockly.Dart.definitions_=Object.create(null);Blockly.Dart.functionNames_=Object.create(null);Blockly.Dart.variableDB_?Blockly.Dart.variableDB_.reset():Blockly.Dart.variableDB_=new Blockly.Names(Blockly.Dart.RESERVED_WORDS_);var b=[];a=Blockly.Variables.allVariables(a);if(a.length){for(var c=0;cc&&(a=a+" - "+-c,g=Blockly.Dart.ORDER_ADDITIVE);d&&(a=
+c?"-("+a+")":"-"+a,g=Blockly.Dart.ORDER_UNARY_PREFIX);g=Math.floor(g);e=Math.floor(e);g&&e>=g&&(a="("+a+")")}return a};Blockly.Dart.colour={};Blockly.Dart.addReservedWords("Math");Blockly.Dart.colour_picker=function(a){return["'"+a.getFieldValue("COLOUR")+"'",Blockly.Dart.ORDER_ATOMIC]};
Blockly.Dart.colour_random=function(a){Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";return[Blockly.Dart.provideFunction_("colour_random",["String "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"() {"," String hex = '0123456789abcdef';"," var rnd = new Math.Random();"," return '#${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}'"," '${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}'"," '${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}';","}"])+"()",Blockly.Dart.ORDER_UNARY_POSTFIX]};
Blockly.Dart.colour_rgb=function(a){var b=Blockly.Dart.valueToCode(a,"RED",Blockly.Dart.ORDER_NONE)||0,c=Blockly.Dart.valueToCode(a,"GREEN",Blockly.Dart.ORDER_NONE)||0;a=Blockly.Dart.valueToCode(a,"BLUE",Blockly.Dart.ORDER_NONE)||0;Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";return[Blockly.Dart.provideFunction_("colour_rgb",["String "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(num r, num g, num b) {"," num rn = (Math.max(Math.min(r, 1), 0) * 255).round();"," String rs = rn.toInt().toRadixString(16);",
" rs = '0$rs';"," rs = rs.substring(rs.length - 2);"," num gn = (Math.max(Math.min(g, 1), 0) * 255).round();"," String gs = gn.toInt().toRadixString(16);"," gs = '0$gs';"," gs = gs.substring(gs.length - 2);"," num bn = (Math.max(Math.min(b, 1), 0) * 255).round();"," String bs = bn.toInt().toRadixString(16);"," bs = '0$bs';"," bs = bs.substring(bs.length - 2);"," return '#$rs$gs$bs';","}"])+"("+b+", "+c+", "+a+")",Blockly.Dart.ORDER_UNARY_POSTFIX]};
Blockly.Dart.colour_blend=function(a){var b=Blockly.Dart.valueToCode(a,"COLOUR1",Blockly.Dart.ORDER_NONE)||"'#000000'",c=Blockly.Dart.valueToCode(a,"COLOUR2",Blockly.Dart.ORDER_NONE)||"'#000000'";a=Blockly.Dart.valueToCode(a,"RATIO",Blockly.Dart.ORDER_NONE)||.5;Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";return[Blockly.Dart.provideFunction_("colour_blend",["String "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(String c1, String c2, num ratio) {"," ratio = Math.max(Math.min(ratio, 1), 0);",
" int r1 = int.parse('0x${c1.substring(1, 3)}');"," int g1 = int.parse('0x${c1.substring(3, 5)}');"," int b1 = int.parse('0x${c1.substring(5, 7)}');"," int r2 = int.parse('0x${c2.substring(1, 3)}');"," int g2 = int.parse('0x${c2.substring(3, 5)}');"," int b2 = int.parse('0x${c2.substring(5, 7)}');"," num rn = (r1 * (1 - ratio) + r2 * ratio).round();"," String rs = rn.toInt().toRadixString(16);"," num gn = (g1 * (1 - ratio) + g2 * ratio).round();"," String gs = gn.toInt().toRadixString(16);",
-" num bn = (b1 * (1 - ratio) + b2 * ratio).round();"," String bs = bn.toInt().toRadixString(16);"," rs = '0$rs';"," rs = rs.substring(rs.length - 2);"," gs = '0$gs';"," gs = gs.substring(gs.length - 2);"," bs = '0$bs';"," bs = bs.substring(bs.length - 2);"," return '#$rs$gs$bs';","}"])+"("+b+", "+c+", "+a+")",Blockly.Dart.ORDER_UNARY_POSTFIX]};Blockly.Dart.lists={};Blockly.Dart.addReservedWords("Math");Blockly.Dart.lists_create_empty=function(a){return["[]",Blockly.Dart.ORDER_ATOMIC]};Blockly.Dart.lists_create_with=function(a){for(var b=Array(a.itemCount_),c=0;c direction * a.compareTo(b),',' "TEXT": (a, b) => direction * a.toString().compareTo(b.toString()),',' "IGNORE_CASE": '," (a, b) => direction * ",
+Blockly.Dart.lists_isEmpty=function(a){return[(Blockly.Dart.valueToCode(a,"VALUE",Blockly.Dart.ORDER_UNARY_POSTFIX)||"[]")+".isEmpty",Blockly.Dart.ORDER_UNARY_POSTFIX]};
+Blockly.Dart.lists_indexOf=function(a){var b="FIRST"==a.getFieldValue("END")?"indexOf":"lastIndexOf",c=Blockly.Dart.valueToCode(a,"FIND",Blockly.Dart.ORDER_NONE)||"''";a=(Blockly.Dart.valueToCode(a,"VALUE",Blockly.Dart.ORDER_UNARY_POSTFIX)||"[]")+"."+b+"("+c+")";return Blockly.Dart.ONE_BASED_INDEXING?[a+" + 1",Blockly.Dart.ORDER_ADDITIVE]:[a,Blockly.Dart.ORDER_UNARY_POSTFIX]};
+Blockly.Dart.lists_getIndex=function(a){function b(){var a=Blockly.Dart.variableDB_.getDistinctName("tmp_list",Blockly.Variables.NAME_TYPE),b="List "+a+" = "+e+";\n";e=a;return b}var c=a.getFieldValue("MODE")||"GET",d=a.getFieldValue("WHERE")||"FROM_START",e=Blockly.Dart.valueToCode(a,"VALUE","RANDOM"==d||"FROM_END"==d?Blockly.Dart.ORDER_NONE:Blockly.Dart.ORDER_UNARY_POSTFIX)||"[]";if(("RANDOM"!=d||"REMOVE"!=c)&&"FROM_END"!=d||e.match(/^\w+$/))switch(d){case "FIRST":if("GET"==c)return[e+".first",
+Blockly.Dart.ORDER_UNARY_POSTFIX];if("GET_REMOVE"==c)return[e+".removeAt(0)",Blockly.Dart.ORDER_UNARY_POSTFIX];if("REMOVE"==c)return e+".removeAt(0);\n";break;case "LAST":if("GET"==c)return[e+".last",Blockly.Dart.ORDER_UNARY_POSTFIX];if("GET_REMOVE"==c)return[e+".removeLast()",Blockly.Dart.ORDER_UNARY_POSTFIX];if("REMOVE"==c)return e+".removeLast();\n";break;case "FROM_START":d=Blockly.Dart.getAdjusted(a,"AT");if("GET"==c)return[e+"["+d+"]",Blockly.Dart.ORDER_UNARY_POSTFIX];if("GET_REMOVE"==c)return[e+
+".removeAt("+d+")",Blockly.Dart.ORDER_UNARY_POSTFIX];if("REMOVE"==c)return e+".removeAt("+d+");\n";break;case "FROM_END":d=Blockly.Dart.getAdjusted(a,"AT",1,!1,Blockly.Dart.ORDER_ADDITIVE);if("GET"==c)return[e+"["+e+".length - "+d+"]",Blockly.Dart.ORDER_UNARY_POSTFIX];if("GET_REMOVE"==c||"REMOVE"==c){a=e+".removeAt("+e+".length - "+d+")";if("GET_REMOVE"==c)return[a,Blockly.Dart.ORDER_UNARY_POSTFIX];if("REMOVE"==c)return a+";\n"}break;case "RANDOM":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";
+if("REMOVE"==c)return c=Blockly.Dart.variableDB_.getDistinctName("tmp_x",Blockly.Variables.NAME_TYPE),"int "+c+" = new Math.Random().nextInt("+e+".length);\n"+(e+".removeAt("+c+");\n");if("GET"==c)return c=Blockly.Dart.provideFunction_("lists_get_random_item",["dynamic "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List my_list) {"," int x = new Math.Random().nextInt(my_list.length);"," return my_list[x];","}"]),[c+"("+e+")",Blockly.Dart.ORDER_UNARY_POSTFIX];if("GET_REMOVE"==c)return c=Blockly.Dart.provideFunction_("lists_remove_random_item",
+["dynamic "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List my_list) {"," int x = new Math.Random().nextInt(my_list.length);"," return my_list.removeAt(x);","}"]),[c+"("+e+")",Blockly.Dart.ORDER_UNARY_POSTFIX]}else{if("RANDOM"==d)return Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;",a=b(),c=Blockly.Dart.variableDB_.getDistinctName("tmp_x",Blockly.Variables.NAME_TYPE),a+("int "+c+" = new Math.Random().nextInt("+e+".length);\n")+(e+".removeAt("+c+");\n");if("REMOVE"==c)return d=
+Blockly.Dart.getAdjusted(a,"AT",1,!1,Blockly.Dart.ORDER_ADDITIVE),a=b(),a+=e+".removeAt("+e+".length - "+d+");\n";if("GET"==c)return d=Blockly.Dart.getAdjusted(a,"AT",1),c=Blockly.Dart.provideFunction_("lists_get_from_end",["dynamic "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List my_list, num x) {"," x = my_list.length - x;"," return my_list[x];","}"]),[c+"("+e+", "+d+")",Blockly.Dart.ORDER_UNARY_POSTFIX];if("GET_REMOVE"==c)return d=Blockly.Dart.getAdjusted(a,"AT",1),c=Blockly.Dart.provideFunction_("lists_remove_from_end",
+["dynamic "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List my_list, num x) {"," x = my_list.length - x;"," return my_list.removeAt(x);","}"]),[c+"("+e+", "+d+")",Blockly.Dart.ORDER_UNARY_POSTFIX]}throw"Unhandled combination (lists_getIndex).";};
+Blockly.Dart.lists_setIndex=function(a){function b(){if(e.match(/^\w+$/))return"";var a=Blockly.Dart.variableDB_.getDistinctName("tmp_list",Blockly.Variables.NAME_TYPE),b="List "+a+" = "+e+";\n";e=a;return b}var c=a.getFieldValue("MODE")||"GET",d=a.getFieldValue("WHERE")||"FROM_START",e=Blockly.Dart.valueToCode(a,"LIST",Blockly.Dart.ORDER_UNARY_POSTFIX)||"[]",f=Blockly.Dart.valueToCode(a,"TO",Blockly.Dart.ORDER_ASSIGNMENT)||"null";switch(d){case "FIRST":if("SET"==c)return e+"[0] = "+f+";\n";if("INSERT"==
+c)return e+".insert(0, "+f+");\n";break;case "LAST":if("SET"==c)return a=b(),a+(e+"["+e+".length - 1] = "+f+";\n");if("INSERT"==c)return e+".add("+f+");\n";break;case "FROM_START":d=Blockly.Dart.getAdjusted(a,"AT");if("SET"==c)return e+"["+d+"] = "+f+";\n";if("INSERT"==c)return e+".insert("+d+", "+f+");\n";break;case "FROM_END":d=Blockly.Dart.getAdjusted(a,"AT",1,!1,Blockly.Dart.ORDER_ADDITIVE);a=b();if("SET"==c)return a+(e+"["+e+".length - "+d+"] = "+f+";\n");if("INSERT"==c)return a+(e+".insert("+
+e+".length - "+d+", "+f+");\n");break;case "RANDOM":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";a=b();d=Blockly.Dart.variableDB_.getDistinctName("tmp_x",Blockly.Variables.NAME_TYPE);a+="int "+d+" = new Math.Random().nextInt("+e+".length);\n";if("SET"==c)return a+(e+"["+d+"] = "+f+";\n");if("INSERT"==c)return a+(e+".insert("+d+", "+f+");\n")}throw"Unhandled combination (lists_setIndex).";};
+Blockly.Dart.lists_getSublist=function(a){var b=Blockly.Dart.valueToCode(a,"LIST",Blockly.Dart.ORDER_UNARY_POSTFIX)||"[]",c=a.getFieldValue("WHERE1"),d=a.getFieldValue("WHERE2");if(b.match(/^\w+$/)||"FROM_END"!=c&&"FROM_START"==d){switch(c){case "FROM_START":var e=Blockly.Dart.getAdjusted(a,"AT1");break;case "FROM_END":e=Blockly.Dart.getAdjusted(a,"AT1",1,!1,Blockly.Dart.ORDER_ADDITIVE);e=b+".length - "+e;break;case "FIRST":e="0";break;default:throw"Unhandled option (lists_getSublist).";}switch(d){case "FROM_START":var f=
+Blockly.Dart.getAdjusted(a,"AT2",1);break;case "FROM_END":f=Blockly.Dart.getAdjusted(a,"AT2",0,!1,Blockly.Dart.ORDER_ADDITIVE);f=b+".length - "+f;break;case "LAST":break;default:throw"Unhandled option (lists_getSublist).";}a="LAST"==d?b+".sublist("+e+")":b+".sublist("+e+", "+f+")"}else e=Blockly.Dart.getAdjusted(a,"AT1"),f=Blockly.Dart.getAdjusted(a,"AT2"),a=Blockly.Dart.provideFunction_("lists_get_sublist",["List "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(list, where1, at1, where2, at2) {"," int getAt(where, at) {",
+" if (where == 'FROM_END') {"," at = list.length - 1 - at;"," } else if (where == 'FIRST') {"," at = 0;"," } else if (where == 'LAST') {"," at = list.length - 1;"," } else if (where != 'FROM_START') {"," throw 'Unhandled option (lists_getSublist).';"," }"," return at;"," }"," at1 = getAt(where1, at1);"," at2 = getAt(where2, at2) + 1;"," return list.sublist(at1, at2);","}"])+"("+b+", '"+c+"', "+e+", '"+d+"', "+f+")";return[a,Blockly.Dart.ORDER_UNARY_POSTFIX]};
+Blockly.Dart.lists_sort=function(a){var b=Blockly.Dart.valueToCode(a,"LIST",Blockly.Dart.ORDER_NONE)||"[]",c="1"===a.getFieldValue("DIRECTION")?1:-1;a=a.getFieldValue("TYPE");return[Blockly.Dart.provideFunction_("lists_sort",["List "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(list, type, direction) {"," var compareFuncs = {",' "NUMERIC": (a, b) => direction * a.compareTo(b),',' "TEXT": (a, b) => direction * a.toString().compareTo(b.toString()),',' "IGNORE_CASE": '," (a, b) => direction * ",
" a.toString().toLowerCase().compareTo(b.toString().toLowerCase())"," };"," list = new List.from(list);"," var compare = compareFuncs[type];"," list.sort(compare);"," return list;","}"])+"("+b+', "'+a+'", '+c+")",Blockly.Dart.ORDER_UNARY_POSTFIX]};
Blockly.Dart.lists_split=function(a){var b=Blockly.Dart.valueToCode(a,"INPUT",Blockly.Dart.ORDER_UNARY_POSTFIX),c=Blockly.Dart.valueToCode(a,"DELIM",Blockly.Dart.ORDER_NONE)||"''";a=a.getFieldValue("MODE");if("SPLIT"==a)b||(b="''"),a="split";else if("JOIN"==a)b||(b="[]"),a="join";else throw"Unknown mode: "+a;return[b+"."+a+"("+c+")",Blockly.Dart.ORDER_UNARY_POSTFIX]};Blockly.Dart.logic={};Blockly.Dart.controls_if=function(a){for(var b=0,c=Blockly.Dart.valueToCode(a,"IF"+b,Blockly.Dart.ORDER_NONE)||"false",d=Blockly.Dart.statementToCode(a,"DO"+b),e="if ("+c+") {\n"+d+"}",b=1;b<=a.elseifCount_;b++)c=Blockly.Dart.valueToCode(a,"IF"+b,Blockly.Dart.ORDER_NONE)||"false",d=Blockly.Dart.statementToCode(a,"DO"+b),e+=" else if ("+c+") {\n"+d+"}";a.elseCount_&&(d=Blockly.Dart.statementToCode(a,"ELSE"),e+=" else {\n"+d+"}");return e+"\n"};
Blockly.Dart.logic_compare=function(a){var b={EQ:"==",NEQ:"!=",LT:"<",LTE:"<=",GT:">",GTE:">="}[a.getFieldValue("OP")],c="=="==b||"!="==b?Blockly.Dart.ORDER_EQUALITY:Blockly.Dart.ORDER_RELATIONAL,d=Blockly.Dart.valueToCode(a,"A",c)||"0";a=Blockly.Dart.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]};
@@ -56,11 +61,11 @@ Blockly.Dart.math_number_property=function(a){var b=Blockly.Dart.valueToCode(a,"
Blockly.Dart.math_change=function(a){var b=Blockly.Dart.valueToCode(a,"DELTA",Blockly.Dart.ORDER_ADDITIVE)||"0";a=Blockly.Dart.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE);return a+" = ("+a+" is num ? "+a+" : 0) + "+b+";\n"};Blockly.Dart.math_round=Blockly.Dart.math_single;Blockly.Dart.math_trig=Blockly.Dart.math_single;
Blockly.Dart.math_on_list=function(a){var b=a.getFieldValue("OP");a=Blockly.Dart.valueToCode(a,"LIST",Blockly.Dart.ORDER_NONE)||"[]";switch(b){case "SUM":b=Blockly.Dart.provideFunction_("math_sum",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," num sumVal = 0;"," myList.forEach((num entry) {sumVal += entry;});"," return sumVal;","}"]);b=b+"("+a+")";break;case "MIN":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";b=Blockly.Dart.provideFunction_("math_min",
["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," if (myList.isEmpty) return null;"," num minVal = myList[0];"," myList.forEach((num entry) {minVal = Math.min(minVal, entry);});"," return minVal;","}"]);b=b+"("+a+")";break;case "MAX":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";b=Blockly.Dart.provideFunction_("math_max",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," if (myList.isEmpty) return null;"," num maxVal = myList[0];",
-" myList.forEach((num entry) {maxVal = Math.max(maxVal, entry);});"," return maxVal;","}"]);b=b+"("+a+")";break;case "AVERAGE":b=Blockly.Dart.provideFunction_("math_mean",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," // First filter list for numbers only."," List localList = new List.from(myList);"," localList.removeMatching((a) => a is! num);"," if (localList.isEmpty) return null;"," num sumVal = 0;"," localList.forEach((num entry) {sumVal += entry;});"," return sumVal / localList.length;",
-"}"]);b=b+"("+a+")";break;case "MEDIAN":b=Blockly.Dart.provideFunction_("math_median",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," // First filter list for numbers only, then sort, then return middle value"," // or the average of two middle values if list has an even number of elements."," List localList = new List.from(myList);"," localList.removeMatching((a) => a is! num);"," if (localList.isEmpty) return null;"," localList.sort((a, b) => (a - b));"," int index = localList.length ~/ 2;",
+" myList.forEach((num entry) {maxVal = Math.max(maxVal, entry);});"," return maxVal;","}"]);b=b+"("+a+")";break;case "AVERAGE":b=Blockly.Dart.provideFunction_("math_mean",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," // First filter list for numbers only."," List localList = new List.from(myList);"," localList.removeWhere((a) => a is! num);"," if (localList.isEmpty) return null;"," num sumVal = 0;"," localList.forEach((num entry) {sumVal += entry;});"," return sumVal / localList.length;",
+"}"]);b=b+"("+a+")";break;case "MEDIAN":b=Blockly.Dart.provideFunction_("math_median",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," // First filter list for numbers only, then sort, then return middle value"," // or the average of two middle values if list has an even number of elements."," List localList = new List.from(myList);"," localList.removeWhere((a) => a is! num);"," if (localList.isEmpty) return null;"," localList.sort((a, b) => (a - b));"," int index = localList.length ~/ 2;",
" if (localList.length % 2 == 1) {"," return localList[index];"," } else {"," return (localList[index - 1] + localList[index]) / 2;"," }","}"]);b=b+"("+a+")";break;case "MODE":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";b=Blockly.Dart.provideFunction_("math_modes",["List "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List values) {"," List modes = [];"," List counts = [];"," int maxCount = 0;"," for (int i = 0; i < values.length; i++) {"," var value = values[i];",
" bool found = false;"," int thisCount;"," for (int j = 0; j < counts.length; j++) {"," if (counts[j][0] == value) {"," thisCount = ++counts[j][1];"," found = true;"," break;"," }"," }"," if (!found) {"," counts.add([value, 1]);"," thisCount = 1;"," }"," maxCount = Math.max(thisCount, maxCount);"," }"," for (int j = 0; j < counts.length; j++) {"," if (counts[j][1] == maxCount) {"," modes.add(counts[j][0]);"," }"," }"," return modes;",
-"}"]);b=b+"("+a+")";break;case "STD_DEV":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";b=Blockly.Dart.provideFunction_("math_standard_deviation",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," // First filter list for numbers only."," List numbers = new List.from(myList);"," numbers.removeMatching((a) => a is! num);"," if (numbers.isEmpty) return null;"," num n = numbers.length;"," num sum = 0;"," numbers.forEach((x) => sum += x);"," num mean = sum / n;",
+"}"]);b=b+"("+a+")";break;case "STD_DEV":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";b=Blockly.Dart.provideFunction_("math_standard_deviation",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," // First filter list for numbers only."," List numbers = new List.from(myList);"," numbers.removeWhere((a) => a is! num);"," if (numbers.isEmpty) return null;"," num n = numbers.length;"," num sum = 0;"," numbers.forEach((x) => sum += x);"," num mean = sum / n;",
" num sumSquare = 0;"," numbers.forEach((x) => sumSquare += Math.pow(x - mean, 2));"," return Math.sqrt(sumSquare / n);","}"]);b=b+"("+a+")";break;case "RANDOM":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";b=Blockly.Dart.provideFunction_("math_random_item",["dynamic "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," int x = new Math.Random().nextInt(myList.length);"," return myList[x];","}"]);b=b+"("+a+")";break;default:throw"Unknown operator: "+b;}return[b,
Blockly.Dart.ORDER_UNARY_POSTFIX]};Blockly.Dart.math_modulo=function(a){var b=Blockly.Dart.valueToCode(a,"DIVIDEND",Blockly.Dart.ORDER_MULTIPLICATIVE)||"0";a=Blockly.Dart.valueToCode(a,"DIVISOR",Blockly.Dart.ORDER_MULTIPLICATIVE)||"0";return[b+" % "+a,Blockly.Dart.ORDER_MULTIPLICATIVE]};
Blockly.Dart.math_constrain=function(a){Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";var b=Blockly.Dart.valueToCode(a,"VALUE",Blockly.Dart.ORDER_NONE)||"0",c=Blockly.Dart.valueToCode(a,"LOW",Blockly.Dart.ORDER_NONE)||"0";a=Blockly.Dart.valueToCode(a,"HIGH",Blockly.Dart.ORDER_NONE)||"double.INFINITY";return["Math.min(Math.max("+b+", "+c+"), "+a+")",Blockly.Dart.ORDER_UNARY_POSTFIX]};
@@ -71,15 +76,17 @@ d+";\n");for(var e=d?"dynamic":"void",f=[],g=0;g list = str.split(exp);"," final title = new StringBuffer();"," for (String part in list) {"," if (part.length > 0) {",
-" title.write(part[0].toUpperCase());"," if (part.length > 0) {"," title.write(part.substring(1).toLowerCase());"," }"," }"," }"," return title.toString();","}"]),a=Blockly.Dart.valueToCode(a,"TEXT",Blockly.Dart.ORDER_NONE)||"''",a=b+"("+a+")");return[a,Blockly.Dart.ORDER_UNARY_POSTFIX]};
+Blockly.Dart.text_join=function(a){switch(a.itemCount_){case 0:return["''",Blockly.Dart.ORDER_ATOMIC];case 1:return[(Blockly.Dart.valueToCode(a,"ADD0",Blockly.Dart.ORDER_UNARY_POSTFIX)||"''")+".toString()",Blockly.Dart.ORDER_UNARY_POSTFIX];default:for(var b=Array(a.itemCount_),c=0;c list = str.split(exp);"," final title = new StringBuffer();"," for (String part in list) {",
+" if (part.length > 0) {"," title.write(part[0].toUpperCase());"," if (part.length > 0) {"," title.write(part.substring(1).toLowerCase());"," }"," }"," }"," return title.toString();","}"])+"("+a+")",Blockly.Dart.ORDER_UNARY_POSTFIX]};
Blockly.Dart.text_trim=function(a){var b={LEFT:".replaceFirst(new RegExp(r'^\\s+'), '')",RIGHT:".replaceFirst(new RegExp(r'\\s+$'), '')",BOTH:".trim()"}[a.getFieldValue("MODE")];return[(Blockly.Dart.valueToCode(a,"TEXT",Blockly.Dart.ORDER_UNARY_POSTFIX)||"''")+b,Blockly.Dart.ORDER_UNARY_POSTFIX]};Blockly.Dart.text_print=function(a){return"print("+(Blockly.Dart.valueToCode(a,"TEXT",Blockly.Dart.ORDER_NONE)||"''")+");\n"};
Blockly.Dart.text_prompt_ext=function(a){Blockly.Dart.definitions_.import_dart_html="import 'dart:html' as Html;";var b="Html.window.prompt("+(a.getField("TEXT")?Blockly.Dart.quote_(a.getFieldValue("TEXT")):Blockly.Dart.valueToCode(a,"TEXT",Blockly.Dart.ORDER_NONE)||"''")+", '')";"NUMBER"==a.getFieldValue("TYPE")&&(Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;",b="Math.parseDouble("+b+")");return[b,Blockly.Dart.ORDER_UNARY_POSTFIX]};Blockly.Dart.text_prompt=Blockly.Dart.text_prompt_ext;Blockly.Dart.variables={};Blockly.Dart.variables_get=function(a){return[Blockly.Dart.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),Blockly.Dart.ORDER_ATOMIC]};Blockly.Dart.variables_set=function(a){var b=Blockly.Dart.valueToCode(a,"VALUE",Blockly.Dart.ORDER_ASSIGNMENT)||"0";return Blockly.Dart.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE)+" = "+b+";\n"};
\ No newline at end of file
diff --git a/demos/blockfactory/blocks.js b/demos/blockfactory/blocks.js
index 5008e6a20..012c76fe0 100644
--- a/demos/blockfactory/blocks.js
+++ b/demos/blockfactory/blocks.js
@@ -505,13 +505,13 @@ Blockly.Blocks['type_group'] = {
// Parse XML to restore the group of types.
this.typeCount_ = parseInt(container.getAttribute('types'), 10);
this.updateShape_();
- for (var x = 0; x < this.typeCount_; x++) {
- this.removeInput('TYPE' + x);
+ for (var i = 0; i < this.typeCount_; i++) {
+ this.removeInput('TYPE' + i);
}
- for (var x = 0; x < this.typeCount_; x++) {
- var input = this.appendValueInput('TYPE' + x)
+ for (var i = 0; i < this.typeCount_; i++) {
+ var input = this.appendValueInput('TYPE' + i)
.setCheck('Type');
- if (x == 0) {
+ if (i == 0) {
input.appendField('any of');
}
}
diff --git a/demos/blockfactory/factory.js b/demos/blockfactory/factory.js
index 3e1cf16a0..1bfdf6ce9 100644
--- a/demos/blockfactory/factory.js
+++ b/demos/blockfactory/factory.js
@@ -501,8 +501,8 @@ function getTypesFrom_(block, name) {
types = [escapeString(typeBlock.getFieldValue('TYPE'))];
} else if (typeBlock.type == 'type_group') {
types = [];
- for (var n = 0; n < typeBlock.typeCount_; n++) {
- types = types.concat(getTypesFrom_(typeBlock, 'TYPE' + n));
+ for (var i = 0; i < typeBlock.typeCount_; i++) {
+ types = types.concat(getTypesFrom_(typeBlock, 'TYPE' + i));
}
// Remove duplicates.
var hash = Object.create(null);
diff --git a/generators/dart.js b/generators/dart.js
index f0d7715ea..6fb1236d4 100644
--- a/generators/dart.js
+++ b/generators/dart.js
@@ -45,16 +45,28 @@ Blockly.Dart = new Blockly.Generator('Dart');
Blockly.Dart.addReservedWords(
// https://www.dartlang.org/docs/spec/latest/dart-language-specification.pdf
// Section 16.1.1
- 'assert,break,case,catch,class,const,continue,default,do,else,enum,extends,false,final,finally,for,if,in,is,new,null,rethrow,return,super,switch,this,throw,true,try,var,void,while,with,' +
+ 'assert,break,case,catch,class,const,continue,default,do,else,enum,' +
+ 'extends,false,final,finally,for,if,in,is,new,null,rethrow,return,super,' +
+ 'switch,this,throw,true,try,var,void,while,with,' +
// https://api.dartlang.org/dart_core.html
- 'print,identityHashCode,identical,BidirectionalIterator,Comparable,double,Function,int,Invocation,Iterable,Iterator,List,Map,Match,num,Pattern,RegExp,Set,StackTrace,String,StringSink,Type,bool,DateTime,Deprecated,Duration,Expando,Null,Object,RuneIterator,Runes,Stopwatch,StringBuffer,Symbol,Uri,Comparator,AbstractClassInstantiationError,ArgumentError,AssertionError,CastError,ConcurrentModificationError,CyclicInitializationError,Error,Exception,FallThroughError,FormatException,IntegerDivisionByZeroException,NoSuchMethodError,NullThrownError,OutOfMemoryError,RangeError,StackOverflowError,StateError,TypeError,UnimplementedError,UnsupportedError');
+ 'print,identityHashCode,identical,BidirectionalIterator,Comparable,' +
+ 'double,Function,int,Invocation,Iterable,Iterator,List,Map,Match,num,' +
+ 'Pattern,RegExp,Set,StackTrace,String,StringSink,Type,bool,DateTime,' +
+ 'Deprecated,Duration,Expando,Null,Object,RuneIterator,Runes,Stopwatch,' +
+ 'StringBuffer,Symbol,Uri,Comparator,AbstractClassInstantiationError,' +
+ 'ArgumentError,AssertionError,CastError,ConcurrentModificationError,' +
+ 'CyclicInitializationError,Error,Exception,FallThroughError,' +
+ 'FormatException,IntegerDivisionByZeroException,NoSuchMethodError,' +
+ 'NullThrownError,OutOfMemoryError,RangeError,StackOverflowError,' +
+ 'StateError,TypeError,UnimplementedError,UnsupportedError'
+);
/**
* Order of operation ENUMs.
* https://www.dartlang.org/docs/dart-up-and-running/ch02.html#operator_table
*/
Blockly.Dart.ORDER_ATOMIC = 0; // 0 "" ...
-Blockly.Dart.ORDER_UNARY_POSTFIX = 1; // expr++ expr-- () [] .
+Blockly.Dart.ORDER_UNARY_POSTFIX = 1; // expr++ expr-- () [] . ?.
Blockly.Dart.ORDER_UNARY_PREFIX = 2; // -expr !expr ~expr ++expr --expr
Blockly.Dart.ORDER_MULTIPLICATIVE = 3; // * / % ~/
Blockly.Dart.ORDER_ADDITIVE = 4; // + -
@@ -66,11 +78,18 @@ Blockly.Dart.ORDER_RELATIONAL = 9; // >= > <= < as is is!
Blockly.Dart.ORDER_EQUALITY = 10; // == !=
Blockly.Dart.ORDER_LOGICAL_AND = 11; // &&
Blockly.Dart.ORDER_LOGICAL_OR = 12; // ||
-Blockly.Dart.ORDER_CONDITIONAL = 13; // expr ? expr : expr
-Blockly.Dart.ORDER_CASCADE = 14; // ..
-Blockly.Dart.ORDER_ASSIGNMENT = 15; // = *= /= ~/= %= += -= <<= >>= &= ^= |=
+Blockly.Dart.ORDER_IF_NULL = 13; // ??
+Blockly.Dart.ORDER_CONDITIONAL = 14; // expr ? expr : expr
+Blockly.Dart.ORDER_CASCADE = 15; // ..
+Blockly.Dart.ORDER_ASSIGNMENT = 16; // = *= /= ~/= %= += -= <<= >>= &= ^= |=
Blockly.Dart.ORDER_NONE = 99; // (...)
+/**
+ * Allow for switching between one and zero based indexing for lists and text,
+ * one based by default.
+ */
+Blockly.Dart.ONE_BASED_INDEXING = true;
+
/**
* Initialise the database of variable names.
* @param {!Blockly.Workspace} workspace Workspace to generate code from.
@@ -182,9 +201,9 @@ Blockly.Dart.scrub_ = function(block, code) {
}
// Collect comments for all value arguments.
// Don't collect comments for nested statements.
- for (var x = 0; x < block.inputList.length; x++) {
- if (block.inputList[x].type == Blockly.INPUT_VALUE) {
- var childBlock = block.inputList[x].connection.targetBlock();
+ for (var i = 0; i < block.inputList.length; i++) {
+ if (block.inputList[i].type == Blockly.INPUT_VALUE) {
+ var childBlock = block.inputList[i].connection.targetBlock();
if (childBlock) {
var comment = Blockly.Dart.allNestedComments(childBlock);
if (comment) {
@@ -198,3 +217,63 @@ Blockly.Dart.scrub_ = function(block, code) {
var nextCode = Blockly.Dart.blockToCode(nextBlock);
return commentCode + code + nextCode;
};
+
+/**
+ * Gets a property and adjusts the value while taking into account indexing.
+ * @param {!Blockly.Block} block The block.
+ * @param {string} atId The property ID of the element to get.
+ * @param {number=} opt_delta Value to add.
+ * @param {boolean=} opt_negate Whether to negate the value.
+ * @param {number=} opt_order The highest order acting on this value.
+ * @return {string|number}
+ */
+Blockly.Dart.getAdjusted = function(block, atId, opt_delta, opt_negate,
+ opt_order) {
+ var delta = opt_delta || 0;
+ var order = opt_order || Blockly.Dart.ORDER_NONE;
+ if (Blockly.Dart.ONE_BASED_INDEXING) {
+ delta--;
+ }
+ var defaultAtIndex = Blockly.Dart.ONE_BASED_INDEXING ? '1' : '0';
+ if (delta) {
+ var at = Blockly.Dart.valueToCode(block, atId,
+ Blockly.Dart.ORDER_ADDITIVE) || defaultAtIndex;
+ } else if (opt_negate) {
+ var at = Blockly.Dart.valueToCode(block, atId,
+ Blockly.Dart.ORDER_UNARY_PREFIX) || defaultAtIndex;
+ } else {
+ var at = Blockly.Dart.valueToCode(block, atId, order) ||
+ defaultAtIndex;
+ }
+
+ if (Blockly.isNumber(at)) {
+ // If the index is a naked number, adjust it right now.
+ at = parseInt(at, 10) + delta;
+ if (opt_negate) {
+ at = -at;
+ }
+ } else {
+ // If the index is dynamic, adjust it in code.
+ if (delta > 0) {
+ at = at + ' + ' + delta;
+ var innerOrder = Blockly.Dart.ORDER_ADDITIVE;
+ } else if (delta < 0) {
+ at = at + ' - ' + -delta;
+ var innerOrder = Blockly.Dart.ORDER_ADDITIVE;
+ }
+ if (opt_negate) {
+ if (delta) {
+ at = '-(' + at + ')';
+ } else {
+ at = '-' + at;
+ }
+ var innerOrder = Blockly.Dart.ORDER_UNARY_PREFIX;
+ }
+ innerOrder = Math.floor(innerOrder);
+ order = Math.floor(order);
+ if (innerOrder && order >= innerOrder) {
+ at = '(' + at + ')';
+ }
+ }
+ return at;
+};
diff --git a/generators/dart/colour.js b/generators/dart/colour.js
index d73415522..7ded91419 100644
--- a/generators/dart/colour.js
+++ b/generators/dart/colour.js
@@ -43,13 +43,13 @@ Blockly.Dart['colour_random'] = function(block) {
'import \'dart:math\' as Math;';
var functionName = Blockly.Dart.provideFunction_(
'colour_random',
- [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '() {',
- ' String hex = \'0123456789abcdef\';',
- ' var rnd = new Math.Random();',
- ' return \'#${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}\'',
- ' \'${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}\'',
- ' \'${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}\';',
- '}']);
+ ['String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '() {',
+ ' String hex = \'0123456789abcdef\';',
+ ' var rnd = new Math.Random();',
+ ' return \'#${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}\'',
+ ' \'${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}\'',
+ ' \'${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}\';',
+ '}']);
var code = functionName + '()';
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
};
@@ -67,22 +67,22 @@ Blockly.Dart['colour_rgb'] = function(block) {
'import \'dart:math\' as Math;';
var functionName = Blockly.Dart.provideFunction_(
'colour_rgb',
- [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(num r, num g, num b) {',
- ' num rn = (Math.max(Math.min(r, 1), 0) * 255).round();',
- ' String rs = rn.toInt().toRadixString(16);',
- ' rs = \'0$rs\';',
- ' rs = rs.substring(rs.length - 2);',
- ' num gn = (Math.max(Math.min(g, 1), 0) * 255).round();',
- ' String gs = gn.toInt().toRadixString(16);',
- ' gs = \'0$gs\';',
- ' gs = gs.substring(gs.length - 2);',
- ' num bn = (Math.max(Math.min(b, 1), 0) * 255).round();',
- ' String bs = bn.toInt().toRadixString(16);',
- ' bs = \'0$bs\';',
- ' bs = bs.substring(bs.length - 2);',
- ' return \'#$rs$gs$bs\';',
- '}']);
+ ' num rn = (Math.max(Math.min(r, 1), 0) * 255).round();',
+ ' String rs = rn.toInt().toRadixString(16);',
+ ' rs = \'0$rs\';',
+ ' rs = rs.substring(rs.length - 2);',
+ ' num gn = (Math.max(Math.min(g, 1), 0) * 255).round();',
+ ' String gs = gn.toInt().toRadixString(16);',
+ ' gs = \'0$gs\';',
+ ' gs = gs.substring(gs.length - 2);',
+ ' num bn = (Math.max(Math.min(b, 1), 0) * 255).round();',
+ ' String bs = bn.toInt().toRadixString(16);',
+ ' bs = \'0$bs\';',
+ ' bs = bs.substring(bs.length - 2);',
+ ' return \'#$rs$gs$bs\';',
+ '}']);
var code = functionName + '(' + red + ', ' + green + ', ' + blue + ')';
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
};
@@ -100,29 +100,29 @@ Blockly.Dart['colour_blend'] = function(block) {
'import \'dart:math\' as Math;';
var functionName = Blockly.Dart.provideFunction_(
'colour_blend',
- [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(String c1, String c2, num ratio) {',
- ' ratio = Math.max(Math.min(ratio, 1), 0);',
- ' int r1 = int.parse(\'0x${c1.substring(1, 3)}\');',
- ' int g1 = int.parse(\'0x${c1.substring(3, 5)}\');',
- ' int b1 = int.parse(\'0x${c1.substring(5, 7)}\');',
- ' int r2 = int.parse(\'0x${c2.substring(1, 3)}\');',
- ' int g2 = int.parse(\'0x${c2.substring(3, 5)}\');',
- ' int b2 = int.parse(\'0x${c2.substring(5, 7)}\');',
- ' num rn = (r1 * (1 - ratio) + r2 * ratio).round();',
- ' String rs = rn.toInt().toRadixString(16);',
- ' num gn = (g1 * (1 - ratio) + g2 * ratio).round();',
- ' String gs = gn.toInt().toRadixString(16);',
- ' num bn = (b1 * (1 - ratio) + b2 * ratio).round();',
- ' String bs = bn.toInt().toRadixString(16);',
- ' rs = \'0$rs\';',
- ' rs = rs.substring(rs.length - 2);',
- ' gs = \'0$gs\';',
- ' gs = gs.substring(gs.length - 2);',
- ' bs = \'0$bs\';',
- ' bs = bs.substring(bs.length - 2);',
- ' return \'#$rs$gs$bs\';',
- '}']);
+ ' ratio = Math.max(Math.min(ratio, 1), 0);',
+ ' int r1 = int.parse(\'0x${c1.substring(1, 3)}\');',
+ ' int g1 = int.parse(\'0x${c1.substring(3, 5)}\');',
+ ' int b1 = int.parse(\'0x${c1.substring(5, 7)}\');',
+ ' int r2 = int.parse(\'0x${c2.substring(1, 3)}\');',
+ ' int g2 = int.parse(\'0x${c2.substring(3, 5)}\');',
+ ' int b2 = int.parse(\'0x${c2.substring(5, 7)}\');',
+ ' num rn = (r1 * (1 - ratio) + r2 * ratio).round();',
+ ' String rs = rn.toInt().toRadixString(16);',
+ ' num gn = (g1 * (1 - ratio) + g2 * ratio).round();',
+ ' String gs = gn.toInt().toRadixString(16);',
+ ' num bn = (b1 * (1 - ratio) + b2 * ratio).round();',
+ ' String bs = bn.toInt().toRadixString(16);',
+ ' rs = \'0$rs\';',
+ ' rs = rs.substring(rs.length - 2);',
+ ' gs = \'0$gs\';',
+ ' gs = gs.substring(gs.length - 2);',
+ ' bs = \'0$bs\';',
+ ' bs = bs.substring(bs.length - 2);',
+ ' return \'#$rs$gs$bs\';',
+ '}']);
var code = functionName + '(' + c1 + ', ' + c2 + ', ' + ratio + ')';
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
};
diff --git a/generators/dart/lists.js b/generators/dart/lists.js
index 24fcd2243..ae5ecc20e 100644
--- a/generators/dart/lists.js
+++ b/generators/dart/lists.js
@@ -38,49 +38,52 @@ Blockly.Dart['lists_create_empty'] = function(block) {
Blockly.Dart['lists_create_with'] = function(block) {
// Create a list with any number of elements of any type.
- var code = new Array(block.itemCount_);
- for (var n = 0; n < block.itemCount_; n++) {
- code[n] = Blockly.Dart.valueToCode(block, 'ADD' + n,
+ var elements = new Array(block.itemCount_);
+ for (var i = 0; i < block.itemCount_; i++) {
+ elements[i] = Blockly.Dart.valueToCode(block, 'ADD' + i,
Blockly.Dart.ORDER_NONE) || 'null';
}
- code = '[' + code.join(', ') + ']';
+ var code = '[' + elements.join(', ') + ']';
return [code, Blockly.Dart.ORDER_ATOMIC];
};
Blockly.Dart['lists_repeat'] = function(block) {
// Create a list with one element repeated.
- var argument0 = Blockly.Dart.valueToCode(block, 'ITEM',
- Blockly.Dart.ORDER_NONE) || 'null';
- var argument1 = Blockly.Dart.valueToCode(block, 'NUM',
- Blockly.Dart.ORDER_NONE) || '0';
- var code = 'new List.filled(' + argument1 + ', ' + argument0 + ')';
+ var element = Blockly.Dart.valueToCode(block, 'ITEM',
+ Blockly.Dart.ORDER_NONE) || 'null';
+ var repeatCount = Blockly.Dart.valueToCode(block, 'NUM',
+ Blockly.Dart.ORDER_NONE) || '0';
+ var code = 'new List.filled(' + repeatCount + ', ' + element + ')';
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
};
Blockly.Dart['lists_length'] = function(block) {
// String or array length.
- var argument0 = Blockly.Dart.valueToCode(block, 'VALUE',
+ var list = Blockly.Dart.valueToCode(block, 'VALUE',
Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]';
- return [argument0 + '.length', Blockly.Dart.ORDER_UNARY_POSTFIX];
+ return [list + '.length', Blockly.Dart.ORDER_UNARY_POSTFIX];
};
Blockly.Dart['lists_isEmpty'] = function(block) {
// Is the string null or array empty?
- var argument0 = Blockly.Dart.valueToCode(block, 'VALUE',
+ var list = Blockly.Dart.valueToCode(block, 'VALUE',
Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]';
- return [argument0 + '.isEmpty', Blockly.Dart.ORDER_UNARY_POSTFIX];
+ return [list + '.isEmpty', Blockly.Dart.ORDER_UNARY_POSTFIX];
};
Blockly.Dart['lists_indexOf'] = function(block) {
// Find an item in the list.
var operator = block.getFieldValue('END') == 'FIRST' ?
'indexOf' : 'lastIndexOf';
- var argument0 = Blockly.Dart.valueToCode(block, 'FIND',
+ var item = Blockly.Dart.valueToCode(block, 'FIND',
Blockly.Dart.ORDER_NONE) || '\'\'';
- var argument1 = Blockly.Dart.valueToCode(block, 'VALUE',
+ var list = Blockly.Dart.valueToCode(block, 'VALUE',
Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]';
- var code = argument1 + '.' + operator + '(' + argument0 + ') + 1';
- return [code, Blockly.Dart.ORDER_ADDITIVE];
+ var code = list + '.' + operator + '(' + item + ')';
+ if (Blockly.Dart.ONE_BASED_INDEXING) {
+ return [code + ' + 1', Blockly.Dart.ORDER_ADDITIVE];
+ }
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
};
Blockly.Dart['lists_getIndex'] = function(block) {
@@ -88,94 +91,156 @@ Blockly.Dart['lists_getIndex'] = function(block) {
// Note: Until January 2013 this block did not have MODE or WHERE inputs.
var mode = block.getFieldValue('MODE') || 'GET';
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.Dart.valueToCode(block, 'AT',
- Blockly.Dart.ORDER_UNARY_PREFIX) || '1';
- var list = Blockly.Dart.valueToCode(block, 'VALUE',
- Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]';
+ var listOrder = (where == 'RANDOM' || where == 'FROM_END') ?
+ Blockly.Dart.ORDER_NONE : Blockly.Dart.ORDER_UNARY_POSTFIX;
+ var list = Blockly.Dart.valueToCode(block, 'VALUE', listOrder) || '[]';
+ // Cache non-trivial values to variables to prevent repeated look-ups.
+ // Closure, which accesses and modifies 'list'.
+ function cacheList() {
+ var listVar = Blockly.Dart.variableDB_.getDistinctName(
+ 'tmp_list', Blockly.Variables.NAME_TYPE);
+ var code = 'List ' + listVar + ' = ' + list + ';\n';
+ list = listVar;
+ return code;
+ }
+ // If `list` would be evaluated more than once (which is the case for
+ // RANDOM REMOVE and FROM_END) and is non-trivial, make sure to access it
+ // only once.
+ if (((where == 'RANDOM' && mode == 'REMOVE') || where == 'FROM_END') &&
+ !list.match(/^\w+$/)) {
+ // `list` is an expression, so we may not evaluate it more than once.
+ if (where == 'RANDOM') {
+ Blockly.Dart.definitions_['import_dart_math'] =
+ 'import \'dart:math\' as Math;';
+ // We can use multiple statements.
+ var code = cacheList();
+ var xVar = Blockly.Dart.variableDB_.getDistinctName(
+ 'tmp_x', Blockly.Variables.NAME_TYPE);
+ code += 'int ' + xVar + ' = new Math.Random().nextInt(' + list +
+ '.length);\n';
+ code += list + '.removeAt(' + xVar + ');\n';
+ return code;
+ } else { // where == 'FROM_END'
+ if (mode == 'REMOVE') {
+ // We can use multiple statements.
+ var at = Blockly.Dart.getAdjusted(block, 'AT', 1, false,
+ Blockly.Dart.ORDER_ADDITIVE);
+ var code = cacheList();
+ code += list + '.removeAt(' + list + '.length' + ' - ' + at + ');\n';
+ return code;
- if (where == 'FIRST') {
- if (mode == 'GET') {
- var code = list + '.first';
- return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
- } else if (mode == 'GET_REMOVE') {
- var code = list + '.removeAt(0)';
- return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
- } else if (mode == 'REMOVE') {
- return list + '.removeAt(0);\n';
- }
- } else if (where == 'LAST') {
- if (mode == 'GET') {
- var code = list + '.last';
- return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
- } else if (mode == 'GET_REMOVE') {
- var code = list + '.removeLast()';
- return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
- } else if (mode == 'REMOVE') {
- return list + '.removeLast();\n';
- }
- } else if (where == 'FROM_START') {
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at)) {
- // If the index is a naked number, decrement it right now.
- at = parseInt(at, 10) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at += ' - 1';
- }
- if (mode == 'GET') {
- var code = list + '[' + at + ']';
- return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
- } else if (mode == 'GET_REMOVE') {
- var code = list + '.removeAt(' + at + ')';
- return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
- } else if (mode == 'REMOVE') {
- return list + '.removeAt(' + at + ');\n';
- }
- } else if (where == 'FROM_END') {
- if (mode == 'GET') {
- var functionName = Blockly.Dart.provideFunction_(
- 'lists_get_from_end',
- [ 'dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
- '(List myList, num x) {',
- ' x = myList.length - x;',
- ' return myList.removeAt(x);',
- '}']);
- code = functionName + '(' + list + ', ' + at + ')';
- return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
- } else if (mode == 'GET_REMOVE' || mode == 'REMOVE') {
- var functionName = Blockly.Dart.provideFunction_(
- 'lists_remove_from_end',
- [ 'dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
- '(List myList, num x) {',
- ' x = myList.length - x;',
- ' return myList.removeAt(x);',
- '}']);
- code = functionName + '(' + list + ', ' + at + ')';
- if (mode == 'GET_REMOVE') {
+ } else if (mode == 'GET') {
+ var at = Blockly.Dart.getAdjusted(block, 'AT', 1);
+ // We need to create a procedure to avoid reevaluating values.
+ var functionName = Blockly.Dart.provideFunction_(
+ 'lists_get_from_end',
+ ['dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ '(List my_list, num x) {',
+ ' x = my_list.length - x;',
+ ' return my_list[x];',
+ '}']);
+ var code = functionName + '(' + list + ', ' + at + ')';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ } else if (mode == 'GET_REMOVE') {
+ var at = Blockly.Dart.getAdjusted(block, 'AT', 1);
+ // We need to create a procedure to avoid reevaluating values.
+ var functionName = Blockly.Dart.provideFunction_(
+ 'lists_remove_from_end',
+ ['dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ '(List my_list, num x) {',
+ ' x = my_list.length - x;',
+ ' return my_list.removeAt(x);',
+ '}']);
+ var code = functionName + '(' + list + ', ' + at + ')';
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
- } else if (mode == 'REMOVE') {
- return code + ';\n';
}
}
- } else if (where == 'RANDOM') {
- Blockly.Dart.definitions_['import_dart_math'] =
- 'import \'dart:math\' as Math;';
- var functionName = Blockly.Dart.provideFunction_(
- 'lists_get_random_item',
- [ 'dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
- '(List myList, bool remove) {',
- ' int x = new Math.Random().nextInt(myList.length);',
- ' if (remove) {',
- ' return myList.removeAt(x);',
- ' } else {',
- ' return myList[x];',
- ' }',
- '}']);
- code = functionName + '(' + list + ', ' + (mode != 'GET') + ')';
- if (mode == 'GET' || mode == 'GET_REMOVE') {
- return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
- } else if (mode == 'REMOVE') {
- return code + ';\n';
+ } else {
+ // Either `list` is a simple variable, or we only need to refer to `list`
+ // once.
+ switch (where) {
+ case 'FIRST':
+ if (mode == 'GET') {
+ var code = list + '.first';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ } else if (mode == 'GET_REMOVE') {
+ var code = list + '.removeAt(0)';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ } else if (mode == 'REMOVE') {
+ return list + '.removeAt(0);\n';
+ }
+ break;
+ case 'LAST':
+ if (mode == 'GET') {
+ var code = list + '.last';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ } else if (mode == 'GET_REMOVE') {
+ var code = list + '.removeLast()';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ } else if (mode == 'REMOVE') {
+ return list + '.removeLast();\n';
+ }
+ break;
+ case 'FROM_START':
+ var at = Blockly.Dart.getAdjusted(block, 'AT');
+ if (mode == 'GET') {
+ var code = list + '[' + at + ']';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ } else if (mode == 'GET_REMOVE') {
+ var code = list + '.removeAt(' + at + ')';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ } else if (mode == 'REMOVE') {
+ return list + '.removeAt(' + at + ');\n';
+ }
+ break;
+ case 'FROM_END':
+ var at = Blockly.Dart.getAdjusted(block, 'AT', 1, false,
+ Blockly.Dart.ORDER_ADDITIVE);
+ if (mode == 'GET') {
+ var code = list + '[' + list + '.length - ' + at + ']';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ } else if (mode == 'GET_REMOVE' || mode == 'REMOVE') {
+ var code = list + '.removeAt(' + list + '.length - ' + at + ')';
+ if (mode == 'GET_REMOVE') {
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ } else if (mode == 'REMOVE') {
+ return code + ';\n';
+ }
+ }
+ break;
+ case 'RANDOM':
+ Blockly.Dart.definitions_['import_dart_math'] =
+ 'import \'dart:math\' as Math;';
+ if (mode == 'REMOVE') {
+ // We can use multiple statements.
+ var xVar = Blockly.Dart.variableDB_.getDistinctName(
+ 'tmp_x', Blockly.Variables.NAME_TYPE);
+ var code = 'int ' + xVar + ' = new Math.Random().nextInt(' + list +
+ '.length);\n';
+ code += list + '.removeAt(' + xVar + ');\n';
+ return code;
+ } else if (mode == 'GET') {
+ var functionName = Blockly.Dart.provideFunction_(
+ 'lists_get_random_item',
+ ['dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ '(List my_list) {',
+ ' int x = new Math.Random().nextInt(my_list.length);',
+ ' return my_list[x];',
+ '}']);
+ var code = functionName + '(' + list + ')';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ } else if (mode == 'GET_REMOVE') {
+ var functionName = Blockly.Dart.provideFunction_(
+ 'lists_remove_random_item',
+ ['dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ '(List my_list) {',
+ ' int x = new Math.Random().nextInt(my_list.length);',
+ ' return my_list.removeAt(x);',
+ '}']);
+ var code = functionName + '(' + list + ')';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ }
+ break;
}
}
throw 'Unhandled combination (lists_getIndex).';
@@ -184,12 +249,10 @@ Blockly.Dart['lists_getIndex'] = function(block) {
Blockly.Dart['lists_setIndex'] = function(block) {
// Set element at index.
// Note: Until February 2013 this block did not have MODE or WHERE inputs.
- var list = Blockly.Dart.valueToCode(block, 'LIST',
- Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]';
var mode = block.getFieldValue('MODE') || 'GET';
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.Dart.valueToCode(block, 'AT',
- Blockly.Dart.ORDER_ADDITIVE) || '1';
+ var list = Blockly.Dart.valueToCode(block, 'LIST',
+ Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]';
var value = Blockly.Dart.valueToCode(block, 'TO',
Blockly.Dart.ORDER_ASSIGNMENT) || 'null';
// Cache non-trivial values to variables to prevent repeated look-ups.
@@ -204,59 +267,61 @@ Blockly.Dart['lists_setIndex'] = function(block) {
list = listVar;
return code;
}
- if (where == 'FIRST') {
- if (mode == 'SET') {
- return list + '[0] = ' + value + ';\n';
- } else if (mode == 'INSERT') {
- return list + '.insert(0, ' + value + ');\n';
- }
- } else if (where == 'LAST') {
- if (mode == 'SET') {
+ switch (where) {
+ case 'FIRST':
+ if (mode == 'SET') {
+ return list + '[0] = ' + value + ';\n';
+ } else if (mode == 'INSERT') {
+ return list + '.insert(0, ' + value + ');\n';
+ }
+ break;
+ case 'LAST':
+ if (mode == 'SET') {
+ var code = cacheList();
+ code += list + '[' + list + '.length - 1] = ' + value + ';\n';
+ return code;
+ } else if (mode == 'INSERT') {
+ return list + '.add(' + value + ');\n';
+ }
+ break;
+ case 'FROM_START':
+ var at = Blockly.Dart.getAdjusted(block, 'AT');
+ if (mode == 'SET') {
+ return list + '[' + at + '] = ' + value + ';\n';
+ } else if (mode == 'INSERT') {
+ return list + '.insert(' + at + ', ' + value + ');\n';
+ }
+ break;
+ case 'FROM_END':
+ var at = Blockly.Dart.getAdjusted(block, 'AT', 1, false,
+ Blockly.Dart.ORDER_ADDITIVE);
var code = cacheList();
- code += list + '[' + list + '.length - 1] = ' + value + ';\n';
- return code;
- } else if (mode == 'INSERT') {
- return list + '.add(' + value + ');\n';
- }
- } else if (where == 'FROM_START') {
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at)) {
- // If the index is a naked number, decrement it right now.
- at = parseInt(at, 10) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at += ' - 1';
- }
- if (mode == 'SET') {
- return list + '[' + at + '] = ' + value + ';\n';
- } else if (mode == 'INSERT') {
- return list + '.insert(' + at + ', ' + value + ');\n';
- }
- } else if (where == 'FROM_END') {
- var code = cacheList();
- if (mode == 'SET') {
- code += list + '[' + list + '.length - ' + at + '] = ' + value + ';\n';
- return code;
- } else if (mode == 'INSERT') {
- code += list + '.insert(' + list + '.length - ' + at + ', ' +
- value + ');\n';
- return code;
- }
- } else if (where == 'RANDOM') {
- Blockly.Dart.definitions_['import_dart_math'] =
- 'import \'dart:math\' as Math;';
- var code = cacheList();
- var xVar = Blockly.Dart.variableDB_.getDistinctName(
- 'tmp_x', Blockly.Variables.NAME_TYPE);
- code += 'int ' + xVar +
- ' = new Math.Random().nextInt(' + list + '.length);';
- if (mode == 'SET') {
- code += list + '[' + xVar + '] = ' + value + ';\n';
- return code;
- } else if (mode == 'INSERT') {
- code += list + '.insert(' + xVar + ', ' + value + ');\n';
- return code;
- }
+ if (mode == 'SET') {
+ code += list + '[' + list + '.length - ' + at + '] = ' + value +
+ ';\n';
+ return code;
+ } else if (mode == 'INSERT') {
+ code += list + '.insert(' + list + '.length - ' + at + ', ' +
+ value + ');\n';
+ return code;
+ }
+ break;
+ case 'RANDOM':
+ Blockly.Dart.definitions_['import_dart_math'] =
+ 'import \'dart:math\' as Math;';
+ var code = cacheList();
+ var xVar = Blockly.Dart.variableDB_.getDistinctName(
+ 'tmp_x', Blockly.Variables.NAME_TYPE);
+ code += 'int ' + xVar +
+ ' = new Math.Random().nextInt(' + list + '.length);\n';
+ if (mode == 'SET') {
+ code += list + '[' + xVar + '] = ' + value + ';\n';
+ return code;
+ } else if (mode == 'INSERT') {
+ code += list + '.insert(' + xVar + ', ' + value + ');\n';
+ return code;
+ }
+ break;
}
throw 'Unhandled combination (lists_setIndex).';
};
@@ -267,43 +332,67 @@ Blockly.Dart['lists_getSublist'] = function(block) {
Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]';
var where1 = block.getFieldValue('WHERE1');
var where2 = block.getFieldValue('WHERE2');
- var at1 = Blockly.Dart.valueToCode(block, 'AT1',
- Blockly.Dart.ORDER_NONE) || '1';
- var at2 = Blockly.Dart.valueToCode(block, 'AT2',
- Blockly.Dart.ORDER_NONE) || '1';
- if ((where1 == 'FIRST' || where1 == 'FROM_START' && Blockly.isNumber(at1)) &&
- (where2 == 'LAST' || where2 == 'FROM_START' && Blockly.isNumber(at2))) {
- // Simple case that can be done inline.
- at1 = where1 == 'FIRST' ? 0 : parseInt(at1, 10) - 1;
+ if (list.match(/^\w+$/) || (where1 != 'FROM_END' && where2 == 'FROM_START')) {
+ // If the list is a is a variable or doesn't require a call for length,
+ // don't generate a helper function.
+ switch (where1) {
+ case 'FROM_START':
+ var at1 = Blockly.Dart.getAdjusted(block, 'AT1');
+ break;
+ case 'FROM_END':
+ var at1 = Blockly.Dart.getAdjusted(block, 'AT1', 1, false,
+ Blockly.Dart.ORDER_ADDITIVE);
+ at1 = list + '.length - ' + at1;
+ break;
+ case 'FIRST':
+ var at1 = '0';
+ break;
+ default:
+ throw 'Unhandled option (lists_getSublist).';
+ }
+ switch (where2) {
+ case 'FROM_START':
+ var at2 = Blockly.Dart.getAdjusted(block, 'AT2', 1);
+ break;
+ case 'FROM_END':
+ var at2 = Blockly.Dart.getAdjusted(block, 'AT2', 0, false,
+ Blockly.Dart.ORDER_ADDITIVE);
+ at2 = list + '.length - ' + at2;
+ break;
+ case 'LAST':
+ // There is no second index if LAST option is chosen.
+ break;
+ default:
+ throw 'Unhandled option (lists_getSublist).';
+ }
if (where2 == 'LAST') {
- code = list + '.sublist(' + at1 + ')';
+ var code = list + '.sublist(' + at1 + ')';
} else {
- at2 = parseInt(at2, 10);
- code = list + '.sublist(' + at1 + ', ' + at2 + ')';
+ var code = list + '.sublist(' + at1 + ', ' + at2 + ')';
}
} else {
+ var at1 = Blockly.Dart.getAdjusted(block, 'AT1');
+ var at2 = Blockly.Dart.getAdjusted(block, 'AT2');
var functionName = Blockly.Dart.provideFunction_(
'lists_get_sublist',
- [ 'List ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['List ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(list, where1, at1, where2, at2) {',
- ' int getAt(where, at) {',
- ' if (where == \'FROM_START\') {',
- ' at--;',
- ' } else if (where == \'FROM_END\') {',
- ' at = list.length - at;',
- ' } else if (where == \'FIRST\') {',
- ' at = 0;',
- ' } else if (where == \'LAST\') {',
- ' at = list.length - 1;',
- ' } else {',
- ' throw \'Unhandled option (lists_getSublist).\';',
- ' }',
- ' return at;',
- ' }',
- ' at1 = getAt(where1, at1);',
- ' at2 = getAt(where2, at2) + 1;',
- ' return list.sublist(at1, at2);',
- '}']);
+ ' int getAt(where, at) {',
+ ' if (where == \'FROM_END\') {',
+ ' at = list.length - 1 - at;',
+ ' } else if (where == \'FIRST\') {',
+ ' at = 0;',
+ ' } else if (where == \'LAST\') {',
+ ' at = list.length - 1;',
+ ' } else if (where != \'FROM_START\') {',
+ ' throw \'Unhandled option (lists_getSublist).\';',
+ ' }',
+ ' return at;',
+ ' }',
+ ' at1 = getAt(where1, at1);',
+ ' at2 = getAt(where2, at2) + 1;',
+ ' return list.sublist(at1, at2);',
+ '}']);
var code = functionName + '(' + list + ', \'' +
where1 + '\', ' + at1 + ', \'' + where2 + '\', ' + at2 + ')';
}
@@ -312,51 +401,52 @@ Blockly.Dart['lists_getSublist'] = function(block) {
Blockly.Dart['lists_sort'] = function(block) {
// Block for sorting a list.
- var listCode = Blockly.Dart.valueToCode(block, 'LIST',
- Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]';
+ var list = Blockly.Dart.valueToCode(block, 'LIST',
+ Blockly.Dart.ORDER_NONE) || '[]';
var direction = block.getFieldValue('DIRECTION') === '1' ? 1 : -1;
var type = block.getFieldValue('TYPE');
var sortFunctionName = Blockly.Dart.provideFunction_(
- 'lists_sort',
- ['List ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
- '(list, type, direction) {',
- ' var compareFuncs = {',
- ' "NUMERIC": (a, b) => direction * a.compareTo(b),',
- ' "TEXT": (a, b) => direction * a.toString().compareTo(b.toString()),',
- ' "IGNORE_CASE": ',
- ' (a, b) => direction * ',
- ' a.toString().toLowerCase().compareTo(b.toString().toLowerCase())',
- ' };',
- ' list = new List.from(list);', // Clone the list.
- ' var compare = compareFuncs[type];',
- ' list.sort(compare);',
- ' return list;',
- '}']);
- return [sortFunctionName + '(' + listCode + ', ' +
+ 'lists_sort',
+ ['List ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ '(list, type, direction) {',
+ ' var compareFuncs = {',
+ ' "NUMERIC": (a, b) => direction * a.compareTo(b),',
+ ' "TEXT": (a, b) => direction * ' +
+ 'a.toString().compareTo(b.toString()),',
+ ' "IGNORE_CASE": ',
+ ' (a, b) => direction * ',
+ ' a.toString().toLowerCase().compareTo(b.toString().toLowerCase())',
+ ' };',
+ ' list = new List.from(list);', // Clone the list.
+ ' var compare = compareFuncs[type];',
+ ' list.sort(compare);',
+ ' return list;',
+ '}']);
+ return [sortFunctionName + '(' + list + ', ' +
'"' + type + '", ' + direction + ')',
Blockly.Dart.ORDER_UNARY_POSTFIX];
};
Blockly.Dart['lists_split'] = function(block) {
// Block for splitting text into a list, or joining a list into text.
- var value_input = Blockly.Dart.valueToCode(block, 'INPUT',
+ var input = Blockly.Dart.valueToCode(block, 'INPUT',
Blockly.Dart.ORDER_UNARY_POSTFIX);
- var value_delim = Blockly.Dart.valueToCode(block, 'DELIM',
+ var delimiter = Blockly.Dart.valueToCode(block, 'DELIM',
Blockly.Dart.ORDER_NONE) || '\'\'';
var mode = block.getFieldValue('MODE');
if (mode == 'SPLIT') {
- if (!value_input) {
- value_input = '\'\'';
+ if (!input) {
+ input = '\'\'';
}
var functionName = 'split';
} else if (mode == 'JOIN') {
- if (!value_input) {
- value_input = '[]';
+ if (!input) {
+ input = '[]';
}
var functionName = 'join';
} else {
throw 'Unknown mode: ' + mode;
}
- var code = value_input + '.' + functionName + '(' + value_delim + ')';
+ var code = input + '.' + functionName + '(' + delimiter + ')';
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
};
diff --git a/generators/dart/math.js b/generators/dart/math.js
index 2f7c8027a..867822beb 100644
--- a/generators/dart/math.js
+++ b/generators/dart/math.js
@@ -200,25 +200,25 @@ Blockly.Dart['math_number_property'] = function(block) {
'import \'dart:math\' as Math;';
var functionName = Blockly.Dart.provideFunction_(
'math_isPrime',
- [ 'bool ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(n) {',
- ' // https://en.wikipedia.org/wiki/Primality_test#Naive_methods',
- ' if (n == 2 || n == 3) {',
- ' return true;',
- ' }',
- ' // False if n is null, negative, is 1, or not whole.',
- ' // And false if n is divisible by 2 or 3.',
- ' if (n == null || n <= 1 || n % 1 != 0 || n % 2 == 0 ||' +
+ ['bool ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(n) {',
+ ' // https://en.wikipedia.org/wiki/Primality_test#Naive_methods',
+ ' if (n == 2 || n == 3) {',
+ ' return true;',
+ ' }',
+ ' // False if n is null, negative, is 1, or not whole.',
+ ' // And false if n is divisible by 2 or 3.',
+ ' if (n == null || n <= 1 || n % 1 != 0 || n % 2 == 0 ||' +
' n % 3 == 0) {',
- ' return false;',
- ' }',
- ' // Check all the numbers of form 6k +/- 1, up to sqrt(n).',
- ' for (var x = 6; x <= Math.sqrt(n) + 1; x += 6) {',
- ' if (n % (x - 1) == 0 || n % (x + 1) == 0) {',
- ' return false;',
- ' }',
- ' }',
- ' return true;',
- '}']);
+ ' return false;',
+ ' }',
+ ' // Check all the numbers of form 6k +/- 1, up to sqrt(n).',
+ ' for (var x = 6; x <= Math.sqrt(n) + 1; x += 6) {',
+ ' if (n % (x - 1) == 0 || n % (x + 1) == 0) {',
+ ' return false;',
+ ' }',
+ ' }',
+ ' return true;',
+ '}']);
code = functionName + '(' + number_to_check + ')';
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
}
@@ -275,12 +275,12 @@ Blockly.Dart['math_on_list'] = function(block) {
case 'SUM':
var functionName = Blockly.Dart.provideFunction_(
'math_sum',
- [ 'num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(List myList) {',
- ' num sumVal = 0;',
- ' myList.forEach((num entry) {sumVal += entry;});',
- ' return sumVal;',
- '}']);
+ ' num sumVal = 0;',
+ ' myList.forEach((num entry) {sumVal += entry;});',
+ ' return sumVal;',
+ '}']);
code = functionName + '(' + list + ')';
break;
case 'MIN':
@@ -288,14 +288,14 @@ Blockly.Dart['math_on_list'] = function(block) {
'import \'dart:math\' as Math;';
var functionName = Blockly.Dart.provideFunction_(
'math_min',
- [ 'num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(List myList) {',
- ' if (myList.isEmpty) return null;',
- ' num minVal = myList[0];',
- ' myList.forEach((num entry) ' +
+ ' if (myList.isEmpty) return null;',
+ ' num minVal = myList[0];',
+ ' myList.forEach((num entry) ' +
'{minVal = Math.min(minVal, entry);});',
- ' return minVal;',
- '}']);
+ ' return minVal;',
+ '}']);
code = functionName + '(' + list + ')';
break;
case 'MAX':
@@ -303,14 +303,14 @@ Blockly.Dart['math_on_list'] = function(block) {
'import \'dart:math\' as Math;';
var functionName = Blockly.Dart.provideFunction_(
'math_max',
- [ 'num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(List myList) {',
- ' if (myList.isEmpty) return null;',
- ' num maxVal = myList[0];',
- ' myList.forEach((num entry) ' +
- '{maxVal = Math.max(maxVal, entry);});',
- ' return maxVal;',
- '}']);
+ ' if (myList.isEmpty) return null;',
+ ' num maxVal = myList[0];',
+ ' myList.forEach((num entry) ' +
+ '{maxVal = Math.max(maxVal, entry);});',
+ ' return maxVal;',
+ '}']);
code = functionName + '(' + list + ')';
break;
case 'AVERAGE':
@@ -318,38 +318,38 @@ Blockly.Dart['math_on_list'] = function(block) {
// math_mean([null,null,"aString",1,9]) == 5.0.
var functionName = Blockly.Dart.provideFunction_(
'math_mean',
- [ 'num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(List myList) {',
- ' // First filter list for numbers only.',
- ' List localList = new List.from(myList);',
- ' localList.removeMatching((a) => a is! num);',
- ' if (localList.isEmpty) return null;',
- ' num sumVal = 0;',
- ' localList.forEach((num entry) {sumVal += entry;});',
- ' return sumVal / localList.length;',
- '}']);
+ ' // First filter list for numbers only.',
+ ' List localList = new List.from(myList);',
+ ' localList.removeWhere((a) => a is! num);',
+ ' if (localList.isEmpty) return null;',
+ ' num sumVal = 0;',
+ ' localList.forEach((num entry) {sumVal += entry;});',
+ ' return sumVal / localList.length;',
+ '}']);
code = functionName + '(' + list + ')';
break;
case 'MEDIAN':
var functionName = Blockly.Dart.provideFunction_(
'math_median',
- [ 'num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(List myList) {',
- ' // First filter list for numbers only, then sort, ' +
+ ' // First filter list for numbers only, then sort, ' +
'then return middle value',
- ' // or the average of two middle values if list has an ' +
+ ' // or the average of two middle values if list has an ' +
'even number of elements.',
- ' List localList = new List.from(myList);',
- ' localList.removeMatching((a) => a is! num);',
- ' if (localList.isEmpty) return null;',
- ' localList.sort((a, b) => (a - b));',
- ' int index = localList.length ~/ 2;',
- ' if (localList.length % 2 == 1) {',
- ' return localList[index];',
- ' } else {',
- ' return (localList[index - 1] + localList[index]) / 2;',
- ' }',
- '}']);
+ ' List localList = new List.from(myList);',
+ ' localList.removeWhere((a) => a is! num);',
+ ' if (localList.isEmpty) return null;',
+ ' localList.sort((a, b) => (a - b));',
+ ' int index = localList.length ~/ 2;',
+ ' if (localList.length % 2 == 1) {',
+ ' return localList[index];',
+ ' } else {',
+ ' return (localList[index - 1] + localList[index]) / 2;',
+ ' }',
+ '}']);
code = functionName + '(' + list + ')';
break;
case 'MODE':
@@ -360,35 +360,35 @@ Blockly.Dart['math_on_list'] = function(block) {
// Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1].
var functionName = Blockly.Dart.provideFunction_(
'math_modes',
- [ 'List ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['List ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(List values) {',
- ' List modes = [];',
- ' List counts = [];',
- ' int maxCount = 0;',
- ' for (int i = 0; i < values.length; i++) {',
- ' var value = values[i];',
- ' bool found = false;',
- ' int thisCount;',
- ' for (int j = 0; j < counts.length; j++) {',
- ' if (counts[j][0] == value) {',
- ' thisCount = ++counts[j][1];',
- ' found = true;',
- ' break;',
- ' }',
- ' }',
- ' if (!found) {',
- ' counts.add([value, 1]);',
- ' thisCount = 1;',
- ' }',
- ' maxCount = Math.max(thisCount, maxCount);',
- ' }',
- ' for (int j = 0; j < counts.length; j++) {',
- ' if (counts[j][1] == maxCount) {',
- ' modes.add(counts[j][0]);',
- ' }',
- ' }',
- ' return modes;',
- '}']);
+ ' List modes = [];',
+ ' List counts = [];',
+ ' int maxCount = 0;',
+ ' for (int i = 0; i < values.length; i++) {',
+ ' var value = values[i];',
+ ' bool found = false;',
+ ' int thisCount;',
+ ' for (int j = 0; j < counts.length; j++) {',
+ ' if (counts[j][0] == value) {',
+ ' thisCount = ++counts[j][1];',
+ ' found = true;',
+ ' break;',
+ ' }',
+ ' }',
+ ' if (!found) {',
+ ' counts.add([value, 1]);',
+ ' thisCount = 1;',
+ ' }',
+ ' maxCount = Math.max(thisCount, maxCount);',
+ ' }',
+ ' for (int j = 0; j < counts.length; j++) {',
+ ' if (counts[j][1] == maxCount) {',
+ ' modes.add(counts[j][0]);',
+ ' }',
+ ' }',
+ ' return modes;',
+ '}']);
code = functionName + '(' + list + ')';
break;
case 'STD_DEV':
@@ -396,21 +396,21 @@ Blockly.Dart['math_on_list'] = function(block) {
'import \'dart:math\' as Math;';
var functionName = Blockly.Dart.provideFunction_(
'math_standard_deviation',
- [ 'num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(List myList) {',
- ' // First filter list for numbers only.',
- ' List numbers = new List.from(myList);',
- ' numbers.removeMatching((a) => a is! num);',
- ' if (numbers.isEmpty) return null;',
- ' num n = numbers.length;',
- ' num sum = 0;',
- ' numbers.forEach((x) => sum += x);',
- ' num mean = sum / n;',
- ' num sumSquare = 0;',
- ' numbers.forEach((x) => sumSquare += ' +
- 'Math.pow(x - mean, 2));',
- ' return Math.sqrt(sumSquare / n);',
- '}']);
+ ' // First filter list for numbers only.',
+ ' List numbers = new List.from(myList);',
+ ' numbers.removeWhere((a) => a is! num);',
+ ' if (numbers.isEmpty) return null;',
+ ' num n = numbers.length;',
+ ' num sum = 0;',
+ ' numbers.forEach((x) => sum += x);',
+ ' num mean = sum / n;',
+ ' num sumSquare = 0;',
+ ' numbers.forEach((x) => sumSquare += ' +
+ 'Math.pow(x - mean, 2));',
+ ' return Math.sqrt(sumSquare / n);',
+ '}']);
code = functionName + '(' + list + ')';
break;
case 'RANDOM':
@@ -418,11 +418,11 @@ Blockly.Dart['math_on_list'] = function(block) {
'import \'dart:math\' as Math;';
var functionName = Blockly.Dart.provideFunction_(
'math_random_item',
- [ 'dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(List myList) {',
- ' int x = new Math.Random().nextInt(myList.length);',
- ' return myList[x];',
- '}']);
+ ' int x = new Math.Random().nextInt(myList.length);',
+ ' return myList[x];',
+ '}']);
code = functionName + '(' + list + ')';
break;
default:
@@ -466,15 +466,15 @@ Blockly.Dart['math_random_int'] = function(block) {
Blockly.Dart.ORDER_NONE) || '0';
var functionName = Blockly.Dart.provideFunction_(
'math_random_int',
- [ 'int ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(num a, num b) {',
- ' if (a > b) {',
- ' // Swap a and b to ensure a is smaller.',
- ' num c = a;',
- ' a = b;',
- ' b = c;',
- ' }',
- ' return new Math.Random().nextInt(b - a + 1) + a;',
- '}']);
+ ['int ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(num a, num b) {',
+ ' if (a > b) {',
+ ' // Swap a and b to ensure a is smaller.',
+ ' num c = a;',
+ ' a = b;',
+ ' b = c;',
+ ' }',
+ ' return new Math.Random().nextInt(b - a + 1) + a;',
+ '}']);
var code = functionName + '(' + argument0 + ', ' + argument1 + ')';
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
};
diff --git a/generators/dart/procedures.js b/generators/dart/procedures.js
index 0085c6bf6..ad2550cc7 100644
--- a/generators/dart/procedures.js
+++ b/generators/dart/procedures.js
@@ -50,8 +50,8 @@ Blockly.Dart['procedures_defreturn'] = function(block) {
}
var returnType = returnValue ? 'dynamic' : 'void';
var args = [];
- for (var x = 0; x < block.arguments_.length; x++) {
- args[x] = Blockly.Dart.variableDB_.getName(block.arguments_[x],
+ for (var i = 0; i < block.arguments_.length; i++) {
+ args[i] = Blockly.Dart.variableDB_.getName(block.arguments_[i],
Blockly.Variables.NAME_TYPE);
}
var code = returnType + ' ' + funcName + '(' + args.join(', ') + ') {\n' +
@@ -71,8 +71,8 @@ Blockly.Dart['procedures_callreturn'] = function(block) {
var funcName = Blockly.Dart.variableDB_.getName(block.getFieldValue('NAME'),
Blockly.Procedures.NAME_TYPE);
var args = [];
- for (var x = 0; x < block.arguments_.length; x++) {
- args[x] = Blockly.Dart.valueToCode(block, 'ARG' + x,
+ for (var i = 0; i < block.arguments_.length; i++) {
+ args[i] = Blockly.Dart.valueToCode(block, 'ARG' + i,
Blockly.Dart.ORDER_NONE) || 'null';
}
var code = funcName + '(' + args.join(', ') + ')';
@@ -84,8 +84,8 @@ Blockly.Dart['procedures_callnoreturn'] = function(block) {
var funcName = Blockly.Dart.variableDB_.getName(block.getFieldValue('NAME'),
Blockly.Procedures.NAME_TYPE);
var args = [];
- for (var x = 0; x < block.arguments_.length; x++) {
- args[x] = Blockly.Dart.valueToCode(block, 'ARG' + x,
+ for (var i = 0; i < block.arguments_.length; i++) {
+ args[i] = Blockly.Dart.valueToCode(block, 'ARG' + i,
Blockly.Dart.ORDER_NONE) || 'null';
}
var code = funcName + '(' + args.join(', ') + ');\n';
diff --git a/generators/dart/text.js b/generators/dart/text.js
index ba5a75cb0..5cdbb03ec 100644
--- a/generators/dart/text.js
+++ b/generators/dart/text.js
@@ -39,22 +39,22 @@ Blockly.Dart['text'] = function(block) {
Blockly.Dart['text_join'] = function(block) {
// Create a string made up of any number of elements of any type.
- var code;
- if (block.itemCount_ == 0) {
- return ['\'\'', Blockly.Dart.ORDER_ATOMIC];
- } else if (block.itemCount_ == 1) {
- var argument0 = Blockly.Dart.valueToCode(block, 'ADD0',
- Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
- code = argument0 + '.toString()';
- return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
- } else {
- code = new Array(block.itemCount_);
- for (var n = 0; n < block.itemCount_; n++) {
- code[n] = Blockly.Dart.valueToCode(block, 'ADD' + n,
- Blockly.Dart.ORDER_NONE) || '\'\'';
- }
- code = '[' + code.join(',') + '].join()';
- return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ switch (block.itemCount_) {
+ case 0:
+ return ['\'\'', Blockly.Dart.ORDER_ATOMIC];
+ case 1:
+ var element = Blockly.Dart.valueToCode(block, 'ADD0',
+ Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
+ var code = element + '.toString()';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ default:
+ var elements = new Array(block.itemCount_);
+ for (var i = 0; i < block.itemCount_; i++) {
+ elements[i] = Blockly.Dart.valueToCode(block, 'ADD' + i,
+ Blockly.Dart.ORDER_NONE) || '\'\'';
+ }
+ var code = '[' + elements.join(',') + '].join()';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
}
};
@@ -62,43 +62,44 @@ Blockly.Dart['text_append'] = function(block) {
// Append to a variable in place.
var varName = Blockly.Dart.variableDB_.getName(block.getFieldValue('VAR'),
Blockly.Variables.NAME_TYPE);
- var argument0 = Blockly.Dart.valueToCode(block, 'TEXT',
- Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
- return varName + ' = [' + varName + ', ' + argument0 + '].join();\n';
+ var value = Blockly.Dart.valueToCode(block, 'TEXT',
+ Blockly.Dart.ORDER_NONE) || '\'\'';
+ return varName + ' = [' + varName + ', ' + value + '].join();\n';
};
Blockly.Dart['text_length'] = function(block) {
// String or array length.
- var argument0 = Blockly.Dart.valueToCode(block, 'VALUE',
+ var text = Blockly.Dart.valueToCode(block, 'VALUE',
Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
- return [argument0 + '.length', Blockly.Dart.ORDER_UNARY_POSTFIX];
+ return [text + '.length', Blockly.Dart.ORDER_UNARY_POSTFIX];
};
Blockly.Dart['text_isEmpty'] = function(block) {
// Is the string null or array empty?
- var argument0 = Blockly.Dart.valueToCode(block, 'VALUE',
+ var text = Blockly.Dart.valueToCode(block, 'VALUE',
Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
- return [argument0 + '.isEmpty', Blockly.Dart.ORDER_UNARY_POSTFIX];
+ return [text + '.isEmpty', Blockly.Dart.ORDER_UNARY_POSTFIX];
};
Blockly.Dart['text_indexOf'] = function(block) {
// Search the text for a substring.
var operator = block.getFieldValue('END') == 'FIRST' ?
'indexOf' : 'lastIndexOf';
- var argument0 = Blockly.Dart.valueToCode(block, 'FIND',
+ var substring = Blockly.Dart.valueToCode(block, 'FIND',
Blockly.Dart.ORDER_NONE) || '\'\'';
- var argument1 = Blockly.Dart.valueToCode(block, 'VALUE',
+ var text = Blockly.Dart.valueToCode(block, 'VALUE',
Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
- var code = argument1 + '.' + operator + '(' + argument0 + ') + 1';
- return [code, Blockly.Dart.ORDER_ADDITIVE];
+ var code = text + '.' + operator + '(' + substring + ')';
+ if (Blockly.Dart.ONE_BASED_INDEXING) {
+ return [code + ' + 1', Blockly.Dart.ORDER_ADDITIVE];
+ }
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
};
Blockly.Dart['text_charAt'] = function(block) {
// Get letter at index.
// Note: Until January 2013 this block did not have the WHERE input.
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.Dart.valueToCode(block, 'AT',
- Blockly.Dart.ORDER_NONE) || '1';
var text = Blockly.Dart.valueToCode(block, 'VALUE',
Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
switch (where) {
@@ -106,26 +107,20 @@ Blockly.Dart['text_charAt'] = function(block) {
var code = text + '[0]';
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
case 'FROM_START':
- // Blockly uses one-based indicies.
- if (at.match(/^-?\d+$/)) {
- // If the index is a naked number, decrement it right now.
- at = parseInt(at, 10) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at += ' - 1';
- }
+ var at = Blockly.Dart.getAdjusted(block, 'AT');
var code = text + '[' + at + ']';
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
case 'LAST':
at = 1;
// Fall through.
case 'FROM_END':
+ var at = Blockly.Dart.getAdjusted(block, 'AT', 1);
var functionName = Blockly.Dart.provideFunction_(
'text_get_from_end',
- [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(String text, num x) {',
- ' return text[text.length - x];',
- '}']);
+ ' return text[text.length - x];',
+ '}']);
code = functionName + '(' + text + ', ' + at + ')';
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
case 'RANDOM':
@@ -133,11 +128,11 @@ Blockly.Dart['text_charAt'] = function(block) {
'import \'dart:math\' as Math;';
var functionName = Blockly.Dart.provideFunction_(
'text_random_letter',
- [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(String text) {',
- ' int x = new Math.Random().nextInt(text.length);',
- ' return text[x];',
- '}']);
+ ' int x = new Math.Random().nextInt(text.length);',
+ ' return text[x];',
+ '}']);
code = functionName + '(' + text + ')';
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
}
@@ -150,35 +145,69 @@ Blockly.Dart['text_getSubstring'] = function(block) {
Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
var where1 = block.getFieldValue('WHERE1');
var where2 = block.getFieldValue('WHERE2');
- var at1 = Blockly.Dart.valueToCode(block, 'AT1',
- Blockly.Dart.ORDER_NONE) || '1';
- var at2 = Blockly.Dart.valueToCode(block, 'AT2',
- Blockly.Dart.ORDER_NONE) || '1';
if (where1 == 'FIRST' && where2 == 'LAST') {
var code = text;
+ } else if (text.match(/^'?\w+'?$/) ||
+ (where1 != 'FROM_END' && where2 == 'FROM_START')) {
+ // If the text is a variable or literal or doesn't require a call for
+ // length, don't generate a helper function.
+ switch (where1) {
+ case 'FROM_START':
+ var at1 = Blockly.Dart.getAdjusted(block, 'AT1');
+ break;
+ case 'FROM_END':
+ var at1 = Blockly.Dart.getAdjusted(block, 'AT1', 1, false,
+ Blockly.Dart.ORDER_ADDITIVE);
+ at1 = text + '.length - ' + at1;
+ break;
+ case 'FIRST':
+ var at1 = '0';
+ break;
+ default:
+ throw 'Unhandled option (text_getSubstring).';
+ }
+ switch (where2) {
+ case 'FROM_START':
+ var at2 = Blockly.Dart.getAdjusted(block, 'AT2', 1);
+ break;
+ case 'FROM_END':
+ var at2 = Blockly.Dart.getAdjusted(block, 'AT2', 0, false,
+ Blockly.Dart.ORDER_ADDITIVE);
+ at2 = text + '.length - ' + at2;
+ break;
+ case 'LAST':
+ break;
+ default:
+ throw 'Unhandled option (text_getSubstring).';
+ }
+ if (where2 == 'LAST') {
+ var code = text + '.substring(' + at1 + ')';
+ } else {
+ var code = text + '.substring(' + at1 + ', ' + at2 + ')';
+ }
} else {
+ var at1 = Blockly.Dart.getAdjusted(block, 'AT1');
+ var at2 = Blockly.Dart.getAdjusted(block, 'AT2');
var functionName = Blockly.Dart.provideFunction_(
'text_get_substring',
- [ 'function ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['List ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(text, where1, at1, where2, at2) {',
- ' function getAt(where, at) {',
- ' if (where == \'FROM_START\') {',
- ' at--;',
- ' } else if (where == \'FROM_END\') {',
- ' at = text.length - at;',
- ' } else if (where == \'FIRST\') {',
- ' at = 0;',
- ' } else if (where == \'LAST\') {',
- ' at = text.length - 1;',
- ' } else {',
- ' throw \'Unhandled option (text_getSubstring).\';',
- ' }',
- ' return at;',
- ' }',
- ' at1 = getAt(where1, at1);',
- ' at2 = getAt(where2, at2) + 1;',
- ' return text.substring(at1, at2);',
- '}']);
+ ' int getAt(where, at) {',
+ ' if (where == \'FROM_END\') {',
+ ' at = text.length - 1 - at;',
+ ' } else if (where == \'FIRST\') {',
+ ' at = 0;',
+ ' } else if (where == \'LAST\') {',
+ ' at = text.length - 1;',
+ ' } else if (where != \'FROM_START\') {',
+ ' throw \'Unhandled option (text_getSubstring).\';',
+ ' }',
+ ' return at;',
+ ' }',
+ ' at1 = getAt(where1, at1);',
+ ' at2 = getAt(where2, at2) + 1;',
+ ' return text.substring(at1, at2);',
+ '}']);
var code = functionName + '(' + text + ', \'' +
where1 + '\', ' + at1 + ', \'' + where2 + '\', ' + at2 + ')';
}
@@ -193,34 +222,32 @@ Blockly.Dart['text_changeCase'] = function(block) {
'TITLECASE': null
};
var operator = OPERATORS[block.getFieldValue('CASE')];
- var code;
+ var textOrder = operator ? Blockly.Dart.ORDER_UNARY_POSTFIX :
+ Blockly.Dart.ORDER_NONE;
+ var text = Blockly.Dart.valueToCode(block, 'TEXT', textOrder) || '\'\'';
if (operator) {
// Upper and lower case are functions built into Dart.
- var argument0 = Blockly.Dart.valueToCode(block, 'TEXT',
- Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
- code = argument0 + operator;
+ var code = text + operator;
} else {
// Title case is not a native Dart function. Define one.
var functionName = Blockly.Dart.provideFunction_(
'text_toTitleCase',
- [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ ['String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
'(String str) {',
- ' RegExp exp = new RegExp(r\'\\b\');',
- ' List list = str.split(exp);',
- ' final title = new StringBuffer();',
- ' for (String part in list) {',
- ' if (part.length > 0) {',
- ' title.write(part[0].toUpperCase());',
- ' if (part.length > 0) {',
- ' title.write(part.substring(1).toLowerCase());',
- ' }',
- ' }',
- ' }',
- ' return title.toString();',
- '}']);
- var argument0 = Blockly.Dart.valueToCode(block, 'TEXT',
- Blockly.Dart.ORDER_NONE) || '\'\'';
- code = functionName + '(' + argument0 + ')';
+ ' RegExp exp = new RegExp(r\'\\b\');',
+ ' List list = str.split(exp);',
+ ' final title = new StringBuffer();',
+ ' for (String part in list) {',
+ ' if (part.length > 0) {',
+ ' title.write(part[0].toUpperCase());',
+ ' if (part.length > 0) {',
+ ' title.write(part.substring(1).toLowerCase());',
+ ' }',
+ ' }',
+ ' }',
+ ' return title.toString();',
+ '}']);
+ var code = functionName + '(' + text + ')';
}
return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
};
@@ -233,16 +260,16 @@ Blockly.Dart['text_trim'] = function(block) {
'BOTH': '.trim()'
};
var operator = OPERATORS[block.getFieldValue('MODE')];
- var argument0 = Blockly.Dart.valueToCode(block, 'TEXT',
+ var text = Blockly.Dart.valueToCode(block, 'TEXT',
Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
- return [argument0 + operator, Blockly.Dart.ORDER_UNARY_POSTFIX];
+ return [text + operator, Blockly.Dart.ORDER_UNARY_POSTFIX];
};
Blockly.Dart['text_print'] = function(block) {
// Print statement.
- var argument0 = Blockly.Dart.valueToCode(block, 'TEXT',
+ var msg = Blockly.Dart.valueToCode(block, 'TEXT',
Blockly.Dart.ORDER_NONE) || '\'\'';
- return 'print(' + argument0 + ');\n';
+ return 'print(' + msg + ');\n';
};
Blockly.Dart['text_prompt_ext'] = function(block) {
diff --git a/generators/javascript.js b/generators/javascript.js
index f14671899..db0952532 100644
--- a/generators/javascript.js
+++ b/generators/javascript.js
@@ -135,8 +135,8 @@ Blockly.JavaScript.ORDER_OVERRIDES = [
];
/**
- * Allow for switching between one and zero based indexing, one based by
- * default.
+ * Allow for switching between one and zero based indexing for lists and text,
+ * one based by default.
*/
Blockly.JavaScript.ONE_BASED_INDEXING = true;
@@ -258,3 +258,66 @@ Blockly.JavaScript.scrub_ = function(block, code) {
var nextCode = Blockly.JavaScript.blockToCode(nextBlock);
return commentCode + code + nextCode;
};
+
+/**
+ * Gets a property and adjusts the value while taking into account indexing.
+ * @param {!Blockly.Block} block The block.
+ * @param {string} atId The property ID of the element to get.
+ * @param {number=} opt_delta Value to add.
+ * @param {boolean=} opt_negate Whether to negate the value.
+ * @param {number=} opt_order The highest order acting on this value.
+ * @return {string|number}
+ */
+Blockly.JavaScript.getAdjusted = function(block, atId, opt_delta, opt_negate,
+ opt_order) {
+ var delta = opt_delta || 0;
+ var order = opt_order || Blockly.JavaScript.ORDER_NONE;
+ if (Blockly.JavaScript.ONE_BASED_INDEXING) {
+ delta--;
+ }
+ var defaultAtIndex = Blockly.JavaScript.ONE_BASED_INDEXING ? '1' : '0';
+ if (delta > 0) {
+ var at = Blockly.JavaScript.valueToCode(block, atId,
+ Blockly.JavaScript.ORDER_ADDITION) || defaultAtIndex;
+ } else if (delta < 0) {
+ var at = Blockly.JavaScript.valueToCode(block, atId,
+ Blockly.JavaScript.ORDER_SUBTRACTION) || defaultAtIndex;
+ } else if (opt_negate) {
+ var at = Blockly.JavaScript.valueToCode(block, atId,
+ Blockly.JavaScript.ORDER_UNARY_NEGATION) || defaultAtIndex;
+ } else {
+ var at = Blockly.JavaScript.valueToCode(block, atId, order) ||
+ defaultAtIndex;
+ }
+
+ if (Blockly.isNumber(at)) {
+ // If the index is a naked number, adjust it right now.
+ at = parseFloat(at) + delta;
+ if (opt_negate) {
+ at = -at;
+ }
+ } else {
+ // If the index is dynamic, adjust it in code.
+ if (delta > 0) {
+ at = at + ' + ' + delta;
+ var innerOrder = Blockly.JavaScript.ORDER_ADDITION;
+ } else if (delta < 0) {
+ at = at + ' - ' + -delta;
+ var innerOrder = Blockly.JavaScript.ORDER_SUBTRACTION;
+ }
+ if (opt_negate) {
+ if (delta) {
+ at = '-(' + at + ')';
+ } else {
+ at = '-' + at;
+ }
+ var innerOrder = Blockly.JavaScript.ORDER_UNARY_NEGATION;
+ }
+ innerOrder = Math.floor(innerOrder);
+ order = Math.floor(order);
+ if (innerOrder && order >= innerOrder) {
+ at = '(' + at + ')';
+ }
+ }
+ return at;
+};
diff --git a/generators/javascript/colour.js b/generators/javascript/colour.js
index b8e290360..21b372e9c 100644
--- a/generators/javascript/colour.js
+++ b/generators/javascript/colour.js
@@ -39,7 +39,7 @@ Blockly.JavaScript['colour_random'] = function(block) {
// Generate a random colour.
var functionName = Blockly.JavaScript.provideFunction_(
'colourRandom',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '() {',
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '() {',
' var num = Math.floor(Math.random() * Math.pow(2, 24));',
' return \'#\' + (\'00000\' + num.toString(16)).substr(-6);',
'}']);
@@ -57,16 +57,16 @@ Blockly.JavaScript['colour_rgb'] = function(block) {
Blockly.JavaScript.ORDER_COMMA) || 0;
var functionName = Blockly.JavaScript.provideFunction_(
'colourRgb',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
'(r, g, b) {',
- ' r = Math.max(Math.min(Number(r), 100), 0) * 2.55;',
- ' g = Math.max(Math.min(Number(g), 100), 0) * 2.55;',
- ' b = Math.max(Math.min(Number(b), 100), 0) * 2.55;',
- ' r = (\'0\' + (Math.round(r) || 0).toString(16)).slice(-2);',
- ' g = (\'0\' + (Math.round(g) || 0).toString(16)).slice(-2);',
- ' b = (\'0\' + (Math.round(b) || 0).toString(16)).slice(-2);',
- ' return \'#\' + r + g + b;',
- '}']);
+ ' r = Math.max(Math.min(Number(r), 100), 0) * 2.55;',
+ ' g = Math.max(Math.min(Number(g), 100), 0) * 2.55;',
+ ' b = Math.max(Math.min(Number(b), 100), 0) * 2.55;',
+ ' r = (\'0\' + (Math.round(r) || 0).toString(16)).slice(-2);',
+ ' g = (\'0\' + (Math.round(g) || 0).toString(16)).slice(-2);',
+ ' b = (\'0\' + (Math.round(b) || 0).toString(16)).slice(-2);',
+ ' return \'#\' + r + g + b;',
+ '}']);
var code = functionName + '(' + red + ', ' + green + ', ' + blue + ')';
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};
@@ -81,23 +81,23 @@ Blockly.JavaScript['colour_blend'] = function(block) {
Blockly.JavaScript.ORDER_COMMA) || 0.5;
var functionName = Blockly.JavaScript.provideFunction_(
'colourBlend',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
'(c1, c2, ratio) {',
- ' ratio = Math.max(Math.min(Number(ratio), 1), 0);',
- ' var r1 = parseInt(c1.substring(1, 3), 16);',
- ' var g1 = parseInt(c1.substring(3, 5), 16);',
- ' var b1 = parseInt(c1.substring(5, 7), 16);',
- ' var r2 = parseInt(c2.substring(1, 3), 16);',
- ' var g2 = parseInt(c2.substring(3, 5), 16);',
- ' var b2 = parseInt(c2.substring(5, 7), 16);',
- ' var r = Math.round(r1 * (1 - ratio) + r2 * ratio);',
- ' var g = Math.round(g1 * (1 - ratio) + g2 * ratio);',
- ' var b = Math.round(b1 * (1 - ratio) + b2 * ratio);',
- ' r = (\'0\' + (r || 0).toString(16)).slice(-2);',
- ' g = (\'0\' + (g || 0).toString(16)).slice(-2);',
- ' b = (\'0\' + (b || 0).toString(16)).slice(-2);',
- ' return \'#\' + r + g + b;',
- '}']);
+ ' ratio = Math.max(Math.min(Number(ratio), 1), 0);',
+ ' var r1 = parseInt(c1.substring(1, 3), 16);',
+ ' var g1 = parseInt(c1.substring(3, 5), 16);',
+ ' var b1 = parseInt(c1.substring(5, 7), 16);',
+ ' var r2 = parseInt(c2.substring(1, 3), 16);',
+ ' var g2 = parseInt(c2.substring(3, 5), 16);',
+ ' var b2 = parseInt(c2.substring(5, 7), 16);',
+ ' var r = Math.round(r1 * (1 - ratio) + r2 * ratio);',
+ ' var g = Math.round(g1 * (1 - ratio) + g2 * ratio);',
+ ' var b = Math.round(b1 * (1 - ratio) + b2 * ratio);',
+ ' r = (\'0\' + (r || 0).toString(16)).slice(-2);',
+ ' g = (\'0\' + (g || 0).toString(16)).slice(-2);',
+ ' b = (\'0\' + (b || 0).toString(16)).slice(-2);',
+ ' return \'#\' + r + g + b;',
+ '}']);
var code = functionName + '(' + c1 + ', ' + c2 + ', ' + ratio + ')';
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};
diff --git a/generators/javascript/lists.js b/generators/javascript/lists.js
index 4bb6aac20..d1e66a0ed 100644
--- a/generators/javascript/lists.js
+++ b/generators/javascript/lists.js
@@ -36,12 +36,12 @@ Blockly.JavaScript['lists_create_empty'] = function(block) {
Blockly.JavaScript['lists_create_with'] = function(block) {
// Create a list with any number of elements of any type.
- var code = new Array(block.itemCount_);
- for (var n = 0; n < block.itemCount_; n++) {
- code[n] = Blockly.JavaScript.valueToCode(block, 'ADD' + n,
+ var elements = new Array(block.itemCount_);
+ for (var i = 0; i < block.itemCount_; i++) {
+ elements[i] = Blockly.JavaScript.valueToCode(block, 'ADD' + i,
Blockly.JavaScript.ORDER_COMMA) || 'null';
}
- code = '[' + code.join(', ') + ']';
+ var code = '[' + elements.join(', ') + ']';
return [code, Blockly.JavaScript.ORDER_ATOMIC];
};
@@ -49,46 +49,49 @@ Blockly.JavaScript['lists_repeat'] = function(block) {
// Create a list with one element repeated.
var functionName = Blockly.JavaScript.provideFunction_(
'listsRepeat',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
'(value, n) {',
- ' var array = [];',
- ' for (var i = 0; i < n; i++) {',
- ' array[i] = value;',
- ' }',
- ' return array;',
- '}']);
- var argument0 = Blockly.JavaScript.valueToCode(block, 'ITEM',
+ ' var array = [];',
+ ' for (var i = 0; i < n; i++) {',
+ ' array[i] = value;',
+ ' }',
+ ' return array;',
+ '}']);
+ var element = Blockly.JavaScript.valueToCode(block, 'ITEM',
Blockly.JavaScript.ORDER_COMMA) || 'null';
- var argument1 = Blockly.JavaScript.valueToCode(block, 'NUM',
+ var repeatCount = Blockly.JavaScript.valueToCode(block, 'NUM',
Blockly.JavaScript.ORDER_COMMA) || '0';
- var code = functionName + '(' + argument0 + ', ' + argument1 + ')';
+ var code = functionName + '(' + element + ', ' + repeatCount + ')';
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};
Blockly.JavaScript['lists_length'] = function(block) {
// String or array length.
- var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE',
- Blockly.JavaScript.ORDER_FUNCTION_CALL) || '[]';
- return [argument0 + '.length', Blockly.JavaScript.ORDER_MEMBER];
+ var list = Blockly.JavaScript.valueToCode(block, 'VALUE',
+ Blockly.JavaScript.ORDER_MEMBER) || '[]';
+ return [list + '.length', Blockly.JavaScript.ORDER_MEMBER];
};
Blockly.JavaScript['lists_isEmpty'] = function(block) {
// Is the string null or array empty?
- var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE',
+ var list = Blockly.JavaScript.valueToCode(block, 'VALUE',
Blockly.JavaScript.ORDER_MEMBER) || '[]';
- return ['!' + argument0 + '.length', Blockly.JavaScript.ORDER_LOGICAL_NOT];
+ return ['!' + list + '.length', Blockly.JavaScript.ORDER_LOGICAL_NOT];
};
Blockly.JavaScript['lists_indexOf'] = function(block) {
// Find an item in the list.
var operator = block.getFieldValue('END') == 'FIRST' ?
'indexOf' : 'lastIndexOf';
- var argument0 = Blockly.JavaScript.valueToCode(block, 'FIND',
+ var item = Blockly.JavaScript.valueToCode(block, 'FIND',
Blockly.JavaScript.ORDER_NONE) || '\'\'';
- var argument1 = Blockly.JavaScript.valueToCode(block, 'VALUE',
+ var list = Blockly.JavaScript.valueToCode(block, 'VALUE',
Blockly.JavaScript.ORDER_MEMBER) || '[]';
- var code = argument1 + '.' + operator + '(' + argument0 + ') + 1';
- return [code, Blockly.JavaScript.ORDER_ADDITION];
+ var code = list + '.' + operator + '(' + item + ')';
+ if (Blockly.JavaScript.ONE_BASED_INDEXING) {
+ return [code + ' + 1', Blockly.JavaScript.ORDER_ADDITION];
+ }
+ return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};
Blockly.JavaScript['lists_getIndex'] = function(block) {
@@ -96,86 +99,76 @@ Blockly.JavaScript['lists_getIndex'] = function(block) {
// Note: Until January 2013 this block did not have MODE or WHERE inputs.
var mode = block.getFieldValue('MODE') || 'GET';
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.JavaScript.valueToCode(block, 'AT',
- Blockly.JavaScript.ORDER_UNARY_NEGATION) || '1';
- var list = Blockly.JavaScript.valueToCode(block, 'VALUE',
- Blockly.JavaScript.ORDER_MEMBER) || '[]';
+ var listOrder = (where == 'RANDOM') ? Blockly.JavaScript.ORDER_COMMA :
+ Blockly.JavaScript.ORDER_MEMBER;
+ var list = Blockly.JavaScript.valueToCode(block, 'VALUE', listOrder) || '[]';
- if (where == 'FIRST') {
- if (mode == 'GET') {
- var code = list + '[0]';
- return [code, Blockly.JavaScript.ORDER_MEMBER];
- } else if (mode == 'GET_REMOVE') {
- var code = list + '.shift()';
- return [code, Blockly.JavaScript.ORDER_MEMBER];
- } else if (mode == 'REMOVE') {
- return list + '.shift();\n';
- }
- } else if (where == 'LAST') {
- if (mode == 'GET') {
- var code = list + '.slice(-1)[0]';
- return [code, Blockly.JavaScript.ORDER_MEMBER];
- } else if (mode == 'GET_REMOVE') {
- var code = list + '.pop()';
- return [code, Blockly.JavaScript.ORDER_MEMBER];
- } else if (mode == 'REMOVE') {
- return list + '.pop();\n';
- }
- } else if (where == 'FROM_START') {
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at)) {
- // If the index is a naked number, decrement it right now.
- at = parseFloat(at) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at += ' - 1';
- }
- if (mode == 'GET') {
- var code = list + '[' + at + ']';
- return [code, Blockly.JavaScript.ORDER_MEMBER];
- } else if (mode == 'GET_REMOVE') {
- var code = list + '.splice(' + at + ', 1)[0]';
- return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
- } else if (mode == 'REMOVE') {
- return list + '.splice(' + at + ', 1);\n';
- }
- } else if (where == 'FROM_END') {
- if (mode == 'GET') {
- var code = list + '.slice(-' + at + ')[0]';
- return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
- } else if (mode == 'GET_REMOVE' || mode == 'REMOVE') {
+ switch (where) {
+ case ('FIRST'):
+ if (mode == 'GET') {
+ var code = list + '[0]';
+ return [code, Blockly.JavaScript.ORDER_MEMBER];
+ } else if (mode == 'GET_REMOVE') {
+ var code = list + '.shift()';
+ return [code, Blockly.JavaScript.ORDER_MEMBER];
+ } else if (mode == 'REMOVE') {
+ return list + '.shift();\n';
+ }
+ break;
+ case ('LAST'):
+ if (mode == 'GET') {
+ var code = list + '.slice(-1)[0]';
+ return [code, Blockly.JavaScript.ORDER_MEMBER];
+ } else if (mode == 'GET_REMOVE') {
+ var code = list + '.pop()';
+ return [code, Blockly.JavaScript.ORDER_MEMBER];
+ } else if (mode == 'REMOVE') {
+ return list + '.pop();\n';
+ }
+ break;
+ case ('FROM_START'):
+ var at = Blockly.JavaScript.getAdjusted(block, 'AT');
+ if (mode == 'GET') {
+ var code = list + '[' + at + ']';
+ return [code, Blockly.JavaScript.ORDER_MEMBER];
+ } else if (mode == 'GET_REMOVE') {
+ var code = list + '.splice(' + at + ', 1)[0]';
+ return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
+ } else if (mode == 'REMOVE') {
+ return list + '.splice(' + at + ', 1);\n';
+ }
+ break;
+ case ('FROM_END'):
+ var at = Blockly.JavaScript.getAdjusted(block, 'AT', 1, true);
+ if (mode == 'GET') {
+ var code = list + '.slice(' + at + ')[0]';
+ return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
+ } else if (mode == 'GET_REMOVE') {
+ var code = list + '.splice(' + at + ', 1)[0]';
+ return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
+ } else if (mode == 'REMOVE') {
+ return list + '.splice(' + at + ', 1);';
+ }
+ break;
+ case ('RANDOM'):
var functionName = Blockly.JavaScript.provideFunction_(
- 'listsRemoveFromEnd',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
- '(list, x) {',
- ' x = list.length - x;',
- ' return list.splice(x, 1)[0];',
- '}']);
- code = functionName + '(' + list + ', ' + at + ')';
- if (mode == 'GET_REMOVE') {
+ 'listsGetRandomItem',
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ '(list, remove) {',
+ ' var x = Math.floor(Math.random() * list.length);',
+ ' if (remove) {',
+ ' return list.splice(x, 1)[0];',
+ ' } else {',
+ ' return list[x];',
+ ' }',
+ '}']);
+ code = functionName + '(' + list + ', ' + (mode != 'GET') + ')';
+ if (mode == 'GET' || mode == 'GET_REMOVE') {
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
} else if (mode == 'REMOVE') {
return code + ';\n';
}
- }
- } else if (where == 'RANDOM') {
- var functionName = Blockly.JavaScript.provideFunction_(
- 'listsGetRandomItem',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
- '(list, remove) {',
- ' var x = Math.floor(Math.random() * list.length);',
- ' if (remove) {',
- ' return list.splice(x, 1)[0];',
- ' } else {',
- ' return list[x];',
- ' }',
- '}']);
- code = functionName + '(' + list + ', ' + (mode != 'GET') + ')';
- if (mode == 'GET' || mode == 'GET_REMOVE') {
- return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
- } else if (mode == 'REMOVE') {
- return code + ';\n';
- }
+ break;
}
throw 'Unhandled combination (lists_getIndex).';
};
@@ -187,8 +180,6 @@ Blockly.JavaScript['lists_setIndex'] = function(block) {
Blockly.JavaScript.ORDER_MEMBER) || '[]';
var mode = block.getFieldValue('MODE') || 'GET';
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.JavaScript.valueToCode(block, 'AT',
- Blockly.JavaScript.ORDER_NONE) || '1';
var value = Blockly.JavaScript.valueToCode(block, 'TO',
Blockly.JavaScript.ORDER_ASSIGNMENT) || 'null';
// Cache non-trivial values to variables to prevent repeated look-ups.
@@ -198,155 +189,206 @@ Blockly.JavaScript['lists_setIndex'] = function(block) {
return '';
}
var listVar = Blockly.JavaScript.variableDB_.getDistinctName(
- 'tmp_list', Blockly.Variables.NAME_TYPE);
+ 'tmpList', Blockly.Variables.NAME_TYPE);
var code = 'var ' + listVar + ' = ' + list + ';\n';
list = listVar;
return code;
}
- if (where == 'FIRST') {
- if (mode == 'SET') {
- return list + '[0] = ' + value + ';\n';
- } else if (mode == 'INSERT') {
- return list + '.unshift(' + value + ');\n';
- }
- } else if (where == 'LAST') {
- if (mode == 'SET') {
+ switch (where) {
+ case ('FIRST'):
+ if (mode == 'SET') {
+ return list + '[0] = ' + value + ';\n';
+ } else if (mode == 'INSERT') {
+ return list + '.unshift(' + value + ');\n';
+ }
+ break;
+ case ('LAST'):
+ if (mode == 'SET') {
+ var code = cacheList();
+ code += list + '[' + list + '.length - 1] = ' + value + ';\n';
+ return code;
+ } else if (mode == 'INSERT') {
+ return list + '.push(' + value + ');\n';
+ }
+ break;
+ case ('FROM_START'):
+ var at = Blockly.JavaScript.getAdjusted(block, 'AT');
+ if (mode == 'SET') {
+ return list + '[' + at + '] = ' + value + ';\n';
+ } else if (mode == 'INSERT') {
+ return list + '.splice(' + at + ', 0, ' + value + ');\n';
+ }
+ break;
+ case ('FROM_END'):
+ var at = Blockly.JavaScript.getAdjusted(block, 'AT', 1, false,
+ Blockly.JavaScript.ORDER_SUBTRACTION);
var code = cacheList();
- code += list + '[' + list + '.length - 1] = ' + value + ';\n';
- return code;
- } else if (mode == 'INSERT') {
- return list + '.push(' + value + ');\n';
- }
- } else if (where == 'FROM_START') {
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at)) {
- // If the index is a naked number, decrement it right now.
- at = parseFloat(at) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at += ' - 1';
- }
- if (mode == 'SET') {
- return list + '[' + at + '] = ' + value + ';\n';
- } else if (mode == 'INSERT') {
- return list + '.splice(' + at + ', 0, ' + value + ');\n';
- }
- } else if (where == 'FROM_END') {
- var code = cacheList();
- if (mode == 'SET') {
- code += list + '[' + list + '.length - ' + at + '] = ' + value + ';\n';
- return code;
- } else if (mode == 'INSERT') {
- code += list + '.splice(' + list + '.length - ' + at + ', 0, ' + value +
- ');\n';
- return code;
- }
- } else if (where == 'RANDOM') {
- var code = cacheList();
- var xVar = Blockly.JavaScript.variableDB_.getDistinctName(
- 'tmp_x', Blockly.Variables.NAME_TYPE);
- code += 'var ' + xVar + ' = Math.floor(Math.random() * ' + list +
- '.length);\n';
- if (mode == 'SET') {
- code += list + '[' + xVar + '] = ' + value + ';\n';
- return code;
- } else if (mode == 'INSERT') {
- code += list + '.splice(' + xVar + ', 0, ' + value + ');\n';
- return code;
- }
+ if (mode == 'SET') {
+ code += list + '[' + list + '.length - ' + at + '] = ' + value + ';\n';
+ return code;
+ } else if (mode == 'INSERT') {
+ code += list + '.splice(' + list + '.length - ' + at + ', 0, ' + value +
+ ');\n';
+ return code;
+ }
+ break;
+ case ('RANDOM'):
+ var code = cacheList();
+ var xVar = Blockly.JavaScript.variableDB_.getDistinctName(
+ 'tmpX', Blockly.Variables.NAME_TYPE);
+ code += 'var ' + xVar + ' = Math.floor(Math.random() * ' + list +
+ '.length);\n';
+ if (mode == 'SET') {
+ code += list + '[' + xVar + '] = ' + value + ';\n';
+ return code;
+ } else if (mode == 'INSERT') {
+ code += list + '.splice(' + xVar + ', 0, ' + value + ');\n';
+ return code;
+ }
+ break;
}
throw 'Unhandled combination (lists_setIndex).';
};
+/**
+ * Returns an expression calculating the index into a list.
+ * @private
+ * @param {string} listName Name of the list, used to calculate length.
+ * @param {string} where The method of indexing, selected by dropdown in Blockly
+ * @param {string=} opt_at The optional offset when indexing from start/end.
+ * @return {string} Index expression.
+ */
+Blockly.JavaScript.lists.getIndex_ = function(listName, where, opt_at) {
+ if (where == 'FIRST') {
+ return '0';
+ } else if (where == 'FROM_END') {
+ return listName + '.length - 1 - ' + opt_at;
+ } else if (where == 'LAST') {
+ return listName + '.length - 1';
+ } else {
+ return opt_at;
+ }
+};
+
Blockly.JavaScript['lists_getSublist'] = function(block) {
// Get sublist.
var list = Blockly.JavaScript.valueToCode(block, 'LIST',
Blockly.JavaScript.ORDER_MEMBER) || '[]';
var where1 = block.getFieldValue('WHERE1');
var where2 = block.getFieldValue('WHERE2');
- var at1 = Blockly.JavaScript.valueToCode(block, 'AT1',
- Blockly.JavaScript.ORDER_NONE) || '1';
- var at2 = Blockly.JavaScript.valueToCode(block, 'AT2',
- Blockly.JavaScript.ORDER_NONE) || '1';
if (where1 == 'FIRST' && where2 == 'LAST') {
- var code = list + '.concat()';
+ var code = list + '.slice(0)';
+ } else if (list.match(/^\w+$/) ||
+ (where1 != 'FROM_END' && where2 == 'FROM_START')) {
+ // If the list is a variable or doesn't require a call for length, don't
+ // generate a helper function.
+ switch (where1) {
+ case 'FROM_START':
+ var at1 = Blockly.JavaScript.getAdjusted(block, 'AT1');
+ break;
+ case 'FROM_END':
+ var at1 = Blockly.JavaScript.getAdjusted(block, 'AT1', 1, false,
+ Blockly.JavaScript.ORDER_SUBTRACTION);
+ at1 = list + '.length - ' + at1;
+ break;
+ case 'FIRST':
+ var at1 = '0';
+ break;
+ default:
+ throw 'Unhandled option (lists_getSublist).';
+ }
+ switch (where2) {
+ case 'FROM_START':
+ var at2 = Blockly.JavaScript.getAdjusted(block, 'AT2', 1);
+ break;
+ case 'FROM_END':
+ var at2 = Blockly.JavaScript.getAdjusted(block, 'AT2', 0, false,
+ Blockly.JavaScript.ORDER_SUBTRACTION);
+ at2 = list + '.length - ' + at2;
+ break;
+ case 'LAST':
+ var at2 = list + '.length';
+ break;
+ default:
+ throw 'Unhandled option (lists_getSublist).';
+ }
+ code = list + '.slice(' + at1 + ', ' + at2 + ')';
} else {
+ var at1 = Blockly.JavaScript.getAdjusted(block, 'AT1');
+ var at2 = Blockly.JavaScript.getAdjusted(block, 'AT2');
+ var getIndex_ = Blockly.JavaScript.lists.getIndex_;
+ var wherePascalCase = {'FIRST': 'First', 'LAST': 'Last',
+ 'FROM_START': 'FromStart', 'FROM_END': 'FromEnd'};
var functionName = Blockly.JavaScript.provideFunction_(
- 'listsGetSublist',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
- '(list, where1, at1, where2, at2) {',
- ' function getAt(where, at) {',
- ' if (where == \'FROM_START\') {',
- ' at--;',
- ' } else if (where == \'FROM_END\') {',
- ' at = list.length - at;',
- ' } else if (where == \'FIRST\') {',
- ' at = 0;',
- ' } else if (where == \'LAST\') {',
- ' at = list.length - 1;',
- ' } else {',
- ' throw \'Unhandled option (lists_getSublist).\';',
- ' }',
- ' return at;',
- ' }',
- ' at1 = getAt(where1, at1);',
- ' at2 = getAt(where2, at2) + 1;',
- ' return list.slice(at1, at2);',
+ 'subsequence' + wherePascalCase[where1] + wherePascalCase[where2],
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ '(sequence' +
+ // The value for 'FROM_END' and'FROM_START' depends on `at` so
+ // we add it as a parameter.
+ ((where1 == 'FROM_END' || where1 == 'FROM_START') ? ', at1' : '') +
+ ((where2 == 'FROM_END' || where2 == 'FROM_START') ? ', at2' : '') +
+ ') {',
+ ' var start = ' + getIndex_('sequence', where1, 'at1') + ';',
+ ' var end = ' + getIndex_('sequence', where2, 'at2') + ' + 1;',
+ ' return sequence.slice(start, end);',
'}']);
- var code = functionName + '(' + list + ', \'' +
- where1 + '\', ' + at1 + ', \'' + where2 + '\', ' + at2 + ')';
+ var code = functionName + '(' + list +
+ // The value for 'FROM_END' and 'FROM_START' depends on `at` so we
+ // pass it.
+ ((where1 == 'FROM_END' || where1 == 'FROM_START') ? ', ' + at1 : '') +
+ ((where2 == 'FROM_END' || where2 == 'FROM_START') ? ', ' + at2 : '') +
+ ')';
}
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};
Blockly.JavaScript['lists_sort'] = function(block) {
// Block for sorting a list.
- var listCode = Blockly.JavaScript.valueToCode(
- block, 'LIST',
+ var list = Blockly.JavaScript.valueToCode(block, 'LIST',
Blockly.JavaScript.ORDER_FUNCTION_CALL) || '[]';
var direction = block.getFieldValue('DIRECTION') === '1' ? 1 : -1;
var type = block.getFieldValue('TYPE');
var getCompareFunctionName = Blockly.JavaScript.provideFunction_(
- 'listsGetSortCompare',
- ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
- '(type, direction) {',
- ' var compareFuncs = {',
- ' "NUMERIC": function(a, b) {',
- ' return parseFloat(a) - parseFloat(b); },',
- ' "TEXT": function(a, b) {',
- ' return a.toString() > b.toString() ? 1 : -1; },',
- ' "IGNORE_CASE": function(a, b) {',
- ' return a.toString().toLowerCase() > ' +
- 'b.toString().toLowerCase() ? 1 : -1; },',
- ' };',
- ' var compare = compareFuncs[type];',
- ' return function(a, b) { return compare(a, b) * direction; }',
- '}']);
- return ['(' + listCode + ').slice().sort(' +
+ 'listsGetSortCompare',
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ '(type, direction) {',
+ ' var compareFuncs = {',
+ ' "NUMERIC": function(a, b) {',
+ ' return parseFloat(a) - parseFloat(b); },',
+ ' "TEXT": function(a, b) {',
+ ' return a.toString() > b.toString() ? 1 : -1; },',
+ ' "IGNORE_CASE": function(a, b) {',
+ ' return a.toString().toLowerCase() > ' +
+ 'b.toString().toLowerCase() ? 1 : -1; },',
+ ' };',
+ ' var compare = compareFuncs[type];',
+ ' return function(a, b) { return compare(a, b) * direction; }',
+ '}']);
+ return [list + '.slice().sort(' +
getCompareFunctionName + '("' + type + '", ' + direction + '))',
Blockly.JavaScript.ORDER_FUNCTION_CALL];
};
Blockly.JavaScript['lists_split'] = function(block) {
// Block for splitting text into a list, or joining a list into text.
- var value_input = Blockly.JavaScript.valueToCode(block, 'INPUT',
+ var input = Blockly.JavaScript.valueToCode(block, 'INPUT',
Blockly.JavaScript.ORDER_MEMBER);
- var value_delim = Blockly.JavaScript.valueToCode(block, 'DELIM',
+ var delimiter = Blockly.JavaScript.valueToCode(block, 'DELIM',
Blockly.JavaScript.ORDER_NONE) || '\'\'';
var mode = block.getFieldValue('MODE');
if (mode == 'SPLIT') {
- if (!value_input) {
- value_input = '\'\'';
+ if (!input) {
+ input = '\'\'';
}
var functionName = 'split';
} else if (mode == 'JOIN') {
- if (!value_input) {
- value_input = '[]';
+ if (!input) {
+ input = '[]';
}
var functionName = 'join';
} else {
throw 'Unknown mode: ' + mode;
}
- var code = value_input + '.' + functionName + '(' + value_delim + ')';
+ var code = input + '.' + functionName + '(' + delimiter + ')';
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};
diff --git a/generators/javascript/math.js b/generators/javascript/math.js
index 0a7d14621..a31b94392 100644
--- a/generators/javascript/math.js
+++ b/generators/javascript/math.js
@@ -168,25 +168,25 @@ Blockly.JavaScript['math_number_property'] = function(block) {
// Prime is a special case as it is not a one-liner test.
var functionName = Blockly.JavaScript.provideFunction_(
'mathIsPrime',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(n) {',
- ' // https://en.wikipedia.org/wiki/Primality_test#Naive_methods',
- ' if (n == 2 || n == 3) {',
- ' return true;',
- ' }',
- ' // False if n is NaN, negative, is 1, or not whole.',
- ' // And false if n is divisible by 2 or 3.',
- ' if (isNaN(n) || n <= 1 || n % 1 != 0 || n % 2 == 0 ||' +
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(n) {',
+ ' // https://en.wikipedia.org/wiki/Primality_test#Naive_methods',
+ ' if (n == 2 || n == 3) {',
+ ' return true;',
+ ' }',
+ ' // False if n is NaN, negative, is 1, or not whole.',
+ ' // And false if n is divisible by 2 or 3.',
+ ' if (isNaN(n) || n <= 1 || n % 1 != 0 || n % 2 == 0 ||' +
' n % 3 == 0) {',
- ' return false;',
- ' }',
- ' // Check all the numbers of form 6k +/- 1, up to sqrt(n).',
- ' for (var x = 6; x <= Math.sqrt(n) + 1; x += 6) {',
- ' if (n % (x - 1) == 0 || n % (x + 1) == 0) {',
- ' return false;',
- ' }',
- ' }',
- ' return true;',
- '}']);
+ ' return false;',
+ ' }',
+ ' // Check all the numbers of form 6k +/- 1, up to sqrt(n).',
+ ' for (var x = 6; x <= Math.sqrt(n) + 1; x += 6) {',
+ ' if (n % (x - 1) == 0 || n % (x + 1) == 0) {',
+ ' return false;',
+ ' }',
+ ' }',
+ ' return true;',
+ '}']);
code = functionName + '(' + number_to_check + ')';
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
}
@@ -254,7 +254,7 @@ Blockly.JavaScript['math_on_list'] = function(block) {
// mathMean([null,null,1,3]) == 2.0.
var functionName = Blockly.JavaScript.provideFunction_(
'mathMean',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
'(myList) {',
' return myList.reduce(function(x, y) {return x + y;}) / ' +
'myList.length;',
@@ -267,7 +267,7 @@ Blockly.JavaScript['math_on_list'] = function(block) {
// mathMedian([null,null,1,3]) == 2.0.
var functionName = Blockly.JavaScript.provideFunction_(
'mathMedian',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
'(myList) {',
' var localList = myList.filter(function (x) ' +
'{return typeof x == \'number\';});',
@@ -290,7 +290,7 @@ Blockly.JavaScript['math_on_list'] = function(block) {
// Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1].
var functionName = Blockly.JavaScript.provideFunction_(
'mathModes',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
'(values) {',
' var modes = [];',
' var counts = [];',
@@ -326,7 +326,7 @@ Blockly.JavaScript['math_on_list'] = function(block) {
case 'STD_DEV':
var functionName = Blockly.JavaScript.provideFunction_(
'mathStandardDeviation',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
'(numbers) {',
' var n = numbers.length;',
' if (!n) return null;',
@@ -345,7 +345,7 @@ Blockly.JavaScript['math_on_list'] = function(block) {
case 'RANDOM':
var functionName = Blockly.JavaScript.provideFunction_(
'mathRandomList',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
'(list) {',
' var x = Math.floor(Math.random() * list.length);',
' return list[x];',
@@ -391,16 +391,16 @@ Blockly.JavaScript['math_random_int'] = function(block) {
Blockly.JavaScript.ORDER_COMMA) || '0';
var functionName = Blockly.JavaScript.provideFunction_(
'mathRandomInt',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
'(a, b) {',
- ' if (a > b) {',
- ' // Swap a and b to ensure a is smaller.',
- ' var c = a;',
- ' a = b;',
- ' b = c;',
- ' }',
- ' return Math.floor(Math.random() * (b - a + 1) + a);',
- '}']);
+ ' if (a > b) {',
+ ' // Swap a and b to ensure a is smaller.',
+ ' var c = a;',
+ ' a = b;',
+ ' b = c;',
+ ' }',
+ ' return Math.floor(Math.random() * (b - a + 1) + a);',
+ '}']);
var code = functionName + '(' + argument0 + ', ' + argument1 + ')';
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};
diff --git a/generators/javascript/text.js b/generators/javascript/text.js
index 86befb9ef..9ecfdc387 100644
--- a/generators/javascript/text.js
+++ b/generators/javascript/text.js
@@ -37,29 +37,29 @@ Blockly.JavaScript['text'] = function(block) {
Blockly.JavaScript['text_join'] = function(block) {
// Create a string made up of any number of elements of any type.
- var code;
- if (block.itemCount_ == 0) {
- return ['\'\'', Blockly.JavaScript.ORDER_ATOMIC];
- } else if (block.itemCount_ == 1) {
- var argument0 = Blockly.JavaScript.valueToCode(block, 'ADD0',
- Blockly.JavaScript.ORDER_NONE) || '\'\'';
- code = 'String(' + argument0 + ')';
- return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
- } else if (block.itemCount_ == 2) {
- var argument0 = Blockly.JavaScript.valueToCode(block, 'ADD0',
- Blockly.JavaScript.ORDER_NONE) || '\'\'';
- var argument1 = Blockly.JavaScript.valueToCode(block, 'ADD1',
- Blockly.JavaScript.ORDER_NONE) || '\'\'';
- code = 'String(' + argument0 + ') + String(' + argument1 + ')';
- return [code, Blockly.JavaScript.ORDER_ADDITION];
- } else {
- code = new Array(block.itemCount_);
- for (var n = 0; n < block.itemCount_; n++) {
- code[n] = Blockly.JavaScript.valueToCode(block, 'ADD' + n,
- Blockly.JavaScript.ORDER_COMMA) || '\'\'';
- }
- code = '[' + code.join(',') + '].join(\'\')';
- return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
+ switch (block.itemCount_) {
+ case 0:
+ return ['\'\'', Blockly.JavaScript.ORDER_ATOMIC];
+ case 1:
+ var element = Blockly.JavaScript.valueToCode(block, 'ADD0',
+ Blockly.JavaScript.ORDER_NONE) || '\'\'';
+ var code = 'String(' + element + ')';
+ return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
+ case 2:
+ var element0 = Blockly.JavaScript.valueToCode(block, 'ADD0',
+ Blockly.JavaScript.ORDER_NONE) || '\'\'';
+ var element1 = Blockly.JavaScript.valueToCode(block, 'ADD1',
+ Blockly.JavaScript.ORDER_NONE) || '\'\'';
+ var code = 'String(' + element0 + ') + String(' + element1 + ')';
+ return [code, Blockly.JavaScript.ORDER_ADDITION];
+ default:
+ var elements = new Array(block.itemCount_);
+ for (var i = 0; i < block.itemCount_; i++) {
+ elements[i] = Blockly.JavaScript.valueToCode(block, 'ADD' + i,
+ Blockly.JavaScript.ORDER_COMMA) || '\'\'';
+ }
+ var code = '[' + elements.join(',') + '].join(\'\')';
+ return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
}
};
@@ -67,45 +67,49 @@ Blockly.JavaScript['text_append'] = function(block) {
// Append to a variable in place.
var varName = Blockly.JavaScript.variableDB_.getName(
block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
- var argument0 = Blockly.JavaScript.valueToCode(block, 'TEXT',
+ var value = Blockly.JavaScript.valueToCode(block, 'TEXT',
Blockly.JavaScript.ORDER_NONE) || '\'\'';
- return varName + ' = String(' + varName + ') + String(' + argument0 + ');\n';
+ return varName + ' = String(' + varName + ') + String(' + value + ');\n';
};
Blockly.JavaScript['text_length'] = function(block) {
// String or array length.
- var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE',
+ var text = Blockly.JavaScript.valueToCode(block, 'VALUE',
Blockly.JavaScript.ORDER_FUNCTION_CALL) || '\'\'';
- return [argument0 + '.length', Blockly.JavaScript.ORDER_MEMBER];
+ return [text + '.length', Blockly.JavaScript.ORDER_MEMBER];
};
Blockly.JavaScript['text_isEmpty'] = function(block) {
// Is the string null or array empty?
- var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE',
+ var text = Blockly.JavaScript.valueToCode(block, 'VALUE',
Blockly.JavaScript.ORDER_MEMBER) || '\'\'';
- return ['!' + argument0 + '.length', Blockly.JavaScript.ORDER_LOGICAL_NOT];
+ return ['!' + text + '.length', Blockly.JavaScript.ORDER_LOGICAL_NOT];
};
Blockly.JavaScript['text_indexOf'] = function(block) {
// Search the text for a substring.
var operator = block.getFieldValue('END') == 'FIRST' ?
'indexOf' : 'lastIndexOf';
- var argument0 = Blockly.JavaScript.valueToCode(block, 'FIND',
+ var substring = Blockly.JavaScript.valueToCode(block, 'FIND',
Blockly.JavaScript.ORDER_NONE) || '\'\'';
- var argument1 = Blockly.JavaScript.valueToCode(block, 'VALUE',
+ var text = Blockly.JavaScript.valueToCode(block, 'VALUE',
Blockly.JavaScript.ORDER_MEMBER) || '\'\'';
- var code = argument1 + '.' + operator + '(' + argument0 + ') + 1';
- return [code, Blockly.JavaScript.ORDER_ADDITION];
+ var code = text + '.' + operator + '(' + substring + ')';
+ // Adjust index if using one-based indices.
+ if (Blockly.JavaScript.ONE_BASED_INDEXING) {
+ return [code + ' + 1', Blockly.JavaScript.ORDER_ADDITION];
+ }
+ return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};
Blockly.JavaScript['text_charAt'] = function(block) {
// Get letter at index.
// Note: Until January 2013 this block did not have the WHERE input.
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.JavaScript.valueToCode(block, 'AT',
- Blockly.JavaScript.ORDER_UNARY_NEGATION) || '1';
+ var textOrder = (where == 'RANDOM') ? Blockly.JavaScript.ORDER_NONE :
+ Blockly.JavaScript.ORDER_MEMBER;
var text = Blockly.JavaScript.valueToCode(block, 'VALUE',
- Blockly.JavaScript.ORDER_MEMBER) || '\'\'';
+ textOrder) || '\'\'';
switch (where) {
case 'FIRST':
var code = text + '.charAt(0)';
@@ -114,70 +118,117 @@ Blockly.JavaScript['text_charAt'] = function(block) {
var code = text + '.slice(-1)';
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
case 'FROM_START':
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at)) {
- // If the index is a naked number, decrement it right now.
- at = parseFloat(at) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at += ' - 1';
- }
+ var at = Blockly.JavaScript.getAdjusted(block, 'AT');
+ // Adjust index if using one-based indices.
var code = text + '.charAt(' + at + ')';
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
case 'FROM_END':
- var code = text + '.slice(-' + at + ').charAt(0)';
+ var at = Blockly.JavaScript.getAdjusted(block, 'AT', 1, true);
+ var code = text + '.slice(' + at + ').charAt(0)';
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
case 'RANDOM':
var functionName = Blockly.JavaScript.provideFunction_(
'textRandomLetter',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
'(text) {',
- ' var x = Math.floor(Math.random() * text.length);',
- ' return text[x];',
- '}']);
- code = functionName + '(' + text + ')';
+ ' var x = Math.floor(Math.random() * text.length);',
+ ' return text[x];',
+ '}']);
+ var code = functionName + '(' + text + ')';
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
}
throw 'Unhandled option (text_charAt).';
};
+/**
+ * Returns an expression calculating the index into a string.
+ * @private
+ * @param {string} stringName Name of the string, used to calculate length.
+ * @param {string} where The method of indexing, selected by dropdown in Blockly
+ * @param {string=} opt_at The optional offset when indexing from start/end.
+ * @return {string} Index expression.
+ */
+Blockly.JavaScript.text.getIndex_ = function(stringName, where, opt_at) {
+ if (where == 'FIRST') {
+ return '0';
+ } else if (where == 'FROM_END') {
+ return stringName + '.length - 1 - ' + opt_at;
+ } else if (where == 'LAST') {
+ return stringName + '.length - 1';
+ } else {
+ return opt_at;
+ }
+};
+
Blockly.JavaScript['text_getSubstring'] = function(block) {
// Get substring.
var text = Blockly.JavaScript.valueToCode(block, 'STRING',
- Blockly.JavaScript.ORDER_MEMBER) || '\'\'';
+ Blockly.JavaScript.ORDER_FUNCTION_CALL) || '\'\'';
var where1 = block.getFieldValue('WHERE1');
var where2 = block.getFieldValue('WHERE2');
- var at1 = Blockly.JavaScript.valueToCode(block, 'AT1',
- Blockly.JavaScript.ORDER_NONE) || '1';
- var at2 = Blockly.JavaScript.valueToCode(block, 'AT2',
- Blockly.JavaScript.ORDER_NONE) || '1';
if (where1 == 'FIRST' && where2 == 'LAST') {
var code = text;
+ } else if (text.match(/^'?\w+'?$/) ||
+ (where1 != 'FROM_END' && where1 != 'LAST' &&
+ where2 != 'FROM_END' && where2 != 'LAST')) {
+ // If the text is a variable or literal or doesn't require a call for
+ // length, don't generate a helper function.
+ switch (where1) {
+ case 'FROM_START':
+ var at1 = Blockly.JavaScript.getAdjusted(block, 'AT1');
+ break;
+ case 'FROM_END':
+ var at1 = Blockly.JavaScript.getAdjusted(block, 'AT1', 1, false,
+ Blockly.JavaScript.ORDER_SUBTRACTION);
+ at1 = text + '.length - ' + at1;
+ break;
+ case 'FIRST':
+ var at1 = '0';
+ break;
+ default:
+ throw 'Unhandled option (text_getSubstring).';
+ }
+ switch (where2) {
+ case 'FROM_START':
+ var at2 = Blockly.JavaScript.getAdjusted(block, 'AT2', 1);
+ break;
+ case 'FROM_END':
+ var at2 = Blockly.JavaScript.getAdjusted(block, 'AT2', 0, false,
+ Blockly.JavaScript.ORDER_SUBTRACTION);
+ at2 = text + '.length - ' + at2;
+ break;
+ case 'LAST':
+ var at2 = text + '.length';
+ break;
+ default:
+ throw 'Unhandled option (text_getSubstring).';
+ }
+ code = text + '.slice(' + at1 + ', ' + at2 + ')';
} else {
+ var at1 = Blockly.JavaScript.getAdjusted(block, 'AT1');
+ var at2 = Blockly.JavaScript.getAdjusted(block, 'AT2');
+ var getIndex_ = Blockly.JavaScript.text.getIndex_;
+ var wherePascalCase = {'FIRST': 'First', 'LAST': 'Last',
+ 'FROM_START': 'FromStart', 'FROM_END': 'FromEnd'};
var functionName = Blockly.JavaScript.provideFunction_(
- 'textGetSubstring',
- [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
- '(text, where1, at1, where2, at2) {',
- ' function getAt(where, at) {',
- ' if (where == \'FROM_START\') {',
- ' at--;',
- ' } else if (where == \'FROM_END\') {',
- ' at = text.length - at;',
- ' } else if (where == \'FIRST\') {',
- ' at = 0;',
- ' } else if (where == \'LAST\') {',
- ' at = text.length - 1;',
- ' } else {',
- ' throw \'Unhandled option (text_getSubstring).\';',
- ' }',
- ' return at;',
- ' }',
- ' at1 = getAt(where1, at1);',
- ' at2 = getAt(where2, at2) + 1;',
- ' return text.slice(at1, at2);',
+ 'subsequence' + wherePascalCase[where1] + wherePascalCase[where2],
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ '(sequence' +
+ // The value for 'FROM_END' and'FROM_START' depends on `at` so
+ // we add it as a parameter.
+ ((where1 == 'FROM_END' || where1 == 'FROM_START') ? ', at1' : '') +
+ ((where2 == 'FROM_END' || where2 == 'FROM_START') ? ', at2' : '') +
+ ') {',
+ ' var start = ' + getIndex_('sequence', where1, 'at1') + ';',
+ ' var end = ' + getIndex_('sequence', where2, 'at2') + ' + 1;',
+ ' return sequence.slice(start, end);',
'}']);
- var code = functionName + '(' + text + ', \'' +
- where1 + '\', ' + at1 + ', \'' + where2 + '\', ' + at2 + ')';
+ var code = functionName + '(' + text +
+ // The value for 'FROM_END' and 'FROM_START' depends on `at` so we
+ // pass it.
+ ((where1 == 'FROM_END' || where1 == 'FROM_START') ? ', ' + at1 : '') +
+ ((where2 == 'FROM_END' || where2 == 'FROM_START') ? ', ' + at2 : '') +
+ ')';
}
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};
@@ -190,25 +241,24 @@ Blockly.JavaScript['text_changeCase'] = function(block) {
'TITLECASE': null
};
var operator = OPERATORS[block.getFieldValue('CASE')];
- var code;
+ var textOrder = operator ? Blockly.JavaScript.ORDER_MEMBER :
+ Blockly.JavaScript.ORDER_NONE;
+ var text = Blockly.JavaScript.valueToCode(block, 'TEXT',
+ textOrder) || '\'\'';
if (operator) {
// Upper and lower case are functions built into JavaScript.
- var argument0 = Blockly.JavaScript.valueToCode(block, 'TEXT',
- Blockly.JavaScript.ORDER_MEMBER) || '\'\'';
- code = argument0 + operator;
+ var code = text + operator;
} else {
// Title case is not a native JavaScript function. Define one.
var functionName = Blockly.JavaScript.provideFunction_(
'textToTitleCase',
- [ 'function ' +
- Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(str) {',
- ' return str.replace(/\\S+/g,',
- ' function(txt) {return txt[0].toUpperCase() + ' +
- 'txt.substring(1).toLowerCase();});',
- '}']);
- var argument0 = Blockly.JavaScript.valueToCode(block, 'TEXT',
- Blockly.JavaScript.ORDER_NONE) || '\'\'';
- code = functionName + '(' + argument0 + ')';
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ '(str) {',
+ ' return str.replace(/\\S+/g,',
+ ' function(txt) {return txt[0].toUpperCase() + ' +
+ 'txt.substring(1).toLowerCase();});',
+ '}']);
+ var code = functionName + '(' + text + ')';
}
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};
@@ -221,16 +271,16 @@ Blockly.JavaScript['text_trim'] = function(block) {
'BOTH': '.trim()'
};
var operator = OPERATORS[block.getFieldValue('MODE')];
- var argument0 = Blockly.JavaScript.valueToCode(block, 'TEXT',
+ var text = Blockly.JavaScript.valueToCode(block, 'TEXT',
Blockly.JavaScript.ORDER_MEMBER) || '\'\'';
- return [argument0 + operator, Blockly.JavaScript.ORDER_FUNCTION_CALL];
+ return [text + operator, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};
Blockly.JavaScript['text_print'] = function(block) {
// Print statement.
- var argument0 = Blockly.JavaScript.valueToCode(block, 'TEXT',
+ var msg = Blockly.JavaScript.valueToCode(block, 'TEXT',
Blockly.JavaScript.ORDER_NONE) || '\'\'';
- return 'window.alert(' + argument0 + ');\n';
+ return 'window.alert(' + msg + ');\n';
};
Blockly.JavaScript['text_prompt_ext'] = function(block) {
diff --git a/generators/lua.js b/generators/lua.js
index 6dbecb666..225489641 100644
--- a/generators/lua.js
+++ b/generators/lua.js
@@ -77,7 +77,7 @@ Blockly.Lua.ORDER_ATOMIC = 0; // literals
// The next level was not explicit in documentation and inferred by Ellen.
Blockly.Lua.ORDER_HIGH = 1; // Function calls, tables[]
Blockly.Lua.ORDER_EXPONENTIATION = 2; // ^
-Blockly.Lua.ORDER_UNARY = 3; // not # - ()
+Blockly.Lua.ORDER_UNARY = 3; // not # - ~
Blockly.Lua.ORDER_MULTIPLICATIVE = 4; // * / %
Blockly.Lua.ORDER_ADDITIVE = 5; // + -
Blockly.Lua.ORDER_CONCATENATION = 6; // ..
@@ -86,6 +86,12 @@ Blockly.Lua.ORDER_AND = 8; // and
Blockly.Lua.ORDER_OR = 9; // or
Blockly.Lua.ORDER_NONE = 99;
+/**
+ * Lua is not supporting zero-indexing since the language itself is one-indexed,
+ * so there is not flag for ONE_BASED_INDEXING to indicate which indexing is
+ * used for lists and text.
+ */
+
/**
* Initialise the database of variable names.
* @param {!Blockly.Workspace} workspace Workspace to generate code from.
@@ -170,9 +176,9 @@ Blockly.Lua.scrub_ = function(block, code) {
}
// Collect comments for all value arguments.
// Don't collect comments for nested statements.
- for (var x = 0; x < block.inputList.length; x++) {
- if (block.inputList[x].type == Blockly.INPUT_VALUE) {
- var childBlock = block.inputList[x].connection.targetBlock();
+ for (var i = 0; i < block.inputList.length; i++) {
+ if (block.inputList[i].type == Blockly.INPUT_VALUE) {
+ var childBlock = block.inputList[i].connection.targetBlock();
if (childBlock) {
comment = Blockly.Lua.allNestedComments(childBlock);
if (comment) {
diff --git a/generators/lua/lists.js b/generators/lua/lists.js
index 8c89a1bd3..5b7711dbb 100644
--- a/generators/lua/lists.js
+++ b/generators/lua/lists.js
@@ -31,18 +31,17 @@ goog.require('Blockly.Lua');
Blockly.Lua['lists_create_empty'] = function(block) {
// Create an empty list.
- // List literals must be parenthesized before indexing into.
- return ['({})', Blockly.Lua.ORDER_ATOMIC];
+ return ['{}', Blockly.Lua.ORDER_ATOMIC];
};
Blockly.Lua['lists_create_with'] = function(block) {
// Create a list with any number of elements of any type.
- var code = new Array(block.itemCount_);
- for (var n = 0; n < block.itemCount_; n++) {
- code[n] = Blockly.Lua.valueToCode(block, 'ADD' + n,
+ var elements = new Array(block.itemCount_);
+ for (var i = 0; i < block.itemCount_; i++) {
+ elements[i] = Blockly.Lua.valueToCode(block, 'ADD' + i,
Blockly.Lua.ORDER_NONE) || 'None';
}
- code = '({' + code.join(', ') + '})';
+ var code = '{' + elements.join(', ') + '}';
return [code, Blockly.Lua.ORDER_ATOMIC];
};
@@ -57,38 +56,37 @@ Blockly.Lua['lists_repeat'] = function(block) {
' end',
' return t',
'end']);
- var argument0 = Blockly.Lua.valueToCode(block, 'ITEM',
+ var element = Blockly.Lua.valueToCode(block, 'ITEM',
Blockly.Lua.ORDER_NONE) || 'None';
- var argument1 = Blockly.Lua.valueToCode(block, 'NUM',
+ var repeatCount = Blockly.Lua.valueToCode(block, 'NUM',
Blockly.Lua.ORDER_NONE) || '0';
- var code = functionName + '(' + argument0 + ', ' + argument1 + ')';
+ var code = functionName + '(' + element + ', ' + repeatCount + ')';
return [code, Blockly.Lua.ORDER_HIGH];
};
Blockly.Lua['lists_length'] = function(block) {
// String or array length.
- var argument0 = Blockly.Lua.valueToCode(block, 'VALUE',
- Blockly.Lua.ORDER_HIGH) || '({})';
- return ['#' + argument0, Blockly.Lua.ORDER_HIGH];
+ var list = Blockly.Lua.valueToCode(block, 'VALUE',
+ Blockly.Lua.ORDER_UNARY) || '{}';
+ return ['#' + list, Blockly.Lua.ORDER_UNARY];
};
Blockly.Lua['lists_isEmpty'] = function(block) {
// Is the string null or array empty?
- var argument0 = Blockly.Lua.valueToCode(block, 'VALUE',
- Blockly.Lua.ORDER_HIGH) || '({})';
- var code = '#' + argument0 + ' == 0';
+ var list = Blockly.Lua.valueToCode(block, 'VALUE',
+ Blockly.Lua.ORDER_UNARY) || '{}';
+ var code = '#' + list + ' == 0';
return [code, Blockly.Lua.ORDER_RELATIONAL];
};
Blockly.Lua['lists_indexOf'] = function(block) {
// Find an item in the list.
- var argument0 = Blockly.Lua.valueToCode(block, 'FIND',
+ var item = Blockly.Lua.valueToCode(block, 'FIND',
Blockly.Lua.ORDER_NONE) || '\'\'';
- var argument1 = Blockly.Lua.valueToCode(block, 'VALUE',
- Blockly.Lua.ORDER_NONE) || '({})';
- var functionName;
+ var list = Blockly.Lua.valueToCode(block, 'VALUE',
+ Blockly.Lua.ORDER_NONE) || '{}';
if (block.getFieldValue('END') == 'FIRST') {
- functionName = Blockly.Lua.provideFunction_(
+ var functionName = Blockly.Lua.provideFunction_(
'first_index',
['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(t, elem)',
' for k, v in ipairs(t) do',
@@ -99,7 +97,7 @@ Blockly.Lua['lists_indexOf'] = function(block) {
' return 0',
'end']);
} else {
- functionName = Blockly.Lua.provideFunction_(
+ var functionName = Blockly.Lua.provideFunction_(
'last_index',
['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(t, elem)',
' for i = #t, 1, -1 do',
@@ -110,64 +108,40 @@ Blockly.Lua['lists_indexOf'] = function(block) {
' return 0',
'end']);
}
- var code = functionName + '(' + argument1 + ', ' + argument0 + ')';
+ var code = functionName + '(' + list + ', ' + item + ')';
return [code, Blockly.Lua.ORDER_HIGH];
};
/**
* Returns an expression calculating the index into a list.
* @private
- * @param {string} listname Name of the list, used to calculate length.
+ * @param {string} listName Name of the list, used to calculate length.
* @param {string} where The method of indexing, selected by dropdown in Blockly
* @param {string=} opt_at The optional offset when indexing from start/end.
* @return {string} Index expression.
*/
-Blockly.Lua.lists.getIndex_ = function(listname, where, opt_at) {
+Blockly.Lua.lists.getIndex_ = function(listName, where, opt_at) {
if (where == 'FIRST') {
return '1';
} else if (where == 'FROM_END') {
- return '#' + listname + ' + 1 - ' + opt_at;
+ return '#' + listName + ' + 1 - ' + opt_at;
} else if (where == 'LAST') {
- return '#' + listname;
+ return '#' + listName;
} else if (where == 'RANDOM') {
- return 'math.random(#' + listname + ')';
+ return 'math.random(#' + listName + ')';
} else {
return opt_at;
}
};
-/**
- * Counter for generating unique symbols.
- * @private
- * @type {number}
- */
-Blockly.Lua.lists.gensym_counter_ = 0;
-
-/**
- * Generate a unique symbol.
- * @private
- * @return {string} unique symbol, eg 'G123'
- */
-Blockly.Lua.lists.gensym_ = function() {
- return 'G' + Blockly.Lua.lists.gensym_counter_++;
-};
-
Blockly.Lua['lists_getIndex'] = function(block) {
// Get element at index.
// Note: Until January 2013 this block did not have MODE or WHERE inputs.
var mode = block.getFieldValue('MODE') || 'GET';
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.Lua.valueToCode(block, 'AT',
- Blockly.Lua.ORDER_ADDITIVE) || '1';
- if (mode == 'GET') {
- var order = Blockly.Lua.ORDER_HIGH;
- } else {
- // List will be an argument in a function call.
- var order = Blockly.Lua.ORDER_NONE;
- }
- var list = Blockly.Lua.valueToCode(block, 'VALUE', order) || '({})';
+ var list = Blockly.Lua.valueToCode(block, 'VALUE', Blockly.Lua.ORDER_HIGH) ||
+ '{}';
var getIndex_ = Blockly.Lua.lists.getIndex_;
- var gensym_ = Blockly.Lua.lists.gensym_;
// If `list` would be evaluated more than once (which is the case for LAST,
// FROM_END, and RANDOM) and is non-trivial, make sure to access it only once.
@@ -176,46 +150,59 @@ Blockly.Lua['lists_getIndex'] = function(block) {
// `list` is an expression, so we may not evaluate it more than once.
if (mode == 'REMOVE') {
// We can use multiple statements.
+ var atOrder = (where == 'FROM_END') ? Blockly.Lua.ORDER_ADDITIVE :
+ Blockly.Lua.ORDER_NONE;
+ var at = Blockly.Lua.valueToCode(block, 'AT', atOrder) || '1';
var listVar = Blockly.Lua.variableDB_.getDistinctName(
'tmp_list', Blockly.Variables.NAME_TYPE);
+ at = getIndex_(listVar, where, at);
var code = listVar + ' = ' + list + '\n' +
- 'table.remove(' + listVar + ', ' + getIndex_(listVar, where, at) +
- ')\n';
+ 'table.remove(' + listVar + ', ' + at + ')\n';
return code;
} else {
// We need to create a procedure to avoid reevaluating values.
+ var at = Blockly.Lua.valueToCode(block, 'AT', Blockly.Lua.ORDER_NONE) ||
+ '1';
if (mode == 'GET') {
- // Note that getIndex_() ignores `at` when `where` == 'LAST' or
- // 'RANDOM', so we only need one procedure for each of those 'where'
- // values. The value for 'FROM_END' depends on `at`, so we will
- // generate a unique procedure (name) each time.
var functionName = Blockly.Lua.provideFunction_(
- 'list_get_' + where.toLowerCase() +
- (where == 'FROM_END' ? '_' + gensym_() : ''),
- ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(t)',
- ' return t[' + getIndex_('t', where, at) + ']',
+ 'list_get_' + where.toLowerCase(),
+ ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(t' +
+ // The value for 'FROM_END' and'FROM_START' depends on `at` so
+ // we add it as a parameter.
+ ((where == 'FROM_END' || where == 'FROM_START') ?
+ ', at)' : ')'),
+ ' return t[' + getIndex_('t', where, 'at') + ']',
'end']);
- } else { // mode == 'GET_REMOVE'
- // We need to create a procedure.
+ } else { // mode == 'GET_REMOVE'
var functionName = Blockly.Lua.provideFunction_(
- 'list_remove_' + where.toLowerCase() +
- (where == 'FROM_END' ? '_' + gensym_() : ''),
- ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(t)',
- ' return table.remove(t, ' + getIndex_('t', where, at) + ')',
+ 'list_remove_' + where.toLowerCase(),
+ ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(t' +
+ // The value for 'FROM_END' and'FROM_START' depends on `at` so
+ // we add it as a parameter.
+ ((where == 'FROM_END' || where == 'FROM_START') ?
+ ', at)' : ')'),
+ ' return table.remove(t, ' + getIndex_('t', where, 'at') + ')',
'end']);
}
- var code = functionName + '(' + list + ')';
+ var code = functionName + '(' + list +
+ // The value for 'FROM_END' and 'FROM_START' depends on `at` so we
+ // pass it.
+ ((where == 'FROM_END' || where == 'FROM_START') ? ', ' + at : '') +
+ ')';
return [code, Blockly.Lua.ORDER_HIGH];
}
} else {
// Either `list` is a simple variable, or we only need to refer to `list`
// once.
+ var atOrder = (mode == 'GET' && where == 'FROM_END') ?
+ Blockly.Lua.ORDER_ADDITIVE : Blockly.Lua.ORDER_NONE;
+ var at = Blockly.Lua.valueToCode(block, 'AT', atOrder) || '1';
+ at = getIndex_(list, where, at);
if (mode == 'GET') {
- var code = list + '[' + getIndex_(list, where, at) + ']';
+ var code = list + '[' + at + ']';
return [code, Blockly.Lua.ORDER_HIGH];
} else {
- var code = 'table.remove(' + list + ', ' + getIndex_(list, where, at) +
- ')';
+ var code = 'table.remove(' + list + ', ' + at + ')';
if (mode == 'GET_REMOVE') {
return [code, Blockly.Lua.ORDER_HIGH];
} else { // `mode` == 'REMOVE'
@@ -229,7 +216,7 @@ Blockly.Lua['lists_setIndex'] = function(block) {
// Set element at index.
// Note: Until February 2013 this block did not have MODE or WHERE inputs.
var list = Blockly.Lua.valueToCode(block, 'LIST',
- Blockly.Lua.ORDER_HIGH) || '({})';
+ Blockly.Lua.ORDER_HIGH) || '{}';
var mode = block.getFieldValue('MODE') || 'SET';
var where = block.getFieldValue('WHERE') || 'FROM_START';
var at = Blockly.Lua.valueToCode(block, 'AT',
@@ -238,97 +225,71 @@ Blockly.Lua['lists_setIndex'] = function(block) {
Blockly.Lua.ORDER_NONE) || 'None';
var getIndex_ = Blockly.Lua.lists.getIndex_;
+ var code = '';
// If `list` would be evaluated more than once (which is the case for LAST,
// FROM_END, and RANDOM) and is non-trivial, make sure to access it only once.
if ((where == 'LAST' || where == 'FROM_END' || where == 'RANDOM') &&
!list.match(/^\w+$/)) {
// `list` is an expression, so we may not evaluate it more than once.
- if (where == 'RANDOM' || where == 'LAST') {
- // In these cases, `at` is implicit. getIndex_() ignores its value.
- if (mode == 'SET') {
- var functionName = Blockly.Lua.provideFunction_(
- 'list_set_' + where.toLowerCase(),
- ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(t, val)',
- ' t[' + getIndex_('t', where, at) + '] = val',
- 'end']);
- } else { // `mode` == 'INSERT'
- var functionName = Blockly.Lua.provideFunction_(
- 'list_insert_' + where.toLowerCase(),
- ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(t, val)',
- ' table.insert(t, ' +
- // LAST is a special case, because we want to insert
- // *after* not *before*, the existing last element.
- getIndex_('t', where, at) + (where == 'LAST' ? ' + 1' : '') +
- ', val)',
- 'end']);
- }
- var code = functionName + '(' + list + ', ' + value + ')\n';
- return code;
- } else { // `where` = 'FROM_END'
- if (mode == 'SET') {
- var functionName = Blockly.Lua.provideFunction_(
- 'list_set_from_end',
- ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ +
- '(t, index, val)',
- ' t[#t + 1 - index] = val',
- 'end']);
- } else { // `mode` == 'INSERT'
- var functionName = Blockly.Lua.provideFunction_(
- 'list_insert_from_end',
- ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ +
- '(t, index, val)',
- ' table.insert(t, #t + 1 - index, val)',
- 'end']);
- }
- var code = functionName + '(' + list + ', ' + at + ', ' + value + ')\n';
- return code;
- }
- } else {
- // It's okay to have multiple references to the list.
- if (mode == 'SET') {
- var code = list + '[' + getIndex_(list, where, at) + '] = ' + value;
- } else { // `mode` == 'INSERT'
- // LAST is a special case, because we want to insert
- // *after* not *before*, the existing last element.
- var code = 'table.insert(' + list + ', ' +
- (getIndex_(list, where, at) + (where == 'LAST' ? ' + 1' : '')) +
- ', ' + value + ')';
- }
- return code + '\n';
+ // We can use multiple statements.
+ var listVar = Blockly.Lua.variableDB_.getDistinctName(
+ 'tmp_list', Blockly.Variables.NAME_TYPE);
+ code = listVar + ' = ' + list + '\n';
+ list = listVar;
}
+ if (mode == 'SET') {
+ code += list + '[' + getIndex_(list, where, at) + '] = ' + value;
+ } else { // `mode` == 'INSERT'
+ // LAST is a special case, because we want to insert
+ // *after* not *before*, the existing last element.
+ code += 'table.insert(' + list + ', ' +
+ (getIndex_(list, where, at) + (where == 'LAST' ? ' + 1' : '')) +
+ ', ' + value + ')';
+ }
+ return code + '\n';
};
Blockly.Lua['lists_getSublist'] = function(block) {
// Get sublist.
var list = Blockly.Lua.valueToCode(block, 'LIST',
- Blockly.Lua.ORDER_HIGH) || '({})';
+ Blockly.Lua.ORDER_NONE) || '{}';
var where1 = block.getFieldValue('WHERE1');
var where2 = block.getFieldValue('WHERE2');
var at1 = Blockly.Lua.valueToCode(block, 'AT1',
- Blockly.Lua.ORDER_ADDITIVE) || '1';
+ Blockly.Lua.ORDER_NONE) || '1';
var at2 = Blockly.Lua.valueToCode(block, 'AT2',
- Blockly.Lua.ORDER_ADDITIVE) || '1';
+ Blockly.Lua.ORDER_NONE) || '1';
var getIndex_ = Blockly.Lua.lists.getIndex_;
var functionName = Blockly.Lua.provideFunction_(
- 'list_sublist_' + Blockly.Lua.lists.gensym_(),
- ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(source)',
+ 'list_sublist_' + where1.toLowerCase() + '_' + where2.toLowerCase(),
+ ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(source' +
+ // The value for 'FROM_END' and'FROM_START' depends on `at` so
+ // we add it as a parameter.
+ ((where1 == 'FROM_END' || where1 == 'FROM_START') ? ', at1' : '') +
+ ((where2 == 'FROM_END' || where2 == 'FROM_START') ? ', at2' : '') +
+ ')',
' local t = {}',
- ' local start = ' + getIndex_('source', where1, at1),
- ' local finish = ' + getIndex_('source', where2, at2),
+ ' local start = ' + getIndex_('source', where1, 'at1'),
+ ' local finish = ' + getIndex_('source', where2, 'at2'),
' for i = start, finish do',
' table.insert(t, source[i])',
' end',
' return t',
'end']);
- var code = functionName + '(' + list + ')';
+ var code = functionName + '(' + list +
+ // The value for 'FROM_END' and 'FROM_START' depends on `at` so we
+ // pass it.
+ ((where1 == 'FROM_END' || where1 == 'FROM_START') ? ', ' + at1 : '') +
+ ((where2 == 'FROM_END' || where2 == 'FROM_START') ? ', ' + at2 : '') +
+ ')';
return [code, Blockly.Lua.ORDER_HIGH];
};
Blockly.Lua['lists_sort'] = function(block) {
// Block for sorting a list.
- var listCode = Blockly.Lua.valueToCode(
- block, 'LIST', Blockly.Lua.ORDER_HIGH) || '({})';
+ var list = Blockly.Lua.valueToCode(
+ block, 'LIST', Blockly.Lua.ORDER_NONE) || '{}';
var direction = block.getFieldValue('DIRECTION') === '1' ? 1 : -1;
var type = block.getFieldValue('TYPE');
@@ -357,26 +318,26 @@ Blockly.Lua['lists_sort'] = function(block) {
'end']);
var code = functionName +
- '(' + listCode + ',"' + type + '", ' + direction + ')';
+ '(' + list + ',"' + type + '", ' + direction + ')';
return [code, Blockly.Lua.ORDER_HIGH];
};
Blockly.Lua['lists_split'] = function(block) {
// Block for splitting text into a list, or joining a list into text.
- var value_input = Blockly.Lua.valueToCode(block, 'INPUT',
+ var input = Blockly.Lua.valueToCode(block, 'INPUT',
Blockly.Lua.ORDER_NONE);
- var value_delim = Blockly.Lua.valueToCode(block, 'DELIM',
+ var delimiter = Blockly.Lua.valueToCode(block, 'DELIM',
Blockly.Lua.ORDER_NONE) || '\'\'';
var mode = block.getFieldValue('MODE');
var functionName;
if (mode == 'SPLIT') {
- if (!value_input) {
- value_input = '\'\'';
+ if (!input) {
+ input = '\'\'';
}
functionName = Blockly.Lua.provideFunction_(
'list_string_split',
['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ +
- '(input, delim)',
+ '(input, delim)',
' local t = {}',
' local pos = 1',
' while true do',
@@ -392,13 +353,13 @@ Blockly.Lua['lists_split'] = function(block) {
' return t',
'end']);
} else if (mode == 'JOIN') {
- if (!value_input) {
- value_input = '({})';
+ if (!input) {
+ input = '{}';
}
functionName = 'table.concat';
} else {
throw 'Unknown mode: ' + mode;
}
- var code = functionName + '(' + value_input + ', ' + value_delim + ')';
+ var code = functionName + '(' + input + ', ' + delimiter + ')';
return [code, Blockly.Lua.ORDER_HIGH];
};
diff --git a/generators/lua/procedures.js b/generators/lua/procedures.js
index 9bdcc416b..b6d6cdda1 100644
--- a/generators/lua/procedures.js
+++ b/generators/lua/procedures.js
@@ -51,8 +51,8 @@ Blockly.Lua['procedures_defreturn'] = function(block) {
branch = '';
}
var args = [];
- for (var x = 0; x < block.arguments_.length; x++) {
- args[x] = Blockly.Lua.variableDB_.getName(block.arguments_[x],
+ for (var i = 0; i < block.arguments_.length; i++) {
+ args[i] = Blockly.Lua.variableDB_.getName(block.arguments_[i],
Blockly.Variables.NAME_TYPE);
}
var code = 'function ' + funcName + '(' + args.join(', ') + ')\n' +
@@ -73,8 +73,8 @@ Blockly.Lua['procedures_callreturn'] = function(block) {
var funcName = Blockly.Lua.variableDB_.getName(
block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE);
var args = [];
- for (var x = 0; x < block.arguments_.length; x++) {
- args[x] = Blockly.Lua.valueToCode(block, 'ARG' + x,
+ for (var i = 0; i < block.arguments_.length; i++) {
+ args[i] = Blockly.Lua.valueToCode(block, 'ARG' + i,
Blockly.Lua.ORDER_NONE) || 'nil';
}
var code = funcName + '(' + args.join(', ') + ')';
@@ -86,8 +86,8 @@ Blockly.Lua['procedures_callnoreturn'] = function(block) {
var funcName = Blockly.Lua.variableDB_.getName(
block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE);
var args = [];
- for (var x = 0; x < block.arguments_.length; x++) {
- args[x] = Blockly.Lua.valueToCode(block, 'ARG' + x,
+ for (var i = 0; i < block.arguments_.length; i++) {
+ args[i] = Blockly.Lua.valueToCode(block, 'ARG' + i,
Blockly.Lua.ORDER_NONE) || 'nil';
}
var code = funcName + '(' + args.join(', ') + ')\n';
diff --git a/generators/lua/text.js b/generators/lua/text.js
index 8a6a02702..74efba4a2 100644
--- a/generators/lua/text.js
+++ b/generators/lua/text.js
@@ -40,24 +40,24 @@ Blockly.Lua['text_join'] = function(block) {
if (block.itemCount_ == 0) {
return ['\'\'', Blockly.Lua.ORDER_ATOMIC];
} else if (block.itemCount_ == 1) {
- var argument0 = Blockly.Lua.valueToCode(block, 'ADD0',
+ var element = Blockly.Lua.valueToCode(block, 'ADD0',
Blockly.Lua.ORDER_NONE) || '\'\'';
- var code = argument0;
+ var code = 'tostring(' + element + ')';
return [code, Blockly.Lua.ORDER_HIGH];
} else if (block.itemCount_ == 2) {
- var argument0 = Blockly.Lua.valueToCode(block, 'ADD0',
- Blockly.Lua.ORDER_NONE) || '\'\'';
- var argument1 = Blockly.Lua.valueToCode(block, 'ADD1',
- Blockly.Lua.ORDER_NONE) || '\'\'';
- var code = argument0 + ' .. ' + argument1;
- return [code, Blockly.Lua.ORDER_UNARY];
+ var element0 = Blockly.Lua.valueToCode(block, 'ADD0',
+ Blockly.Lua.ORDER_CONCATENATION) || '\'\'';
+ var element1 = Blockly.Lua.valueToCode(block, 'ADD1',
+ Blockly.Lua.ORDER_CONCATENATION) || '\'\'';
+ var code = element0 + ' .. ' + element1;
+ return [code, Blockly.Lua.ORDER_CONCATENATION];
} else {
- var code = [];
- for (var n = 0; n < block.itemCount_; n++) {
- code[n] = Blockly.Lua.valueToCode(block, 'ADD' + n,
+ var elements = [];
+ for (var i = 0; i < block.itemCount_; i++) {
+ elements[i] = Blockly.Lua.valueToCode(block, 'ADD' + i,
Blockly.Lua.ORDER_NONE) || '\'\'';
}
- code = 'table.concat({' + code.join(', ') + '})';
+ var code = 'table.concat({' + elements.join(', ') + '})';
return [code, Blockly.Lua.ORDER_HIGH];
}
};
@@ -66,32 +66,30 @@ Blockly.Lua['text_append'] = function(block) {
// Append to a variable in place.
var varName = Blockly.Lua.variableDB_.getName(
block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
- var argument0 = Blockly.Lua.valueToCode(block, 'TEXT',
- Blockly.Lua.ORDER_NONE) || '\'\'';
- return varName + ' = ' + varName + ' .. ' + argument0 + '\n';
+ var value = Blockly.Lua.valueToCode(block, 'TEXT',
+ Blockly.Lua.ORDER_CONCATENATION) || '\'\'';
+ return varName + ' = ' + varName + ' .. ' + value + '\n';
};
Blockly.Lua['text_length'] = function(block) {
// String or array length.
- var argument0 = Blockly.Lua.valueToCode(block, 'VALUE',
- Blockly.Lua.ORDER_HIGH) || '\'\'';
- return ['#' + argument0, Blockly.Lua.ORDER_HIGH];
+ var text = Blockly.Lua.valueToCode(block, 'VALUE',
+ Blockly.Lua.ORDER_UNARY) || '\'\'';
+ return ['#' + text, Blockly.Lua.ORDER_UNARY];
};
Blockly.Lua['text_isEmpty'] = function(block) {
// Is the string null or array empty?
- var argument0 = Blockly.Lua.valueToCode(block, 'VALUE',
- Blockly.Lua.ORDER_HIGH) || '\'\'';
- return ['#' + argument0 + ' == 0', Blockly.Lua.ORDER_RELATIONAL];
+ var text = Blockly.Lua.valueToCode(block, 'VALUE',
+ Blockly.Lua.ORDER_UNARY) || '\'\'';
+ return ['#' + text + ' == 0', Blockly.Lua.ORDER_RELATIONAL];
};
Blockly.Lua['text_indexOf'] = function(block) {
// Search the text for a substring.
- var operator = block.getFieldValue('END') == 'FIRST' ?
- 'indexOf' : 'lastIndexOf';
- var substr = Blockly.Lua.valueToCode(block, 'FIND',
+ var substring = Blockly.Lua.valueToCode(block, 'FIND',
Blockly.Lua.ORDER_NONE) || '\'\'';
- var str = Blockly.Lua.valueToCode(block, 'VALUE',
+ var text = Blockly.Lua.valueToCode(block, 'VALUE',
Blockly.Lua.ORDER_NONE) || '\'\'';
if (block.getFieldValue('END') == 'FIRST') {
var functionName = Blockly.Lua.provideFunction_(
@@ -118,7 +116,7 @@ Blockly.Lua['text_indexOf'] = function(block) {
' return 0',
'end']);
}
- var code = functionName + '(' + str + ', ' + substr + ')';
+ var code = functionName + '(' + text + ', ' + substring + ')';
return [code, Blockly.Lua.ORDER_HIGH];
};
@@ -126,8 +124,9 @@ Blockly.Lua['text_charAt'] = function(block) {
// Get letter at index.
// Note: Until January 2013 this block did not have the WHERE input.
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.Lua.valueToCode(block, 'AT',
- Blockly.Lua.ORDER_UNARY) || '1';
+ var atOrder = (where == 'FROM_END') ? Blockly.Lua.ORDER_UNARY :
+ Blockly.Lua.ORDER_NONE;
+ var at = Blockly.Lua.valueToCode(block, 'AT', atOrder) || '1';
var text = Blockly.Lua.valueToCode(block, 'VALUE',
Blockly.Lua.ORDER_NONE) || '\'\'';
var code;
@@ -176,8 +175,9 @@ Blockly.Lua['text_getSubstring'] = function(block) {
// Get start index.
var where1 = block.getFieldValue('WHERE1');
- var at1 = Blockly.Lua.valueToCode(block, 'AT1',
- Blockly.Lua.ORDER_UNARY) || '1';
+ var at1Order = (where1 == 'FROM_END') ? Blockly.Lua.ORDER_UNARY :
+ Blockly.Lua.ORDER_NONE;
+ var at1 = Blockly.Lua.valueToCode(block, 'AT1', at1Order) || '1';
if (where1 == 'FIRST') {
var start = 1;
} else if (where1 == 'FROM_START') {
@@ -190,8 +190,9 @@ Blockly.Lua['text_getSubstring'] = function(block) {
// Get end index.
var where2 = block.getFieldValue('WHERE2');
- var at2 = Blockly.Lua.valueToCode(block, 'AT2',
- Blockly.Lua.ORDER_UNARY) || '1';
+ var at2Order = (where2 == 'FROM_END') ? Blockly.Lua.ORDER_UNARY :
+ Blockly.Lua.ORDER_NONE;
+ var at2 = Blockly.Lua.valueToCode(block, 'AT2', at2Order) || '1';
if (where2 == 'LAST') {
var end = -1;
} else if (where2 == 'FROM_START') {
@@ -208,7 +209,7 @@ Blockly.Lua['text_getSubstring'] = function(block) {
Blockly.Lua['text_changeCase'] = function(block) {
// Change capitalization.
var operator = block.getFieldValue('CASE');
- var argument0 = Blockly.Lua.valueToCode(block, 'TEXT',
+ var text = Blockly.Lua.valueToCode(block, 'TEXT',
Blockly.Lua.ORDER_NONE) || '\'\'';
if (operator == 'UPPERCASE') {
var functionName = 'string.upper';
@@ -238,7 +239,7 @@ Blockly.Lua['text_changeCase'] = function(block) {
' return table.concat(buf)',
'end']);
}
- var code = functionName + '(' + argument0 + ')';
+ var code = functionName + '(' + text + ')';
return [code, Blockly.Lua.ORDER_HIGH];
};
@@ -258,9 +259,9 @@ Blockly.Lua['text_trim'] = function(block) {
Blockly.Lua['text_print'] = function(block) {
// Print statement.
- var argument0 = Blockly.Lua.valueToCode(block, 'TEXT',
+ var msg = Blockly.Lua.valueToCode(block, 'TEXT',
Blockly.Lua.ORDER_NONE) || '\'\'';
- return 'print(' + argument0 + ')\n';
+ return 'print(' + msg + ')\n';
};
Blockly.Lua['text_prompt_ext'] = function(block) {
diff --git a/generators/php.js b/generators/php.js
index b836c7bc1..0543a439a 100644
--- a/generators/php.js
+++ b/generators/php.js
@@ -44,44 +44,98 @@ Blockly.PHP = new Blockly.Generator('PHP');
*/
Blockly.PHP.addReservedWords(
// http://php.net/manual/en/reserved.keywords.php
- '__halt_compiler,abstract,and,array,as,break,callable,case,catch,class,clone,const,continue,declare,default,die,do,echo,else,elseif,empty,enddeclare,endfor,endforeach,endif,endswitch,endwhile,eval,exit,extends,final,for,foreach,function,global,goto,if,implements,include,include_once,instanceof,insteadof,interface,isset,list,namespace,new,or,print,private,protected,public,require,require_once,return,static,switch,throw,trait,try,unset,use,var,while,xor,' +
+ '__halt_compiler,abstract,and,array,as,break,callable,case,catch,class,' +
+ 'clone,const,continue,declare,default,die,do,echo,else,elseif,empty,' +
+ 'enddeclare,endfor,endforeach,endif,endswitch,endwhile,eval,exit,extends,' +
+ 'final,for,foreach,function,global,goto,if,implements,include,' +
+ 'include_once,instanceof,insteadof,interface,isset,list,namespace,new,or,' +
+ 'print,private,protected,public,require,require_once,return,static,' +
+ 'switch,throw,trait,try,unset,use,var,while,xor,' +
// http://php.net/manual/en/reserved.constants.php
- 'PHP_VERSION,PHP_MAJOR_VERSION,PHP_MINOR_VERSION,PHP_RELEASE_VERSION,PHP_VERSION_ID,PHP_EXTRA_VERSION,PHP_ZTS,PHP_DEBUG,PHP_MAXPATHLEN,PHP_OS,PHP_SAPI,PHP_EOL,PHP_INT_MAX,PHP_INT_SIZE,DEFAULT_INCLUDE_PATH,PEAR_INSTALL_DIR,PEAR_EXTENSION_DIR,PHP_EXTENSION_DIR,PHP_PREFIX,PHP_BINDIR,PHP_BINARY,PHP_MANDIR,PHP_LIBDIR,PHP_DATADIR,PHP_SYSCONFDIR,PHP_LOCALSTATEDIR,PHP_CONFIG_FILE_PATH,PHP_CONFIG_FILE_SCAN_DIR,PHP_SHLIB_SUFFIX,E_ERROR,E_WARNING,E_PARSE,E_NOTICE,E_CORE_ERROR,E_CORE_WARNING,E_COMPILE_ERROR,E_COMPILE_WARNING,E_USER_ERROR,E_USER_WARNING,E_USER_NOTICE,E_DEPRECATED,E_USER_DEPRECATED,E_ALL,E_STRICT,__COMPILER_HALT_OFFSET__,TRUE,FALSE,NULL,__CLASS__,__DIR__,__FILE__,__FUNCTION__,__LINE__,__METHOD__,__NAMESPACE__,__TRAIT__');
+ 'PHP_VERSION,PHP_MAJOR_VERSION,PHP_MINOR_VERSION,PHP_RELEASE_VERSION,' +
+ 'PHP_VERSION_ID,PHP_EXTRA_VERSION,PHP_ZTS,PHP_DEBUG,PHP_MAXPATHLEN,' +
+ 'PHP_OS,PHP_SAPI,PHP_EOL,PHP_INT_MAX,PHP_INT_SIZE,DEFAULT_INCLUDE_PATH,' +
+ 'PEAR_INSTALL_DIR,PEAR_EXTENSION_DIR,PHP_EXTENSION_DIR,PHP_PREFIX,' +
+ 'PHP_BINDIR,PHP_BINARY,PHP_MANDIR,PHP_LIBDIR,PHP_DATADIR,PHP_SYSCONFDIR,' +
+ 'PHP_LOCALSTATEDIR,PHP_CONFIG_FILE_PATH,PHP_CONFIG_FILE_SCAN_DIR,' +
+ 'PHP_SHLIB_SUFFIX,E_ERROR,E_WARNING,E_PARSE,E_NOTICE,E_CORE_ERROR,' +
+ 'E_CORE_WARNING,E_COMPILE_ERROR,E_COMPILE_WARNING,E_USER_ERROR,' +
+ 'E_USER_WARNING,E_USER_NOTICE,E_DEPRECATED,E_USER_DEPRECATED,E_ALL,' +
+ 'E_STRICT,__COMPILER_HALT_OFFSET__,TRUE,FALSE,NULL,__CLASS__,__DIR__,' +
+ '__FILE__,__FUNCTION__,__LINE__,__METHOD__,__NAMESPACE__,__TRAIT__'
+);
/**
* Order of operation ENUMs.
* http://php.net/manual/en/language.operators.precedence.php
*/
-Blockly.PHP.ORDER_ATOMIC = 0; // 0 "" ...
-Blockly.PHP.ORDER_CLONE = 1; // clone
-Blockly.PHP.ORDER_NEW = 1; // new
-Blockly.PHP.ORDER_MEMBER = 2; // ()
-Blockly.PHP.ORDER_FUNCTION_CALL = 2; // ()
-Blockly.PHP.ORDER_INCREMENT = 3; // ++
-Blockly.PHP.ORDER_DECREMENT = 3; // --
-Blockly.PHP.ORDER_LOGICAL_NOT = 4; // !
-Blockly.PHP.ORDER_BITWISE_NOT = 4; // ~
-Blockly.PHP.ORDER_UNARY_PLUS = 4; // +
-Blockly.PHP.ORDER_UNARY_NEGATION = 4; // -
-Blockly.PHP.ORDER_MULTIPLICATION = 5; // *
-Blockly.PHP.ORDER_DIVISION = 5; // /
-Blockly.PHP.ORDER_MODULUS = 5; // %
-Blockly.PHP.ORDER_ADDITION = 6; // +
-Blockly.PHP.ORDER_SUBTRACTION = 6; // -
-Blockly.PHP.ORDER_BITWISE_SHIFT = 7; // << >> >>>
-Blockly.PHP.ORDER_RELATIONAL = 8; // < <= > >=
-Blockly.PHP.ORDER_IN = 8; // in
-Blockly.PHP.ORDER_INSTANCEOF = 8; // instanceof
-Blockly.PHP.ORDER_EQUALITY = 9; // == != === !==
-Blockly.PHP.ORDER_BITWISE_AND = 10; // &
-Blockly.PHP.ORDER_BITWISE_XOR = 11; // ^
-Blockly.PHP.ORDER_BITWISE_OR = 12; // |
-Blockly.PHP.ORDER_CONDITIONAL = 13; // ?:
-Blockly.PHP.ORDER_ASSIGNMENT = 14; // = += -= *= /= %= <<= >>= ...
-Blockly.PHP.ORDER_LOGICAL_AND = 15; // &&
-Blockly.PHP.ORDER_LOGICAL_OR = 16; // ||
-Blockly.PHP.ORDER_COMMA = 17; // ,
-Blockly.PHP.ORDER_NONE = 99; // (...)
+Blockly.PHP.ORDER_ATOMIC = 0; // 0 "" ...
+Blockly.PHP.ORDER_CLONE = 1; // clone
+Blockly.PHP.ORDER_NEW = 1; // new
+Blockly.PHP.ORDER_MEMBER = 2.1; // []
+Blockly.PHP.ORDER_FUNCTION_CALL = 2.2; // ()
+Blockly.PHP.ORDER_POWER = 3; // **
+Blockly.PHP.ORDER_INCREMENT = 4; // ++
+Blockly.PHP.ORDER_DECREMENT = 4; // --
+Blockly.PHP.ORDER_BITWISE_NOT = 4; // ~
+Blockly.PHP.ORDER_CAST = 4; // (int) (float) (string) (array) ...
+Blockly.PHP.ORDER_SUPPRESS_ERROR = 4; // @
+Blockly.PHP.ORDER_INSTANCEOF = 5; // instanceof
+Blockly.PHP.ORDER_LOGICAL_NOT = 6; // !
+Blockly.PHP.ORDER_UNARY_PLUS = 7.1; // +
+Blockly.PHP.ORDER_UNARY_NEGATION = 7.2; // -
+Blockly.PHP.ORDER_MULTIPLICATION = 8.1; // *
+Blockly.PHP.ORDER_DIVISION = 8.2; // /
+Blockly.PHP.ORDER_MODULUS = 8.3; // %
+Blockly.PHP.ORDER_ADDITION = 9.1; // +
+Blockly.PHP.ORDER_SUBTRACTION = 9.2; // -
+Blockly.PHP.ORDER_STRING_CONCAT = 9.3; // .
+Blockly.PHP.ORDER_BITWISE_SHIFT = 10; // << >>
+Blockly.PHP.ORDER_RELATIONAL = 11; // < <= > >=
+Blockly.PHP.ORDER_EQUALITY = 12; // == != === !== <> <=>
+Blockly.PHP.ORDER_REFERENCE = 13; // &
+Blockly.PHP.ORDER_BITWISE_AND = 13; // &
+Blockly.PHP.ORDER_BITWISE_XOR = 14; // ^
+Blockly.PHP.ORDER_BITWISE_OR = 15; // |
+Blockly.PHP.ORDER_LOGICAL_AND = 16; // &&
+Blockly.PHP.ORDER_LOGICAL_OR = 17; // ||
+Blockly.PHP.ORDER_IF_NULL = 18; // ??
+Blockly.PHP.ORDER_CONDITIONAL = 19; // ?:
+Blockly.PHP.ORDER_ASSIGNMENT = 20; // = += -= *= /= %= <<= >>= ...
+Blockly.PHP.ORDER_LOGICAL_AND_WEAK = 21; // and
+Blockly.PHP.ORDER_LOGICAL_XOR = 22; // xor
+Blockly.PHP.ORDER_LOGICAL_OR_WEAK = 23; // or
+Blockly.PHP.ORDER_COMMA = 24; // ,
+Blockly.PHP.ORDER_NONE = 99; // (...)
+
+/**
+ * List of outer-inner pairings that do NOT require parentheses.
+ * @type {!Array.>}
+ */
+Blockly.PHP.ORDER_OVERRIDES = [
+ // (foo()).bar() -> foo().bar()
+ // (foo())[0] -> foo()[0]
+ [Blockly.PHP.ORDER_MEMBER, Blockly.PHP.ORDER_FUNCTION_CALL],
+ // (foo[0])[1] -> foo[0][1]
+ // (foo.bar).baz -> foo.bar.baz
+ [Blockly.PHP.ORDER_MEMBER, Blockly.PHP.ORDER_MEMBER],
+ // !(!foo) -> !!foo
+ [Blockly.PHP.ORDER_LOGICAL_NOT, Blockly.PHP.ORDER_LOGICAL_NOT],
+ // a * (b * c) -> a * b * c
+ [Blockly.PHP.ORDER_MULTIPLICATION, Blockly.PHP.ORDER_MULTIPLICATION],
+ // a + (b + c) -> a + b + c
+ [Blockly.PHP.ORDER_ADDITION, Blockly.PHP.ORDER_ADDITION],
+ // a && (b && c) -> a && b && c
+ [Blockly.PHP.ORDER_LOGICAL_AND, Blockly.PHP.ORDER_LOGICAL_AND],
+ // a || (b || c) -> a || b || c
+ [Blockly.PHP.ORDER_LOGICAL_OR, Blockly.PHP.ORDER_LOGICAL_OR]
+];
+
+/**
+ * Allow for switching between one and zero based indexing for lists and text,
+ * one based by default.
+ */
+Blockly.PHP.ONE_BASED_INDEXING = true;
/**
* Initialise the database of variable names.
@@ -173,9 +227,9 @@ Blockly.PHP.scrub_ = function(block, code) {
}
// Collect comments for all value arguments.
// Don't collect comments for nested statements.
- for (var x = 0; x < block.inputList.length; x++) {
- if (block.inputList[x].type == Blockly.INPUT_VALUE) {
- var childBlock = block.inputList[x].connection.targetBlock();
+ for (var i = 0; i < block.inputList.length; i++) {
+ if (block.inputList[i].type == Blockly.INPUT_VALUE) {
+ var childBlock = block.inputList[i].connection.targetBlock();
if (childBlock) {
var comment = Blockly.PHP.allNestedComments(childBlock);
if (comment) {
@@ -189,3 +243,66 @@ Blockly.PHP.scrub_ = function(block, code) {
var nextCode = Blockly.PHP.blockToCode(nextBlock);
return commentCode + code + nextCode;
};
+
+/**
+ * Gets a property and adjusts the value while taking into account indexing.
+ * @param {!Blockly.Block} block The block.
+ * @param {string} atId The property ID of the element to get.
+ * @param {number=} opt_delta Value to add.
+ * @param {boolean=} opt_negate Whether to negate the value.
+ * @param {number=} opt_order The highest order acting on this value.
+ * @return {string|number}
+ */
+Blockly.PHP.getAdjusted = function(block, atId, opt_delta, opt_negate,
+ opt_order) {
+ var delta = opt_delta || 0;
+ var order = opt_order || Blockly.PHP.ORDER_NONE;
+ if (Blockly.PHP.ONE_BASED_INDEXING) {
+ delta--;
+ }
+ var defaultAtIndex = Blockly.PHP.ONE_BASED_INDEXING ? '1' : '0';
+ if (delta > 0) {
+ var at = Blockly.PHP.valueToCode(block, atId,
+ Blockly.PHP.ORDER_ADDITION) || defaultAtIndex;
+ } else if (delta < 0) {
+ var at = Blockly.PHP.valueToCode(block, atId,
+ Blockly.PHP.ORDER_SUBTRACTION) || defaultAtIndex;
+ } else if (opt_negate) {
+ var at = Blockly.PHP.valueToCode(block, atId,
+ Blockly.PHP.ORDER_UNARY_NEGATION) || defaultAtIndex;
+ } else {
+ var at = Blockly.PHP.valueToCode(block, atId, order) ||
+ defaultAtIndex;
+ }
+
+ if (Blockly.isNumber(at)) {
+ // If the index is a naked number, adjust it right now.
+ at = parseFloat(at) + delta;
+ if (opt_negate) {
+ at = -at;
+ }
+ } else {
+ // If the index is dynamic, adjust it in code.
+ if (delta > 0) {
+ at = at + ' + ' + delta;
+ var innerOrder = Blockly.PHP.ORDER_ADDITION;
+ } else if (delta < 0) {
+ at = at + ' - ' + -delta;
+ var innerOrder = Blockly.PHP.ORDER_SUBTRACTION;
+ }
+ if (opt_negate) {
+ if (delta) {
+ at = '-(' + at + ')';
+ } else {
+ at = '-' + at;
+ }
+ var innerOrder = Blockly.PHP.ORDER_UNARY_NEGATION;
+ }
+ innerOrder = Math.floor(innerOrder);
+ order = Math.floor(order);
+ if (innerOrder && order >= innerOrder) {
+ at = '(' + at + ')';
+ }
+ }
+ return at;
+};
diff --git a/generators/php/colour.js b/generators/php/colour.js
index bc1789c35..e73c17a95 100644
--- a/generators/php/colour.js
+++ b/generators/php/colour.js
@@ -39,10 +39,10 @@ Blockly.PHP['colour_random'] = function(block) {
// Generate a random colour.
var functionName = Blockly.PHP.provideFunction_(
'colour_random',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + '() {',
- ' return \'#\' . str_pad(dechex(mt_rand(0, 0xFFFFFF)), ' +
- '6, \'0\', STR_PAD_LEFT);',
- '}']);
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + '() {',
+ ' return \'#\' . str_pad(dechex(mt_rand(0, 0xFFFFFF)), ' +
+ '6, \'0\', STR_PAD_LEFT);',
+ '}']);
var code = functionName + '()';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
};
@@ -57,17 +57,17 @@ Blockly.PHP['colour_rgb'] = function(block) {
Blockly.PHP.ORDER_COMMA) || 0;
var functionName = Blockly.PHP.provideFunction_(
'colour_rgb',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
'($r, $g, $b) {',
- ' $r = round(max(min($r, 100), 0) * 2.55);',
- ' $g = round(max(min($g, 100), 0) * 2.55);',
- ' $b = round(max(min($b, 100), 0) * 2.55);',
- ' $hex = "#";',
- ' $hex .= str_pad(dechex($r), 2, "0", STR_PAD_LEFT);',
- ' $hex .= str_pad(dechex($g), 2, "0", STR_PAD_LEFT);',
- ' $hex .= str_pad(dechex($b), 2, "0", STR_PAD_LEFT);',
- ' return $hex;',
- '}']);
+ ' $r = round(max(min($r, 100), 0) * 2.55);',
+ ' $g = round(max(min($g, 100), 0) * 2.55);',
+ ' $b = round(max(min($b, 100), 0) * 2.55);',
+ ' $hex = \'#\';',
+ ' $hex .= str_pad(dechex($r), 2, \'0\', STR_PAD_LEFT);',
+ ' $hex .= str_pad(dechex($g), 2, \'0\', STR_PAD_LEFT);',
+ ' $hex .= str_pad(dechex($b), 2, \'0\', STR_PAD_LEFT);',
+ ' return $hex;',
+ '}']);
var code = functionName + '(' + red + ', ' + green + ', ' + blue + ')';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
};
@@ -82,24 +82,24 @@ Blockly.PHP['colour_blend'] = function(block) {
Blockly.PHP.ORDER_COMMA) || 0.5;
var functionName = Blockly.PHP.provideFunction_(
'colour_blend',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
'($c1, $c2, $ratio) {',
- ' $ratio = max(min($ratio, 1), 0);',
- ' $r1 = hexdec(substr($c1, 1, 2));',
- ' $g1 = hexdec(substr($c1, 3, 2));',
- ' $b1 = hexdec(substr($c1, 5, 2));',
- ' $r2 = hexdec(substr($c2, 1, 2));',
- ' $g2 = hexdec(substr($c2, 3, 2));',
- ' $b2 = hexdec(substr($c2, 5, 2));',
- ' $r = round($r1 * (1 - $ratio) + $r2 * $ratio);',
- ' $g = round($g1 * (1 - $ratio) + $g2 * $ratio);',
- ' $b = round($b1 * (1 - $ratio) + $b2 * $ratio);',
- ' $hex = "#";',
- ' $hex .= str_pad(dechex($r), 2, "0", STR_PAD_LEFT);',
- ' $hex .= str_pad(dechex($g), 2, "0", STR_PAD_LEFT);',
- ' $hex .= str_pad(dechex($b), 2, "0", STR_PAD_LEFT);',
- ' return $hex;',
- '}']);
+ ' $ratio = max(min($ratio, 1), 0);',
+ ' $r1 = hexdec(substr($c1, 1, 2));',
+ ' $g1 = hexdec(substr($c1, 3, 2));',
+ ' $b1 = hexdec(substr($c1, 5, 2));',
+ ' $r2 = hexdec(substr($c2, 1, 2));',
+ ' $g2 = hexdec(substr($c2, 3, 2));',
+ ' $b2 = hexdec(substr($c2, 5, 2));',
+ ' $r = round($r1 * (1 - $ratio) + $r2 * $ratio);',
+ ' $g = round($g1 * (1 - $ratio) + $g2 * $ratio);',
+ ' $b = round($b1 * (1 - $ratio) + $b2 * $ratio);',
+ ' $hex = \'#\';',
+ ' $hex .= str_pad(dechex($r), 2, \'0\', STR_PAD_LEFT);',
+ ' $hex .= str_pad(dechex($g), 2, \'0\', STR_PAD_LEFT);',
+ ' $hex .= str_pad(dechex($b), 2, \'0\', STR_PAD_LEFT);',
+ ' return $hex;',
+ '}']);
var code = functionName + '(' + c1 + ', ' + c2 + ', ' + ratio + ')';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
};
diff --git a/generators/php/lists.js b/generators/php/lists.js
index a406aa6d2..449c31a5e 100644
--- a/generators/php/lists.js
+++ b/generators/php/lists.js
@@ -22,6 +22,17 @@
* @fileoverview Generating PHP for list blocks.
* @author daarond@gmail.com (Daaron Dwyer)
*/
+
+/*
+ * Lists in PHP are known to break when non-variables are passed into blocks
+ * that require a list. PHP, unlike other languages, passes arrays as reference
+ * value instead of value so we are unable to support it to the extent we can
+ * for the other languages.
+ * For example, a ternary operator with two arrays will return the array by
+ * value and that cannot be passed into any of the built-in array functions for
+ * PHP (because only variables can be passed by reference).
+ * ex: end(true ? list1 : list2)
+ */
'use strict';
goog.provide('Blockly.PHP.lists');
@@ -31,37 +42,37 @@ goog.require('Blockly.PHP');
Blockly.PHP['lists_create_empty'] = function(block) {
// Create an empty list.
- return ['array()', Blockly.PHP.ORDER_ATOMIC];
+ return ['array()', Blockly.PHP.ORDER_FUNCTION_CALL];
};
Blockly.PHP['lists_create_with'] = function(block) {
// Create a list with any number of elements of any type.
var code = new Array(block.itemCount_);
- for (var n = 0; n < block.itemCount_; n++) {
- code[n] = Blockly.PHP.valueToCode(block, 'ADD' + n,
+ for (var i = 0; i < block.itemCount_; i++) {
+ code[i] = Blockly.PHP.valueToCode(block, 'ADD' + i,
Blockly.PHP.ORDER_COMMA) || 'null';
}
code = 'array(' + code.join(', ') + ')';
- return [code, Blockly.PHP.ORDER_ATOMIC];
+ return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
};
Blockly.PHP['lists_repeat'] = function(block) {
// Create a list with one element repeated.
var functionName = Blockly.PHP.provideFunction_(
'lists_repeat',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
'($value, $count) {',
- ' $array = array();',
- ' for ($index = 0; $index < $count; $index++) {',
- ' $array[] = $value;',
- ' }',
- ' return $array;',
- '}']);
- var argument0 = Blockly.PHP.valueToCode(block, 'ITEM',
+ ' $array = array();',
+ ' for ($index = 0; $index < $count; $index++) {',
+ ' $array[] = $value;',
+ ' }',
+ ' return $array;',
+ '}']);
+ var element = Blockly.PHP.valueToCode(block, 'ITEM',
Blockly.PHP.ORDER_COMMA) || 'null';
- var argument1 = Blockly.PHP.valueToCode(block, 'NUM',
+ var repeatCount = Blockly.PHP.valueToCode(block, 'NUM',
Blockly.PHP.ORDER_COMMA) || '0';
- var code = functionName + '(' + argument0 + ', ' + argument1 + ')';
+ var code = functionName + '(' + element + ', ' + repeatCount + ')';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
};
@@ -69,16 +80,16 @@ Blockly.PHP['lists_length'] = function(block) {
// String or array length.
var functionName = Blockly.PHP.provideFunction_(
'length',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + '($value) {',
- ' if (is_string($value)) {',
- ' return strlen($value);',
- ' } else {',
- ' return count($value);',
- ' }',
- '}']);
- var argument0 = Blockly.PHP.valueToCode(block, 'VALUE',
- Blockly.PHP.ORDER_FUNCTION_CALL) || '\'\'';
- return [functionName + '(' + argument0 + ')', Blockly.PHP.ORDER_FUNCTION_CALL];
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + '($value) {',
+ ' if (is_string($value)) {',
+ ' return strlen($value);',
+ ' } else {',
+ ' return count($value);',
+ ' }',
+ '}']);
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_NONE) || '\'\'';
+ return [functionName + '(' + list + ')', Blockly.PHP.ORDER_FUNCTION_CALL];
};
Blockly.PHP['lists_isEmpty'] = function(block) {
@@ -90,36 +101,42 @@ Blockly.PHP['lists_isEmpty'] = function(block) {
Blockly.PHP['lists_indexOf'] = function(block) {
// Find an item in the list.
- var operator = block.getFieldValue('END') == 'FIRST' ?
- 'indexOf' : 'lastIndexOf';
var argument0 = Blockly.PHP.valueToCode(block, 'FIND',
Blockly.PHP.ORDER_NONE) || '\'\'';
var argument1 = Blockly.PHP.valueToCode(block, 'VALUE',
Blockly.PHP.ORDER_MEMBER) || '[]';
- var functionName;
- if (block.getFieldValue('END') == 'FIRST'){
+ if (Blockly.PHP.ONE_BASED_INDEXING) {
+ var errorIndex = ' 0';
+ var indexAdjustment = ' + 1';
+ } else {
+ var errorIndex = ' -1';
+ var indexAdjustment = '';
+ }
+ if (block.getFieldValue('END') == 'FIRST') {
// indexOf
- functionName = Blockly.PHP.provideFunction_(
+ var functionName = Blockly.PHP.provideFunction_(
'indexOf',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
- '($haystack, $needle) {',
- ' for ($index = 0; $index < count($haystack); $index++) {',
- ' if ($haystack[$index] == $needle) return $index + 1;',
- ' }',
- ' return 0;',
- '}']);
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ '($haystack, $needle) {',
+ ' for ($index = 0; $index < count($haystack); $index++) {',
+ ' if ($haystack[$index] == $needle) return $index' +
+ indexAdjustment + ';',
+ ' }',
+ ' return ' + errorIndex + ';',
+ '}']);
} else {
// lastIndexOf
- functionName = Blockly.PHP.provideFunction_(
+ var functionName = Blockly.PHP.provideFunction_(
'lastIndexOf',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
- '($haystack, $needle) {',
- ' $last = 0;',
- ' for ($index = 0; $index < count($haystack); $index++) {',
- ' if ($haystack[$index] == $needle) $last = $index + 1;',
- ' }',
- ' return $last;',
- '}']);
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ '($haystack, $needle) {',
+ ' $last = ' + errorIndex + ';',
+ ' for ($index = 0; $index < count($haystack); $index++) {',
+ ' if ($haystack[$index] == $needle) $last = $index' +
+ indexAdjustment + ';',
+ ' }',
+ ' return $last;',
+ '}']);
}
var code = functionName + '(' + argument1 + ', ' + argument0 + ')';
@@ -130,97 +147,113 @@ Blockly.PHP['lists_getIndex'] = function(block) {
// Get element at index.
var mode = block.getFieldValue('MODE') || 'GET';
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.PHP.valueToCode(block, 'AT',
- Blockly.PHP.ORDER_UNARY_NEGATION) || '1';
- if (mode == 'GET') {
- var order = Blockly.PHP.ORDER_FUNCTION_CALL;
- } else {
- // List will be an argument in a function call.
- var order = Blockly.PHP.ORDER_COMMA;
- }
- var list = Blockly.PHP.valueToCode(block, 'VALUE', order) || 'array()';
-
- if (where == 'FIRST') {
- if (mode == 'GET') {
- var code = list + '[0]';
- return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
- } else if (mode == 'GET_REMOVE') {
- var code = 'array_shift(' + list + ')';
- return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
- } else if (mode == 'REMOVE') {
- return 'array_shift(' + list + ');\n';
- }
- } else if (where == 'LAST') {
- if (mode == 'GET') {
- var code = 'end(' + list + ')';
- return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
- } else if (mode == 'GET_REMOVE') {
- var code = 'array_pop(' + list + ')';
- return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
- } else if (mode == 'REMOVE') {
- return 'array_pop(' + list + ');\n';
- }
- } else if (where == 'FROM_START') {
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at)) {
- // If the index is a naked number, decrement it right now.
- at = parseFloat(at) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at += ' - 1';
- }
- if (mode == 'GET') {
- var code = list + '[' + at + ']';
- return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
- } else if (mode == 'GET_REMOVE') {
- var code = 'array_splice(' + list + ', ' + at + ', 1)[0]';
- return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
- } else if (mode == 'REMOVE') {
- return 'array_splice(' + list + ', ' + at + ', 1);\n';
- }
- } else if (where == 'FROM_END') {
- if (mode == 'GET') {
- var code = 'array_slice(' + list + ', -' + at + ', 1)[0]';
- return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
- } else if (mode == 'GET_REMOVE' || mode == 'REMOVE') {
- code = 'array_splice(' + list +
- ', count(' + list + ') - ' + at + ', 1)[0]';
- if (mode == 'GET_REMOVE') {
+ switch (where) {
+ case 'FIRST':
+ if (mode == 'GET') {
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_MEMBER) || 'array()';
+ var code = list + '[0]';
+ return [code, Blockly.PHP.ORDER_MEMBER];
+ } else if (mode == 'GET_REMOVE') {
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_NONE) || 'array()';
+ var code = 'array_shift(' + list + ')';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
} else if (mode == 'REMOVE') {
- return code + ';\n';
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_NONE) || 'array()';
+ return 'array_shift(' + list + ');\n';
}
- }
- } else if (where == 'RANDOM') {
- if (mode == 'GET'){
- var functionName = Blockly.PHP.provideFunction_(
- 'lists_get_random_item',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
- '($list) {',
- ' return $list[rand(0,count($list)-1)];',
- '}']);
- code = functionName + '(' + list + ')';
- return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
- } else if (mode == 'GET_REMOVE'){
- var functionName = Blockly.PHP.provideFunction_(
- 'lists_get_remove_random_item',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
- '(&$list) {',
- ' $x = rand(0,count($list)-1);',
- ' unset($list[$x]);',
- ' return array_values($list);',
- '}']);
- code = functionName + '(' + list + ')';
- return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
- } else if (mode == 'REMOVE') {
- var functionName = Blockly.PHP.provideFunction_(
- 'lists_remove_random_item',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
- '(&$list) {',
- ' unset($list[rand(0,count($list)-1)]);',
- '}']);
- return functionName + '(' + list + ');\n';
- }
+ break;
+ case 'LAST':
+ if (mode == 'GET') {
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_NONE) || 'array()';
+ var code = 'end(' + list + ')';
+ return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
+ } else if (mode == 'GET_REMOVE') {
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_NONE) || 'array()';
+ var code = 'array_pop(' + list + ')';
+ return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
+ } else if (mode == 'REMOVE') {
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_NONE) || 'array()';
+ return 'array_pop(' + list + ');\n';
+ }
+ break;
+ case 'FROM_START':
+ var at = Blockly.PHP.getAdjusted(block, 'AT');
+ if (mode == 'GET') {
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_MEMBER) || 'array()';
+ var code = list + '[' + at + ']';
+ return [code, Blockly.PHP.ORDER_MEMBER];
+ } else if (mode == 'GET_REMOVE') {
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_COMMA) || 'array()';
+ var code = 'array_splice(' + list + ', ' + at + ', 1)[0]';
+ return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
+ } else if (mode == 'REMOVE') {
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_COMMA) || 'array()';
+ return 'array_splice(' + list + ', ' + at + ', 1);\n';
+ }
+ break;
+ case 'FROM_END':
+ if (mode == 'GET') {
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_COMMA) || 'array()';
+ var at = Blockly.PHP.getAdjusted(block, 'AT', 1, true);
+ var code = 'array_slice(' + list + ', ' + at + ', 1)[0]';
+ return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
+ } else if (mode == 'GET_REMOVE' || mode == 'REMOVE') {
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_NONE) || 'array()';
+ var at = Blockly.PHP.getAdjusted(block, 'AT', 1, false,
+ Blockly.PHP.ORDER_SUBTRACTION);
+ code = 'array_splice(' + list +
+ ', count(' + list + ') - ' + at + ', 1)[0]';
+ if (mode == 'GET_REMOVE') {
+ return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
+ } else if (mode == 'REMOVE') {
+ return code + ';\n';
+ }
+ }
+ break;
+ case 'RANDOM':
+ var list = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_NONE) || 'array()';
+ if (mode == 'GET') {
+ var functionName = Blockly.PHP.provideFunction_(
+ 'lists_get_random_item',
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ '($list) {',
+ ' return $list[rand(0,count($list)-1)];',
+ '}']);
+ code = functionName + '(' + list + ')';
+ return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
+ } else if (mode == 'GET_REMOVE') {
+ var functionName = Blockly.PHP.provideFunction_(
+ 'lists_get_remove_random_item',
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ '(&$list) {',
+ ' $x = rand(0,count($list)-1);',
+ ' unset($list[$x]);',
+ ' return array_values($list);',
+ '}']);
+ code = functionName + '(' + list + ')';
+ return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
+ } else if (mode == 'REMOVE') {
+ var functionName = Blockly.PHP.provideFunction_(
+ 'lists_remove_random_item',
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ '(&$list) {',
+ ' unset($list[rand(0,count($list)-1)]);',
+ '}']);
+ return functionName + '(' + list + ');\n';
+ }
+ break;
}
throw 'Unhandled combination (lists_getIndex).';
};
@@ -228,18 +261,14 @@ Blockly.PHP['lists_getIndex'] = function(block) {
Blockly.PHP['lists_setIndex'] = function(block) {
// Set element at index.
// Note: Until February 2013 this block did not have MODE or WHERE inputs.
- var list = Blockly.PHP.valueToCode(block, 'LIST',
- Blockly.PHP.ORDER_MEMBER) || 'array()';
var mode = block.getFieldValue('MODE') || 'GET';
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.PHP.valueToCode(block, 'AT',
- Blockly.PHP.ORDER_NONE) || '1';
var value = Blockly.PHP.valueToCode(block, 'TO',
Blockly.PHP.ORDER_ASSIGNMENT) || 'null';
// Cache non-trivial values to variables to prevent repeated look-ups.
// Closure, which accesses and modifies 'list'.
function cacheList() {
- if (list.match(/^\w+$/)) {
+ if (list.match(/^\$\w+$/)) {
return '';
}
var listVar = Blockly.PHP.variableDB_.getDistinctName(
@@ -248,68 +277,83 @@ Blockly.PHP['lists_setIndex'] = function(block) {
list = listVar;
return code;
}
- if (where == 'FIRST') {
- if (mode == 'SET') {
- return list + '[0] = ' + value + ';\n';
- } else if (mode == 'INSERT') {
- return 'array_unshift(' + list + ', ' + value + ');\n';
- }
- } else if (where == 'LAST') {
- if (mode == 'SET') {
- var functionName = Blockly.PHP.provideFunction_(
- 'lists_set_last_item',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
- '(&$list, $value) {',
- ' $list[count($list) - 1] = $value;',
- '}']);
- return functionName + '(' + list + ', ' + value + ');\n';
- } else if (mode == 'INSERT') {
- return 'array_push(' + list + ', ' + value + ');\n';
- }
- } else if (where == 'FROM_START') {
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at)) {
- // If the index is a naked number, decrement it right now.
- at = parseFloat(at) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at += ' - 1';
- }
- if (mode == 'SET') {
- return list + '[' + at + '] = ' + value + ';\n';
- } else if (mode == 'INSERT') {
- return 'array_splice(' + list + ', ' + at + ', 0, ' + value + ');\n';
- }
- } else if (where == 'FROM_END') {
- if (mode == 'SET') {
- var functionName = Blockly.PHP.provideFunction_(
- 'lists_set_from_end',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
- '(&$list, $at, $value) {',
- ' $list[count($list) - $at] = $value;',
- '}']);
- return functionName + '(' + list + ', ' + at + ', ' + value + ');\n';
- } else if (mode == 'INSERT') {
- var functionName = Blockly.PHP.provideFunction_(
- 'lists_insert_from_end',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
- '(&$list, $at, $value) {',
- ' return array_splice($list, count($list) - $at, 0, $value);',
- '}']);
- return functionName + '(' + list + ', ' + at + ', ' + value + ');\n';
- }
- } else if (where == 'RANDOM') {
- var code = cacheList();
- var xVar = Blockly.PHP.variableDB_.getDistinctName(
- 'tmp_x', Blockly.Variables.NAME_TYPE);
- code += xVar + ' = rand(0, count(' + list + ')-1);\n';
- if (mode == 'SET') {
- code += list + '[' + xVar + '] = ' + value + ';\n';
- return code;
- } else if (mode == 'INSERT') {
- code += 'array_splice(' + list + ', ' + xVar + ', 0, ' + value + ');\n';
- return code;
- }
+ switch (where) {
+ case 'FIRST':
+ if (mode == 'SET') {
+ var list = Blockly.PHP.valueToCode(block, 'LIST',
+ Blockly.PHP.ORDER_MEMBER) || 'array()';
+ return list + '[0] = ' + value + ';\n';
+ } else if (mode == 'INSERT') {
+ var list = Blockly.PHP.valueToCode(block, 'LIST',
+ Blockly.PHP.ORDER_COMMA) || 'array()';
+ return 'array_unshift(' + list + ', ' + value + ');\n';
+ }
+ break;
+ case 'LAST':
+ var list = Blockly.PHP.valueToCode(block, 'LIST',
+ Blockly.PHP.ORDER_COMMA) || 'array()';
+ if (mode == 'SET') {
+ var functionName = Blockly.PHP.provideFunction_(
+ 'lists_set_last_item',
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ '(&$list, $value) {',
+ ' $list[count($list) - 1] = $value;',
+ '}']);
+ return functionName + '(' + list + ', ' + value + ');\n';
+ } else if (mode == 'INSERT') {
+ return 'array_push(' + list + ', ' + value + ');\n';
+ }
+ break;
+ case 'FROM_START':
+ var at = Blockly.PHP.getAdjusted(block, 'AT');
+ if (mode == 'SET') {
+ var list = Blockly.PHP.valueToCode(block, 'LIST',
+ Blockly.PHP.ORDER_MEMBER) || 'array()';
+ return list + '[' + at + '] = ' + value + ';\n';
+ } else if (mode == 'INSERT') {
+ var list = Blockly.PHP.valueToCode(block, 'LIST',
+ Blockly.PHP.ORDER_COMMA) || 'array()';
+ return 'array_splice(' + list + ', ' + at + ', 0, ' + value + ');\n';
+ }
+ break;
+ case 'FROM_END':
+ var list = Blockly.PHP.valueToCode(block, 'LIST',
+ Blockly.PHP.ORDER_COMMA) || 'array()';
+ var at = Blockly.PHP.getAdjusted(block, 'AT', 1);
+ if (mode == 'SET') {
+ var functionName = Blockly.PHP.provideFunction_(
+ 'lists_set_from_end',
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ '(&$list, $at, $value) {',
+ ' $list[count($list) - $at] = $value;',
+ '}']);
+ return functionName + '(' + list + ', ' + at + ', ' + value + ');\n';
+ } else if (mode == 'INSERT') {
+ var functionName = Blockly.PHP.provideFunction_(
+ 'lists_insert_from_end',
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ '(&$list, $at, $value) {',
+ ' return array_splice($list, count($list) - $at, 0, $value);',
+ '}']);
+ return functionName + '(' + list + ', ' + at + ', ' + value + ');\n';
+ }
+ break;
+ case 'RANDOM':
+ var list = Blockly.PHP.valueToCode(block, 'LIST',
+ Blockly.PHP.ORDER_REFERENCE) || 'array()';
+ var code = cacheList();
+ var xVar = Blockly.PHP.variableDB_.getDistinctName(
+ 'tmp_x', Blockly.Variables.NAME_TYPE);
+ code += xVar + ' = rand(0, count(' + list + ')-1);\n';
+ if (mode == 'SET') {
+ code += list + '[' + xVar + '] = ' + value + ';\n';
+ return code;
+ } else if (mode == 'INSERT') {
+ code += 'array_splice(' + list + ', ' + xVar + ', 0, ' + value +
+ ');\n';
+ return code;
+ }
+ break;
}
throw 'Unhandled combination (lists_setIndex).';
};
@@ -317,44 +361,90 @@ Blockly.PHP['lists_setIndex'] = function(block) {
Blockly.PHP['lists_getSublist'] = function(block) {
// Get sublist.
var list = Blockly.PHP.valueToCode(block, 'LIST',
- Blockly.PHP.ORDER_MEMBER) || 'array()';
+ Blockly.PHP.ORDER_COMMA) || 'array()';
var where1 = block.getFieldValue('WHERE1');
var where2 = block.getFieldValue('WHERE2');
- var at1 = Blockly.PHP.valueToCode(block, 'AT1',
- Blockly.PHP.ORDER_NONE) || '1';
- var at2 = Blockly.PHP.valueToCode(block, 'AT2',
- Blockly.PHP.ORDER_NONE) || '1';
if (where1 == 'FIRST' && where2 == 'LAST') {
var code = list;
+ } else if (list.match(/^\$\w+$/) ||
+ (where1 != 'FROM_END' && where2 == 'FROM_START')) {
+ // If the list is a simple value or doesn't require a call for length, don't
+ // generate a helper function.
+ switch (where1) {
+ case 'FROM_START':
+ var at1 = Blockly.PHP.getAdjusted(block, 'AT1');
+ break;
+ case 'FROM_END':
+ var at1 = Blockly.PHP.getAdjusted(block, 'AT1', 1, false,
+ Blockly.PHP.ORDER_SUBTRACTION);
+ at1 = 'count(' + list + ') - ' + at1;
+ break;
+ case 'FIRST':
+ var at1 = '0';
+ break;
+ default:
+ throw 'Unhandled option (lists_getSublist).';
+ }
+ switch (where2) {
+ case 'FROM_START':
+ var at2 = Blockly.PHP.getAdjusted(block, 'AT2', 0, false,
+ Blockly.PHP.ORDER_SUBTRACTION);
+ var length = at2 + ' - ';
+ if (Blockly.isNumber(String(at1)) || String(at1).match(/^\(.+\)$/)) {
+ length += at1;
+ } else {
+ length += '(' + at1 + ')';
+ }
+ length += ' + 1';
+ break;
+ case 'FROM_END':
+ var at2 = Blockly.PHP.getAdjusted(block, 'AT2', 0, false,
+ Blockly.PHP.ORDER_SUBTRACTION);
+ var length = 'count(' + list + ') - ' + at2 + ' - ';
+ if (Blockly.isNumber(String(at1)) || String(at1).match(/^\(.+\)$/)) {
+ length += at1;
+ } else {
+ length += '(' + at1 + ')';
+ }
+ break;
+ case 'LAST':
+ var length = 'count(' + list + ') - ';
+ if (Blockly.isNumber(String(at1)) || String(at1).match(/^\(.+\)$/)) {
+ length += at1;
+ } else {
+ length += '(' + at1 + ')';
+ }
+ break;
+ default:
+ throw 'Unhandled option (lists_getSublist).';
+ }
+ code = 'array_slice(' + list + ', ' + at1 + ', ' + length + ')';
} else {
+ var at1 = Blockly.PHP.getAdjusted(block, 'AT1');
+ var at2 = Blockly.PHP.getAdjusted(block, 'AT2');
var functionName = Blockly.PHP.provideFunction_(
'lists_get_sublist',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
'($list, $where1, $at1, $where2, $at2) {',
- ' if ($where2 == \'FROM_START\') {',
- ' $at2--;',
- ' } else if ($where2 == \'FROM_END\') {',
- ' $at2 = $at2 - $at1;',
- ' } else if ($where2 == \'FIRST\') {',
- ' $at2 = 0;',
- ' } else if ($where2 == \'LAST\') {',
- ' $at2 = count($list);',
- ' } else {',
- ' throw \'Unhandled option (lists_getSublist).\';',
- ' }',
- ' if ($where1 == \'FROM_START\') {',
- ' $at1--;',
- ' } else if ($where1 == \'FROM_END\') {',
- ' $at1 = count($list) - $at1;',
- ' } else if ($where1 == \'FIRST\') {',
- ' $at1 = 0;',
- ' } else if ($where1 == \'LAST\') {',
- ' $at1 = count($list) - 1;',
- ' } else {',
- ' throw \'Unhandled option (lists_getSublist).\';',
- ' }',
- ' return array_slice($list, $at1, $at2);',
- '}']);
+ ' if ($where1 == \'FROM_END\') {',
+ ' $at1 = count($list) - 1 - $at1;',
+ ' } else if ($where1 == \'FIRST\') {',
+ ' $at1 = 0;',
+ ' } else if ($where1 != \'FROM_START\'){',
+ ' throw new Exception(\'Unhandled option (lists_get_sublist).\');',
+ ' }',
+ ' $length = 0;',
+ ' if ($where2 == \'FROM_START\') {',
+ ' $length = $at2 - $at1 + 1;',
+ ' } else if ($where2 == \'FROM_END\') {',
+ ' $length = count($list) - $at1 - $at2;',
+ ' } else if ($where2 == \'LAST\') {',
+ ' $length = count($list) - $at1;',
+ ' } else {',
+ ' throw new Exception(\'Unhandled option (lists_get_sublist).\');',
+ ' }',
+ ' return array_slice($list, $at1, $length);',
+ '}']);
var code = functionName + '(' + list + ', \'' +
where1 + '\', ' + at1 + ', \'' + where2 + '\', ' + at2 + ')';
}
@@ -364,26 +454,26 @@ Blockly.PHP['lists_getSublist'] = function(block) {
Blockly.PHP['lists_sort'] = function(block) {
// Block for sorting a list.
var listCode = Blockly.PHP.valueToCode(block, 'LIST',
- Blockly.PHP.ORDER_FUNCTION_CALL) || 'array()';
+ Blockly.PHP.ORDER_COMMA) || 'array()';
var direction = block.getFieldValue('DIRECTION') === '1' ? 1 : -1;
var type = block.getFieldValue('TYPE');
var functionName = Blockly.PHP.provideFunction_(
- 'lists_sort', [
- 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
- '($list, $type, $direction) {',
- ' $sortCmpFuncs = array(',
- ' "NUMERIC" => "strnatcasecmp",',
- ' "TEXT" => "strcmp",',
- ' "IGNORE_CASE" => "strcasecmp"',
- ' );',
- ' $sortCmp = $sortCmpFuncs[$type];',
- ' $list2 = $list;', // Clone list.
- ' usort($list2, $sortCmp);',
- ' if ($direction == -1) {',
- ' $list2 = array_reverse($list2);',
- ' }',
- ' return $list2;',
- '}']);
+ 'lists_sort',
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ '($list, $type, $direction) {',
+ ' $sortCmpFuncs = array(',
+ ' "NUMERIC" => "strnatcasecmp",',
+ ' "TEXT" => "strcmp",',
+ ' "IGNORE_CASE" => "strcasecmp"',
+ ' );',
+ ' $sortCmp = $sortCmpFuncs[$type];',
+ ' $list2 = $list;', // Clone list.
+ ' usort($list2, $sortCmp);',
+ ' if ($direction == -1) {',
+ ' $list2 = array_reverse($list2);',
+ ' }',
+ ' return $list2;',
+ '}']);
var sortCode = functionName +
'(' + listCode + ', "' + type + '", ' + direction + ')';
return [sortCode, Blockly.PHP.ORDER_FUNCTION_CALL];
@@ -392,9 +482,9 @@ Blockly.PHP['lists_sort'] = function(block) {
Blockly.PHP['lists_split'] = function(block) {
// Block for splitting text into a list, or joining a list into text.
var value_input = Blockly.PHP.valueToCode(block, 'INPUT',
- Blockly.PHP.ORDER_MEMBER);
+ Blockly.PHP.ORDER_COMMA);
var value_delim = Blockly.PHP.valueToCode(block, 'DELIM',
- Blockly.PHP.ORDER_NONE) || '\'\'';
+ Blockly.PHP.ORDER_COMMA) || '\'\'';
var mode = block.getFieldValue('MODE');
if (mode == 'SPLIT') {
if (!value_input) {
diff --git a/generators/php/math.js b/generators/php/math.js
index f0bb9fa79..7789ba8fe 100644
--- a/generators/php/math.js
+++ b/generators/php/math.js
@@ -47,20 +47,14 @@ Blockly.PHP['math_arithmetic'] = function(block) {
'MINUS': [' - ', Blockly.PHP.ORDER_SUBTRACTION],
'MULTIPLY': [' * ', Blockly.PHP.ORDER_MULTIPLICATION],
'DIVIDE': [' / ', Blockly.PHP.ORDER_DIVISION],
- 'POWER': [null, Blockly.PHP.ORDER_COMMA] // Handle power separately.
+ 'POWER': [' ** ', Blockly.PHP.ORDER_POWER]
};
var tuple = OPERATORS[block.getFieldValue('OP')];
var operator = tuple[0];
var order = tuple[1];
var argument0 = Blockly.PHP.valueToCode(block, 'A', order) || '0';
var argument1 = Blockly.PHP.valueToCode(block, 'B', order) || '0';
- var code;
- // Power in PHP requires a special case since it has no operator.
- if (!operator) {
- code = 'pow(' + argument0 + ', ' + argument1 + ')';
- return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
- }
- code = argument0 + operator + argument1;
+ var code = argument0 + operator + argument1;
return [code, order];
};
@@ -172,25 +166,25 @@ Blockly.PHP['math_number_property'] = function(block) {
// Prime is a special case as it is not a one-liner test.
var functionName = Blockly.PHP.provideFunction_(
'math_isPrime',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + '($n) {',
- ' // https://en.wikipedia.org/wiki/Primality_test#Naive_methods',
- ' if ($n == 2 || $n == 3) {',
- ' return true;',
- ' }',
- ' // False if n is NaN, negative, is 1, or not whole.',
- ' // And false if n is divisible by 2 or 3.',
- ' if (!is_numeric($n) || $n <= 1 || $n % 1 != 0 || $n % 2 == 0 ||' +
- ' $n % 3 == 0) {',
- ' return false;',
- ' }',
- ' // Check all the numbers of form 6k +/- 1, up to sqrt(n).',
- ' for ($x = 6; $x <= sqrt($n) + 1; $x += 6) {',
- ' if ($n % ($x - 1) == 0 || $n % ($x + 1) == 0) {',
- ' return false;',
- ' }',
- ' }',
- ' return true;',
- '}']);
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + '($n) {',
+ ' // https://en.wikipedia.org/wiki/Primality_test#Naive_methods',
+ ' if ($n == 2 || $n == 3) {',
+ ' return true;',
+ ' }',
+ ' // False if n is NaN, negative, is 1, or not whole.',
+ ' // And false if n is divisible by 2 or 3.',
+ ' if (!is_numeric($n) || $n <= 1 || $n % 1 != 0 || $n % 2 == 0 ||' +
+ ' $n % 3 == 0) {',
+ ' return false;',
+ ' }',
+ ' // Check all the numbers of form 6k +/- 1, up to sqrt(n).',
+ ' for ($x = 6; $x <= sqrt($n) + 1; $x += 6) {',
+ ' if ($n % ($x - 1) == 0 || $n % ($x + 1) == 0) {',
+ ' return false;',
+ ' }',
+ ' }',
+ ' return true;',
+ '}']);
code = functionName + '(' + number_to_check + ')';
return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
}
@@ -256,10 +250,10 @@ Blockly.PHP['math_on_list'] = function(block) {
case 'AVERAGE':
var functionName = Blockly.PHP.provideFunction_(
'math_mean',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
'($myList) {',
- ' return array_sum($myList) / count($myList);',
- '}']);
+ ' return array_sum($myList) / count($myList);',
+ '}']);
list = Blockly.PHP.valueToCode(block, 'LIST',
Blockly.PHP.ORDER_NONE) || 'array()';
code = functionName + '(' + list + ')';
@@ -267,12 +261,13 @@ Blockly.PHP['math_on_list'] = function(block) {
case 'MEDIAN':
var functionName = Blockly.PHP.provideFunction_(
'math_median',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
'($arr) {',
- ' sort($arr,SORT_NUMERIC);',
- ' return (count($arr) % 2) ? $arr[floor(count($arr)/2)] : ',
- ' ($arr[floor(count($arr)/2)] + $arr[floor(count($arr)/2) - 1]) / 2;',
- '}']);
+ ' sort($arr,SORT_NUMERIC);',
+ ' return (count($arr) % 2) ? $arr[floor(count($arr)/2)] : ',
+ ' ($arr[floor(count($arr)/2)] + $arr[floor(count($arr)/2)' +
+ ' - 1]) / 2;',
+ '}']);
list = Blockly.PHP.valueToCode(block, 'LIST',
Blockly.PHP.ORDER_NONE) || '[]';
code = functionName + '(' + list + ')';
@@ -283,13 +278,14 @@ Blockly.PHP['math_on_list'] = function(block) {
// Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1].
var functionName = Blockly.PHP.provideFunction_(
'math_modes',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
'($values) {',
- ' $v = array_count_values($values);',
- ' arsort($v);',
- ' foreach($v as $k => $v){$total = $k; break;}',
- ' return array($total);',
- '}']);
+ ' if (empty($values)) return array();',
+ ' $counts = array_count_values($values);',
+ ' arsort($counts); // Sort counts in descending order',
+ ' $modes = array_keys($counts, current($counts), true);',
+ ' return $modes;',
+ '}']);
list = Blockly.PHP.valueToCode(block, 'LIST',
Blockly.PHP.ORDER_NONE) || '[]';
code = functionName + '(' + list + ')';
@@ -297,14 +293,15 @@ Blockly.PHP['math_on_list'] = function(block) {
case 'STD_DEV':
var functionName = Blockly.PHP.provideFunction_(
'math_standard_deviation',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
- '($numbers) {',
- ' $n = count($numbers);',
- ' if (!$n) return null;',
- ' $mean = array_sum($numbers) / count($numbers);',
- ' foreach($numbers as $key => $num) $devs[$key] = pow($num - $mean, 2);',
- ' return sqrt(array_sum($devs) / (count($devs) - 1));',
- '}']);
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ '($numbers) {',
+ ' $n = count($numbers);',
+ ' if (!$n) return null;',
+ ' $mean = array_sum($numbers) / count($numbers);',
+ ' foreach($numbers as $key => $num) $devs[$key] = ' +
+ 'pow($num - $mean, 2);',
+ ' return sqrt(array_sum($devs) / (count($devs) - 1));',
+ '}']);
list = Blockly.PHP.valueToCode(block, 'LIST',
Blockly.PHP.ORDER_NONE) || '[]';
code = functionName + '(' + list + ')';
@@ -312,11 +309,11 @@ Blockly.PHP['math_on_list'] = function(block) {
case 'RANDOM':
var functionName = Blockly.PHP.provideFunction_(
'math_random_list',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
'($list) {',
- ' $x = rand(0, count($list)-1);',
- ' return $list[$x];',
- '}']);
+ ' $x = rand(0, count($list)-1);',
+ ' return $list[$x];',
+ '}']);
list = Blockly.PHP.valueToCode(block, 'LIST',
Blockly.PHP.ORDER_NONE) || '[]';
code = functionName + '(' + list + ')';
@@ -358,13 +355,13 @@ Blockly.PHP['math_random_int'] = function(block) {
Blockly.PHP.ORDER_COMMA) || '0';
var functionName = Blockly.PHP.provideFunction_(
'math_random_int',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
'($a, $b) {',
- ' if ($a > $b) {',
- ' return rand($b, $a);',
- ' }',
- ' return rand($a, $b);',
- '}']);
+ ' if ($a > $b) {',
+ ' return rand($b, $a);',
+ ' }',
+ ' return rand($a, $b);',
+ '}']);
var code = functionName + '(' + argument0 + ', ' + argument1 + ')';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
};
diff --git a/generators/php/procedures.js b/generators/php/procedures.js
index 1fd4cc872..0dc56d7cb 100644
--- a/generators/php/procedures.js
+++ b/generators/php/procedures.js
@@ -63,8 +63,8 @@ Blockly.PHP['procedures_defreturn'] = function(block) {
returnValue = ' return ' + returnValue + ';\n';
}
var args = [];
- for (var x = 0; x < block.arguments_.length; x++) {
- args[x] = Blockly.PHP.variableDB_.getName(block.arguments_[x],
+ for (var i = 0; i < block.arguments_.length; i++) {
+ args[i] = Blockly.PHP.variableDB_.getName(block.arguments_[i],
Blockly.Variables.NAME_TYPE);
}
var code = 'function ' + funcName + '(' + args.join(', ') + ') {\n' +
@@ -85,8 +85,8 @@ Blockly.PHP['procedures_callreturn'] = function(block) {
var funcName = Blockly.PHP.variableDB_.getName(
block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE);
var args = [];
- for (var x = 0; x < block.arguments_.length; x++) {
- args[x] = Blockly.PHP.valueToCode(block, 'ARG' + x,
+ for (var i = 0; i < block.arguments_.length; i++) {
+ args[i] = Blockly.PHP.valueToCode(block, 'ARG' + i,
Blockly.PHP.ORDER_COMMA) || 'null';
}
var code = funcName + '(' + args.join(', ') + ')';
@@ -98,8 +98,8 @@ Blockly.PHP['procedures_callnoreturn'] = function(block) {
var funcName = Blockly.PHP.variableDB_.getName(
block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE);
var args = [];
- for (var x = 0; x < block.arguments_.length; x++) {
- args[x] = Blockly.PHP.valueToCode(block, 'ARG' + x,
+ for (var i = 0; i < block.arguments_.length; i++) {
+ args[i] = Blockly.PHP.valueToCode(block, 'ARG' + i,
Blockly.PHP.ORDER_COMMA) || 'null';
}
var code = funcName + '(' + args.join(', ') + ');\n';
diff --git a/generators/php/text.js b/generators/php/text.js
index 3960ab011..efc0f2de3 100644
--- a/generators/php/text.js
+++ b/generators/php/text.js
@@ -37,28 +37,27 @@ Blockly.PHP['text'] = function(block) {
Blockly.PHP['text_join'] = function(block) {
// Create a string made up of any number of elements of any type.
- var code;
if (block.itemCount_ == 0) {
return ['\'\'', Blockly.PHP.ORDER_ATOMIC];
} else if (block.itemCount_ == 1) {
- var argument0 = Blockly.PHP.valueToCode(block, 'ADD0',
+ var element = Blockly.PHP.valueToCode(block, 'ADD0',
Blockly.PHP.ORDER_NONE) || '\'\'';
- code = argument0;
+ var code = element;
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
} else if (block.itemCount_ == 2) {
- var argument0 = Blockly.PHP.valueToCode(block, 'ADD0',
+ var element0 = Blockly.PHP.valueToCode(block, 'ADD0',
Blockly.PHP.ORDER_NONE) || '\'\'';
- var argument1 = Blockly.PHP.valueToCode(block, 'ADD1',
+ var element1 = Blockly.PHP.valueToCode(block, 'ADD1',
Blockly.PHP.ORDER_NONE) || '\'\'';
- code = argument0 + ' . ' + argument1;
+ var code = element0 + ' . ' + element1;
return [code, Blockly.PHP.ORDER_ADDITION];
} else {
- code = new Array(block.itemCount_);
- for (var n = 0; n < block.itemCount_; n++) {
- code[n] = Blockly.PHP.valueToCode(block, 'ADD' + n,
+ var elements = new Array(block.itemCount_);
+ for (var i = 0; i < block.itemCount_; i++) {
+ elements[i] = Blockly.PHP.valueToCode(block, 'ADD' + i,
Blockly.PHP.ORDER_COMMA) || '\'\'';
}
- code = 'implode(\'\', array(' + code.join(',') + '))';
+ var code = 'implode(\'\', array(' + elements.join(',') + '))';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
}
};
@@ -67,89 +66,89 @@ Blockly.PHP['text_append'] = function(block) {
// Append to a variable in place.
var varName = Blockly.PHP.variableDB_.getName(
block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
- var argument0 = Blockly.PHP.valueToCode(block, 'TEXT',
- Blockly.PHP.ORDER_NONE) || '\'\'';
- return varName + ' .= ' + argument0 + ';\n';
+ var value = Blockly.PHP.valueToCode(block, 'TEXT',
+ Blockly.PHP.ORDER_ASSIGNMENT) || '\'\'';
+ return varName + ' .= ' + value + ';\n';
};
Blockly.PHP['text_length'] = function(block) {
// String or array length.
var functionName = Blockly.PHP.provideFunction_(
'length',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + '($value) {',
- ' if (is_string($value)) {',
- ' return strlen($value);',
- ' } else {',
- ' return count($value);',
- ' }',
- '}']);
- var argument0 = Blockly.PHP.valueToCode(block, 'VALUE',
- Blockly.PHP.ORDER_FUNCTION_CALL) || '\'\'';
- return [functionName + '(' + argument0 + ')', Blockly.PHP.ORDER_FUNCTION_CALL];
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + '($value) {',
+ ' if (is_string($value)) {',
+ ' return strlen($value);',
+ ' } else {',
+ ' return count($value);',
+ ' }',
+ '}']);
+ var text = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_NONE) || '\'\'';
+ return [functionName + '(' + text + ')', Blockly.PHP.ORDER_FUNCTION_CALL];
};
Blockly.PHP['text_isEmpty'] = function(block) {
// Is the string null or array empty?
- var argument0 = Blockly.PHP.valueToCode(block, 'VALUE',
- Blockly.PHP.ORDER_FUNCTION_CALL) || '\'\'';
- return ['empty(' + argument0 + ')', Blockly.PHP.ORDER_FUNCTION_CALL];
+ var text = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_NONE) || '\'\'';
+ return ['empty(' + text + ')', Blockly.PHP.ORDER_FUNCTION_CALL];
};
Blockly.PHP['text_indexOf'] = function(block) {
// Search the text for a substring.
var operator = block.getFieldValue('END') == 'FIRST' ?
'strpos' : 'strrpos';
- var argument0 = Blockly.PHP.valueToCode(block, 'FIND',
- Blockly.PHP.ORDER_FUNCTION_CALL) || '\'\'';
- var argument1 = Blockly.PHP.valueToCode(block, 'VALUE',
- Blockly.PHP.ORDER_FUNCTION_CALL) || '\'\'';
-
+ var substring = Blockly.PHP.valueToCode(block, 'FIND',
+ Blockly.PHP.ORDER_NONE) || '\'\'';
+ var text = Blockly.PHP.valueToCode(block, 'VALUE',
+ Blockly.PHP.ORDER_NONE) || '\'\'';
+ if (Blockly.PHP.ONE_BASED_INDEXING) {
+ var errorIndex = ' 0';
+ var indexAdjustment = ' + 1';
+ } else {
+ var errorIndex = ' -1';
+ var indexAdjustment = '';
+ }
var functionName = Blockly.PHP.provideFunction_(
block.getFieldValue('END') == 'FIRST' ?
'text_indexOf' : 'text_lastIndexOf',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
'($text, $search) {',
- ' $pos = ' + operator + '($text, $search);',
- ' return $pos === false ? 0 : $pos + 1;',
- '}']);
- var code = functionName + '(' + argument1 + ', ' + argument0 + ')';
+ ' $pos = ' + operator + '($text, $search);',
+ ' return $pos === false ? ' + errorIndex + ' : $pos' +
+ indexAdjustment + ';',
+ '}']);
+ var code = functionName + '(' + text + ', ' + substring + ')';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
};
Blockly.PHP['text_charAt'] = function(block) {
// Get letter at index.
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.PHP.valueToCode(block, 'AT',
- Blockly.PHP.ORDER_FUNCTION_CALL) || '0';
- var text = Blockly.PHP.valueToCode(block, 'VALUE',
- Blockly.PHP.ORDER_FUNCTION_CALL) || '\'\'';
+ var textOrder = (where == 'RANDOM') ? Blockly.PHP.ORDER_NONE :
+ Blockly.PHP.ORDER_COMMA;
+ var text = Blockly.PHP.valueToCode(block, 'VALUE', textOrder) || '\'\'';
switch (where) {
case 'FIRST':
- var code = text + '[0]';
+ var code = 'substr(' + text + ', 0, 1)';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
case 'LAST':
- var code = 'substr(' + text + ', -1, 1)';
+ var code = 'substr(' + text + ', -1)';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
case 'FROM_START':
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at)) {
- // If the index is a naked number, decrement it right now.
- at = parseFloat(at) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at += ' - 1';
- }
+ var at = Blockly.PHP.getAdjusted(block, 'AT');
var code = 'substr(' + text + ', ' + at + ', 1)';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
case 'FROM_END':
- var code = 'substr(' + text + ', -' + at + ', 1)';
+ var at = Blockly.PHP.getAdjusted(block, 'AT', 1, true);
+ var code = 'substr(' + text + ', ' + at + ', 1)';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
case 'RANDOM':
var functionName = Blockly.PHP.provideFunction_(
'text_random_letter',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + '($text) {',
- ' return $text[rand(0, strlen($text) - 1)];',
- '}']);
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + '($text) {',
+ ' return $text[rand(0, strlen($text) - 1)];',
+ '}']);
code = functionName + '(' + text + ')';
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
}
@@ -162,37 +161,34 @@ Blockly.PHP['text_getSubstring'] = function(block) {
Blockly.PHP.ORDER_FUNCTION_CALL) || '\'\'';
var where1 = block.getFieldValue('WHERE1');
var where2 = block.getFieldValue('WHERE2');
- var at1 = Blockly.PHP.valueToCode(block, 'AT1',
- Blockly.PHP.ORDER_FUNCTION_CALL) || '0';
- var at2 = Blockly.PHP.valueToCode(block, 'AT2',
- Blockly.PHP.ORDER_FUNCTION_CALL) || '0';
if (where1 == 'FIRST' && where2 == 'LAST') {
var code = text;
} else {
+ var at1 = Blockly.PHP.getAdjusted(block, 'AT1');
+ var at2 = Blockly.PHP.getAdjusted(block, 'AT2');
var functionName = Blockly.PHP.provideFunction_(
'text_get_substring',
- [ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
'($text, $where1, $at1, $where2, $at2) {',
- ' if ($where2 == \'FROM_START\') {',
- ' $at2--;',
- ' } else if ($where2 == \'FROM_END\') {',
- ' $at2 = $at2 - $at1;',
- ' } else if ($where2 == \'FIRST\') {',
- ' $at2 = 0;',
- ' } else if ($where2 == \'LAST\') {',
- ' $at2 = strlen($text);',
- ' } else { $at2 = 0; }',
- ' if ($where1 == \'FROM_START\') {',
- ' $at1--;',
- ' } else if ($where1 == \'FROM_END\') {',
- ' $at1 = strlen($text) - $at1;',
- ' } else if ($where1 == \'FIRST\') {',
- ' $at1 = 0;',
- ' } else if ($where1 == \'LAST\') {',
- ' $at1 = strlen($text) - 1;',
- ' } else { $at1 = 0; }',
- ' return substr($text, $at1, $at2);',
- '}']);
+ ' if ($where1 == \'FROM_END\') {',
+ ' $at1 = strlen($text) - 1 - $at1;',
+ ' } else if ($where1 == \'FIRST\') {',
+ ' $at1 = 0;',
+ ' } else if ($where1 != \'FROM_START\'){',
+ ' throw new Exception(\'Unhandled option (text_get_substring).\');',
+ ' }',
+ ' $length = 0;',
+ ' if ($where2 == \'FROM_START\') {',
+ ' $length = $at2 - $at1 + 1;',
+ ' } else if ($where2 == \'FROM_END\') {',
+ ' $length = strlen($text) - $at1 - $at2;',
+ ' } else if ($where2 == \'LAST\') {',
+ ' $length = strlen($text) - $at1;',
+ ' } else {',
+ ' throw new Exception(\'Unhandled option (text_get_substring).\');',
+ ' }',
+ ' return substr($text, $at1, $length);',
+ '}']);
var code = functionName + '(' + text + ', \'' +
where1 + '\', ' + at1 + ', \'' + where2 + '\', ' + at2 + ')';
}
@@ -201,19 +197,14 @@ Blockly.PHP['text_getSubstring'] = function(block) {
Blockly.PHP['text_changeCase'] = function(block) {
// Change capitalization.
- var code;
+ var text = Blockly.PHP.valueToCode(block, 'TEXT',
+ Blockly.PHP.ORDER_NONE) || '\'\'';
if (block.getFieldValue('CASE') == 'UPPERCASE') {
- var argument0 = Blockly.PHP.valueToCode(block, 'TEXT',
- Blockly.PHP.ORDER_FUNCTION_CALL) || '\'\'';
- code = 'strtoupper(' + argument0 + ')';
+ var code = 'strtoupper(' + text + ')';
} else if (block.getFieldValue('CASE') == 'LOWERCASE') {
- var argument0 = Blockly.PHP.valueToCode(block, 'TEXT',
- Blockly.PHP.ORDER_FUNCTION_CALL) || '\'\'';
- code = 'strtolower(' + argument0 + ')';
+ var code = 'strtolower(' + text + ')';
} else if (block.getFieldValue('CASE') == 'TITLECASE') {
- var argument0 = Blockly.PHP.valueToCode(block, 'TEXT',
- Blockly.PHP.ORDER_FUNCTION_CALL) || '\'\'';
- code = 'ucwords(strtolower(' + argument0 + '))';
+ var code = 'ucwords(strtolower(' + text + '))';
}
return [code, Blockly.PHP.ORDER_FUNCTION_CALL];
};
@@ -226,16 +217,16 @@ Blockly.PHP['text_trim'] = function(block) {
'BOTH': 'trim'
};
var operator = OPERATORS[block.getFieldValue('MODE')];
- var argument0 = Blockly.PHP.valueToCode(block, 'TEXT',
+ var text = Blockly.PHP.valueToCode(block, 'TEXT',
Blockly.PHP.ORDER_NONE) || '\'\'';
- return [ operator + '(' + argument0 + ')', Blockly.PHP.ORDER_FUNCTION_CALL];
+ return [operator + '(' + text + ')', Blockly.PHP.ORDER_FUNCTION_CALL];
};
Blockly.PHP['text_print'] = function(block) {
// Print statement.
- var argument0 = Blockly.PHP.valueToCode(block, 'TEXT',
+ var msg = Blockly.PHP.valueToCode(block, 'TEXT',
Blockly.PHP.ORDER_NONE) || '\'\'';
- return 'print(' + argument0 + ');\n';
+ return 'print(' + msg + ');\n';
};
Blockly.PHP['text_prompt_ext'] = function(block) {
diff --git a/generators/php/variables.js b/generators/php/variables.js
index dd68f4ead..466774b3f 100644
--- a/generators/php/variables.js
+++ b/generators/php/variables.js
@@ -43,4 +43,4 @@ Blockly.PHP['variables_set'] = function(block) {
var varName = Blockly.PHP.variableDB_.getName(
block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
return varName + ' = ' + argument0 + ';\n';
-};
\ No newline at end of file
+};
diff --git a/generators/python.js b/generators/python.js
index 082480685..3534aec27 100644
--- a/generators/python.js
+++ b/generators/python.js
@@ -46,11 +46,22 @@ Blockly.Python.addReservedWords(
// import keyword
// print ','.join(keyword.kwlist)
// http://docs.python.org/reference/lexical_analysis.html#keywords
- 'and,as,assert,break,class,continue,def,del,elif,else,except,exec,finally,for,from,global,if,import,in,is,lambda,not,or,pass,print,raise,return,try,while,with,yield,' +
+ 'and,as,assert,break,class,continue,def,del,elif,else,except,exec,' +
+ 'finally,for,from,global,if,import,in,is,lambda,not,or,pass,print,raise,' +
+ 'return,try,while,with,yield,' +
//http://docs.python.org/library/constants.html
- 'True,False,None,NotImplemented,Ellipsis,__debug__,quit,exit,copyright,license,credits,' +
+ 'True,False,None,NotImplemented,Ellipsis,__debug__,quit,exit,copyright,' +
+ 'license,credits,' +
// http://docs.python.org/library/functions.html
- 'abs,divmod,input,open,staticmethod,all,enumerate,int,ord,str,any,eval,isinstance,pow,sum,basestring,execfile,issubclass,print,super,bin,file,iter,property,tuple,bool,filter,len,range,type,bytearray,float,list,raw_input,unichr,callable,format,locals,reduce,unicode,chr,frozenset,long,reload,vars,classmethod,getattr,map,repr,xrange,cmp,globals,max,reversed,zip,compile,hasattr,memoryview,round,__import__,complex,hash,min,set,apply,delattr,help,next,setattr,buffer,dict,hex,object,slice,coerce,dir,id,oct,sorted,intern');
+ 'abs,divmod,input,open,staticmethod,all,enumerate,int,ord,str,any,eval,' +
+ 'isinstance,pow,sum,basestring,execfile,issubclass,print,super,bin,file,' +
+ 'iter,property,tuple,bool,filter,len,range,type,bytearray,float,list,' +
+ 'raw_input,unichr,callable,format,locals,reduce,unicode,chr,frozenset,' +
+ 'long,reload,vars,classmethod,getattr,map,repr,xrange,cmp,globals,max,' +
+ 'reversed,zip,compile,hasattr,memoryview,round,__import__,complex,hash,' +
+ 'min,set,apply,delattr,help,next,setattr,buffer,dict,hex,object,slice,' +
+ 'coerce,dir,id,oct,sorted,intern'
+);
/**
* Order of operation ENUMs.
@@ -79,6 +90,12 @@ Blockly.Python.ORDER_CONDITIONAL = 15; // if else
Blockly.Python.ORDER_LAMBDA = 16; // lambda
Blockly.Python.ORDER_NONE = 99; // (...)
+/**
+ * Allow for switching between one and zero based indexing for lists and text,
+ * one based by default.
+ */
+Blockly.Python.ONE_BASED_INDEXING = true;
+
/**
* List of outer-inner pairings that do NOT require parentheses.
* @type {!Array.>}
@@ -213,9 +230,9 @@ Blockly.Python.scrub_ = function(block, code) {
}
// Collect comments for all value arguments.
// Don't collect comments for nested statements.
- for (var x = 0; x < block.inputList.length; x++) {
- if (block.inputList[x].type == Blockly.INPUT_VALUE) {
- var childBlock = block.inputList[x].connection.targetBlock();
+ for (var i = 0; i < block.inputList.length; i++) {
+ if (block.inputList[i].type == Blockly.INPUT_VALUE) {
+ var childBlock = block.inputList[i].connection.targetBlock();
if (childBlock) {
var comment = Blockly.Python.allNestedComments(childBlock);
if (comment) {
@@ -229,3 +246,45 @@ Blockly.Python.scrub_ = function(block, code) {
var nextCode = Blockly.Python.blockToCode(nextBlock);
return commentCode + code + nextCode;
};
+
+/**
+ * Gets a property and adjusts the value, taking into account indexing, and
+ * casts to an integer.
+ * @param {!Blockly.Block} block The block.
+ * @param {string} atId The property ID of the element to get.
+ * @param {number=} opt_delta Value to add.
+ * @param {boolean=} opt_negate Whether to negate the value.
+ * @return {string|number}
+ */
+Blockly.Python.getAdjustedInt = function(block, atId, opt_delta, opt_negate) {
+ var delta = opt_delta || 0;
+ if (Blockly.Python.ONE_BASED_INDEXING) {
+ delta--;
+ }
+ var defaultAtIndex = Blockly.Python.ONE_BASED_INDEXING ? '1' : '0';
+ var atOrder = delta ? Blockly.Python.ORDER_ADDITIVE :
+ Blockly.Python.ORDER_NONE;
+ var at = Blockly.Python.valueToCode(block, atId, atOrder) || defaultAtIndex;
+
+ if (Blockly.isNumber(at)) {
+ // If the index is a naked number, adjust it right now.
+ at = parseInt(at, 10) + delta;
+ if (opt_negate) {
+ at = -at;
+ }
+ } else {
+ // If the index is dynamic, adjust it in code.
+ if (delta > 0) {
+ at = 'int(' + at + ' + ' + delta + ')';
+ } else if (delta < 0) {
+ at = 'int(' + at + ' - ' + -delta + ')';
+ } else {
+ at = 'int(' + at + ')';
+ }
+ if (opt_negate) {
+ at = '-' + at;
+ }
+ }
+ return at;
+};
+
diff --git a/generators/python/colour.js b/generators/python/colour.js
index 49505ac86..68666a89b 100644
--- a/generators/python/colour.js
+++ b/generators/python/colour.js
@@ -46,11 +46,11 @@ Blockly.Python['colour_rgb'] = function(block) {
// Compose a colour from RGB components expressed as percentages.
var functionName = Blockly.Python.provideFunction_(
'colour_rgb',
- [ 'def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(r, g, b):',
- ' r = round(min(100, max(0, r)) * 2.55)',
- ' g = round(min(100, max(0, g)) * 2.55)',
- ' b = round(min(100, max(0, b)) * 2.55)',
- ' return \'#%02x%02x%02x\' % (r, g, b)']);
+ ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(r, g, b):',
+ ' r = round(min(100, max(0, r)) * 2.55)',
+ ' g = round(min(100, max(0, g)) * 2.55)',
+ ' b = round(min(100, max(0, b)) * 2.55)',
+ ' return \'#%02x%02x%02x\' % (r, g, b)']);
var r = Blockly.Python.valueToCode(block, 'RED',
Blockly.Python.ORDER_NONE) || 0;
var g = Blockly.Python.valueToCode(block, 'GREEN',
diff --git a/generators/python/lists.js b/generators/python/lists.js
index e43e31d5e..b831d4d2f 100644
--- a/generators/python/lists.js
+++ b/generators/python/lists.js
@@ -36,66 +36,75 @@ Blockly.Python['lists_create_empty'] = function(block) {
Blockly.Python['lists_create_with'] = function(block) {
// Create a list with any number of elements of any type.
- var code = new Array(block.itemCount_);
- for (var n = 0; n < block.itemCount_; n++) {
- code[n] = Blockly.Python.valueToCode(block, 'ADD' + n,
+ var elements = new Array(block.itemCount_);
+ for (var i = 0; i < block.itemCount_; i++) {
+ elements[i] = Blockly.Python.valueToCode(block, 'ADD' + i,
Blockly.Python.ORDER_NONE) || 'None';
}
- code = '[' + code.join(', ') + ']';
+ var code = '[' + elements.join(', ') + ']';
return [code, Blockly.Python.ORDER_ATOMIC];
};
Blockly.Python['lists_repeat'] = function(block) {
// Create a list with one element repeated.
- var argument0 = Blockly.Python.valueToCode(block, 'ITEM',
+ var item = Blockly.Python.valueToCode(block, 'ITEM',
Blockly.Python.ORDER_NONE) || 'None';
- var argument1 = Blockly.Python.valueToCode(block, 'NUM',
+ var times = Blockly.Python.valueToCode(block, 'NUM',
Blockly.Python.ORDER_MULTIPLICATIVE) || '0';
- var code = '[' + argument0 + '] * ' + argument1;
+ var code = '[' + item + '] * ' + times;
return [code, Blockly.Python.ORDER_MULTIPLICATIVE];
};
Blockly.Python['lists_length'] = function(block) {
// String or array length.
- var argument0 = Blockly.Python.valueToCode(block, 'VALUE',
+ var list = Blockly.Python.valueToCode(block, 'VALUE',
Blockly.Python.ORDER_NONE) || '[]';
- return ['len(' + argument0 + ')', Blockly.Python.ORDER_FUNCTION_CALL];
+ return ['len(' + list + ')', Blockly.Python.ORDER_FUNCTION_CALL];
};
Blockly.Python['lists_isEmpty'] = function(block) {
// Is the string null or array empty?
- var argument0 = Blockly.Python.valueToCode(block, 'VALUE',
+ var list = Blockly.Python.valueToCode(block, 'VALUE',
Blockly.Python.ORDER_NONE) || '[]';
- var code = 'not len(' + argument0 + ')';
+ var code = 'not len(' + list + ')';
return [code, Blockly.Python.ORDER_LOGICAL_NOT];
};
Blockly.Python['lists_indexOf'] = function(block) {
// Find an item in the list.
- var argument0 = Blockly.Python.valueToCode(block, 'FIND',
+ var item = Blockly.Python.valueToCode(block, 'FIND',
Blockly.Python.ORDER_NONE) || '[]';
- var argument1 = Blockly.Python.valueToCode(block, 'VALUE',
- Blockly.Python.ORDER_MEMBER) || '\'\'';
- var code;
+ var list = Blockly.Python.valueToCode(block, 'VALUE',
+ Blockly.Python.ORDER_NONE) || '\'\'';
+ if (Blockly.Python.ONE_BASED_INDEXING) {
+ var errorIndex = ' 0';
+ var firstIndexAdjustment = ' + 1';
+ var lastIndexAdjustment = '';
+ } else {
+ var errorIndex = ' -1';
+ var firstIndexAdjustment = '';
+ var lastIndexAdjustment = ' - 1';
+ }
if (block.getFieldValue('END') == 'FIRST') {
var functionName = Blockly.Python.provideFunction_(
'first_index',
- ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList, elem):',
- ' try: theIndex = myList.index(elem) + 1',
- ' except: theIndex = 0',
- ' return theIndex']);
- code = functionName + '(' + argument1 + ', ' + argument0 + ')';
- return [code, Blockly.Python.ORDER_FUNCTION_CALL];
- } else {
- var functionName = Blockly.Python.provideFunction_(
- 'last_index',
- ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList, elem):',
- ' try: theIndex = len(myList) - myList[::-1].index(elem)',
- ' except: theIndex = 0',
- ' return theIndex']);
- code = functionName + '(' + argument1 + ', ' + argument0 + ')';
+ ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ +
+ '(my_list, elem):',
+ ' try: index = my_list.index(elem)' + firstIndexAdjustment,
+ ' except: index =' + errorIndex,
+ ' return index']);
+ var code = functionName + '(' + list + ', ' + item + ')';
return [code, Blockly.Python.ORDER_FUNCTION_CALL];
}
+ var functionName = Blockly.Python.provideFunction_(
+ 'last_index',
+ ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(my_list, elem):',
+ ' try: index = len(my_list) - my_list[::-1].index(elem)' +
+ lastIndexAdjustment,
+ ' except: index =' + errorIndex,
+ ' return index']);
+ var code = functionName + '(' + list + ', ' + item + ')';
+ return [code, Blockly.Python.ORDER_FUNCTION_CALL];
};
Blockly.Python['lists_getIndex'] = function(block) {
@@ -103,85 +112,76 @@ Blockly.Python['lists_getIndex'] = function(block) {
// Note: Until January 2013 this block did not have MODE or WHERE inputs.
var mode = block.getFieldValue('MODE') || 'GET';
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.Python.valueToCode(block, 'AT',
- Blockly.Python.ORDER_UNARY_SIGN) || '1';
- var list = Blockly.Python.valueToCode(block, 'VALUE',
- Blockly.Python.ORDER_MEMBER) || '[]';
+ var listOrder = (where == 'RANDOM') ? Blockly.Python.ORDER_NONE :
+ Blockly.Python.ORDER_MEMBER;
+ var list = Blockly.Python.valueToCode(block, 'VALUE', listOrder) || '[]';
- if (where == 'FIRST') {
- if (mode == 'GET') {
- var code = list + '[0]';
- return [code, Blockly.Python.ORDER_MEMBER];
- } else {
- var code = list + '.pop(0)';
- if (mode == 'GET_REMOVE') {
+ switch (where) {
+ case 'FIRST':
+ if (mode == 'GET') {
+ var code = list + '[0]';
+ return [code, Blockly.Python.ORDER_MEMBER];
+ } else if (mode == 'GET_REMOVE') {
+ var code = list + '.pop(0)';
return [code, Blockly.Python.ORDER_FUNCTION_CALL];
} else if (mode == 'REMOVE') {
- return code + '\n';
+ return list + '.pop(0)\n';
}
- }
- } else if (where == 'LAST') {
- if (mode == 'GET') {
- var code = list + '[-1]';
- return [code, Blockly.Python.ORDER_MEMBER];
- } else {
- var code = list + '.pop()';
- if (mode == 'GET_REMOVE') {
+ break;
+ case 'LAST':
+ if (mode == 'GET') {
+ var code = list + '[-1]';
+ return [code, Blockly.Python.ORDER_MEMBER];
+ } else if (mode == 'GET_REMOVE') {
+ var code = list + '.pop()';
return [code, Blockly.Python.ORDER_FUNCTION_CALL];
} else if (mode == 'REMOVE') {
- return code + '\n';
+ return list + '.pop()\n';
}
- }
- } else if (where == 'FROM_START') {
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at)) {
- // If the index is a naked number, decrement it right now.
- at = parseInt(at, 10) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at = 'int(' + at + ' - 1)';
- }
- if (mode == 'GET') {
- var code = list + '[' + at + ']';
- return [code, Blockly.Python.ORDER_MEMBER];
- } else {
- var code = list + '.pop(' + at + ')';
- if (mode == 'GET_REMOVE') {
+ break;
+ case 'FROM_START':
+ var at = Blockly.Python.getAdjustedInt(block, 'AT');
+ if (mode == 'GET') {
+ var code = list + '[' + at + ']';
+ return [code, Blockly.Python.ORDER_MEMBER];
+ } else if (mode == 'GET_REMOVE') {
+ var code = list + '.pop(' + at + ')';
return [code, Blockly.Python.ORDER_FUNCTION_CALL];
} else if (mode == 'REMOVE') {
- return code + '\n';
+ return list + '.pop(' + at + ')\n';
}
- }
- } else if (where == 'FROM_END') {
- if (mode == 'GET') {
- var code = list + '[-' + at + ']';
- return [code, Blockly.Python.ORDER_MEMBER];
- } else {
- var code = list + '.pop(-' + at + ')';
- if (mode == 'GET_REMOVE') {
+ break;
+ case'FROM_END':
+ var at = Blockly.Python.getAdjustedInt(block, 'AT', 1, true);
+ if (mode == 'GET') {
+ var code = list + '[' + at + ']';
+ return [code, Blockly.Python.ORDER_MEMBER];
+ } else if (mode == 'GET_REMOVE') {
+ var code = list + '.pop(' + at + ')';
return [code, Blockly.Python.ORDER_FUNCTION_CALL];
} else if (mode == 'REMOVE') {
- return code + '\n';
+ return list + '.pop(' + at + ')\n';
}
- }
- } else if (where == 'RANDOM') {
- Blockly.Python.definitions_['import_random'] = 'import random';
- if (mode == 'GET') {
- code = 'random.choice(' + list + ')';
- return [code, Blockly.Python.ORDER_FUNCTION_CALL];
- } else {
- var functionName = Blockly.Python.provideFunction_(
- 'lists_remove_random_item',
- ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):',
- ' x = int(random.random() * len(myList))',
- ' return myList.pop(x)']);
- code = functionName + '(' + list + ')';
- if (mode == 'GET_REMOVE') {
+ break;
+ case 'RANDOM':
+ Blockly.Python.definitions_['import_random'] = 'import random';
+ if (mode == 'GET') {
+ code = 'random.choice(' + list + ')';
return [code, Blockly.Python.ORDER_FUNCTION_CALL];
- } else if (mode == 'REMOVE') {
- return code + '\n';
+ } else {
+ var functionName = Blockly.Python.provideFunction_(
+ 'lists_remove_random_item',
+ ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):',
+ ' x = int(random.random() * len(myList))',
+ ' return myList.pop(x)']);
+ code = functionName + '(' + list + ')';
+ if (mode == 'GET_REMOVE') {
+ return [code, Blockly.Python.ORDER_FUNCTION_CALL];
+ } else if (mode == 'REMOVE') {
+ return code + '\n';
+ }
}
- }
+ break;
}
throw 'Unhandled combination (lists_getIndex).';
};
@@ -193,8 +193,6 @@ Blockly.Python['lists_setIndex'] = function(block) {
Blockly.Python.ORDER_MEMBER) || '[]';
var mode = block.getFieldValue('MODE') || 'GET';
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.Python.valueToCode(block, 'AT',
- Blockly.Python.ORDER_NONE) || '1';
var value = Blockly.Python.valueToCode(block, 'TO',
Blockly.Python.ORDER_NONE) || 'None';
// Cache non-trivial values to variables to prevent repeated look-ups.
@@ -209,51 +207,52 @@ Blockly.Python['lists_setIndex'] = function(block) {
list = listVar;
return code;
}
- if (where == 'FIRST') {
- if (mode == 'SET') {
- return list + '[0] = ' + value + '\n';
- } else if (mode == 'INSERT') {
- return list + '.insert(0, ' + value + ')\n';
- }
- } else if (where == 'LAST') {
- if (mode == 'SET') {
- return list + '[-1] = ' + value + '\n';
- } else if (mode == 'INSERT') {
- return list + '.append(' + value + ')\n';
- }
- } else if (where == 'FROM_START') {
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at)) {
- // If the index is a naked number, decrement it right now.
- at = parseInt(at, 10) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at = 'int(' + at + ' - 1)';
- }
- if (mode == 'SET') {
- return list + '[' + at + '] = ' + value + '\n';
- } else if (mode == 'INSERT') {
- return list + '.insert(' + at + ', ' + value + ')\n';
- }
- } else if (where == 'FROM_END') {
- if (mode == 'SET') {
- return list + '[-' + at + '] = ' + value + '\n';
- } else if (mode == 'INSERT') {
- return list + '.insert(-' + at + ', ' + value + ')\n';
- }
- } else if (where == 'RANDOM') {
- Blockly.Python.definitions_['import_random'] = 'import random';
- var code = cacheList();
- var xVar = Blockly.Python.variableDB_.getDistinctName(
- 'tmp_x', Blockly.Variables.NAME_TYPE);
- code += xVar + ' = int(random.random() * len(' + list + '))\n';
- if (mode == 'SET') {
- code += list + '[' + xVar + '] = ' + value + '\n';
- return code;
- } else if (mode == 'INSERT') {
- code += list + '.insert(' + xVar + ', ' + value + ')\n';
- return code;
- }
+
+ switch (where) {
+ case 'FIRST':
+ if (mode == 'SET') {
+ return list + '[0] = ' + value + '\n';
+ } else if (mode == 'INSERT') {
+ return list + '.insert(0, ' + value + ')\n';
+ }
+ break;
+ case 'LAST':
+ if (mode == 'SET') {
+ return list + '[-1] = ' + value + '\n';
+ } else if (mode == 'INSERT') {
+ return list + '.append(' + value + ')\n';
+ }
+ break;
+ case 'FROM_START':
+ var at = Blockly.Python.getAdjustedInt(block, 'AT');
+ if (mode == 'SET') {
+ return list + '[' + at + '] = ' + value + '\n';
+ } else if (mode == 'INSERT') {
+ return list + '.insert(' + at + ', ' + value + ')\n';
+ }
+ break;
+ case 'FROM_END':
+ var at = Blockly.Python.getAdjustedInt(block, 'AT', 1, true);
+ if (mode == 'SET') {
+ return list + '[' + at + '] = ' + value + '\n';
+ } else if (mode == 'INSERT') {
+ return list + '.insert(' + at + ', ' + value + ')\n';
+ }
+ break;
+ case 'RANDOM':
+ Blockly.Python.definitions_['import_random'] = 'import random';
+ var code = cacheList();
+ var xVar = Blockly.Python.variableDB_.getDistinctName(
+ 'tmp_x', Blockly.Variables.NAME_TYPE);
+ code += xVar + ' = int(random.random() * len(' + list + '))\n';
+ if (mode == 'SET') {
+ code += list + '[' + xVar + '] = ' + value + '\n';
+ return code;
+ } else if (mode == 'INSERT') {
+ code += list + '.insert(' + xVar + ', ' + value + ')\n';
+ return code;
+ }
+ break;
}
throw 'Unhandled combination (lists_setIndex).';
};
@@ -264,49 +263,42 @@ Blockly.Python['lists_getSublist'] = function(block) {
Blockly.Python.ORDER_MEMBER) || '[]';
var where1 = block.getFieldValue('WHERE1');
var where2 = block.getFieldValue('WHERE2');
- var at1 = Blockly.Python.valueToCode(block, 'AT1',
- Blockly.Python.ORDER_ADDITIVE) || '1';
- var at2 = Blockly.Python.valueToCode(block, 'AT2',
- Blockly.Python.ORDER_ADDITIVE) || '1';
- if (where1 == 'FIRST' || (where1 == 'FROM_START' && at1 == '1')) {
- at1 = '';
- } else if (where1 == 'FROM_START') {
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at1)) {
- // If the index is a naked number, decrement it right now.
- at1 = parseInt(at1, 10) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at1 = 'int(' + at1 + ' - 1)';
- }
- } else if (where1 == 'FROM_END') {
- if (Blockly.isNumber(at1)) {
- at1 = -parseInt(at1, 10);
- } else {
- at1 = '-int(' + at1 + ')';
- }
+ switch (where1) {
+ case 'FROM_START':
+ var at1 = Blockly.Python.getAdjustedInt(block, 'AT1');
+ if (at1 == '0') {
+ at1 = '';
+ }
+ break;
+ case 'FROM_END':
+ var at1 = Blockly.Python.getAdjustedInt(block, 'AT1', 1, true);
+ break;
+ case 'FIRST':
+ var at1 = '';
+ break;
+ default:
+ throw 'Unhandled option (lists_getSublist)';
}
- if (where2 == 'LAST' || (where2 == 'FROM_END' && at2 == '1')) {
- at2 = '';
- } else if (where1 == 'FROM_START') {
- if (Blockly.isNumber(at2)) {
- at2 = parseInt(at2, 10);
- } else {
- at2 = 'int(' + at2 + ')';
- }
- } else if (where1 == 'FROM_END') {
- if (Blockly.isNumber(at2)) {
- // If the index is a naked number, increment it right now.
- // Add special case for -0.
- at2 = 1 - parseInt(at2, 10);
- if (at2 == 0) {
+ switch (where2) {
+ case 'FROM_START':
+ var at2 = Blockly.Python.getAdjustedInt(block, 'AT2', 1);
+ break;
+ case 'FROM_END':
+ var at2 = Blockly.Python.getAdjustedInt(block, 'AT2', 0, true);
+ // Ensure that if the result calculated is 0 that sub-sequence will
+ // include all elements as expected.
+ if (!Blockly.isNumber(String(at2))) {
+ Blockly.Python.definitions_['import_sys'] = 'import sys';
+ at2 += ' or sys.maxsize';
+ } else if (at2 == '0') {
at2 = '';
}
- } else {
- // If the index is dynamic, increment it in code.
- Blockly.Python.definitions_['import_sys'] = 'import sys';
- at2 = 'int(1 - ' + at2 + ') or sys.maxsize';
- }
+ break;
+ case 'LAST':
+ var at2 = '';
+ break;
+ default:
+ throw 'Unhandled option (lists_getSublist)';
}
var code = list + '[' + at1 + ' : ' + at2 + ']';
return [code, Blockly.Python.ORDER_MEMBER];
@@ -314,30 +306,30 @@ Blockly.Python['lists_getSublist'] = function(block) {
Blockly.Python['lists_sort'] = function(block) {
// Block for sorting a list.
- var listCode = (Blockly.Python.valueToCode(block, 'LIST',
- Blockly.Python.ORDER_MEMBER) || '[]');
+ var list = (Blockly.Python.valueToCode(block, 'LIST',
+ Blockly.Python.ORDER_NONE) || '[]');
var type = block.getFieldValue('TYPE');
var reverse = block.getFieldValue('DIRECTION') === '1' ? 'False' : 'True';
var sortFunctionName = Blockly.Python.provideFunction_('lists_sort',
['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ +
- '(listv, type, reversev):',
- ' def tryfloat(s):',
+ '(my_list, type, reverse):',
+ ' def try_float(s):',
' try:',
' return float(s)',
' except:',
' return 0',
- ' keyFuncts = {',
- ' "NUMERIC": tryfloat,',
+ ' key_funcs = {',
+ ' "NUMERIC": try_float,',
' "TEXT": str,',
' "IGNORE_CASE": lambda s: str(s).lower()',
' }',
- ' keyv = keyFuncts[type]',
- ' tmp_list = list(listv)', // Clone the list.
- ' return sorted(tmp_list, key=keyv, reverse=reversev)'
+ ' key_func = key_funcs[type]',
+ ' list_cpy = list(my_list)', // Clone the list.
+ ' return sorted(list_cpy, key=key_func, reverse=reverse)'
]);
var code = sortFunctionName +
- '(' + listCode + ', "' + type + '", ' + reverse + ')';
+ '(' + list + ', "' + type + '", ' + reverse + ')';
return [code, Blockly.Python.ORDER_FUNCTION_CALL];
};
diff --git a/generators/python/procedures.js b/generators/python/procedures.js
index daa7386aa..b90f38d5b 100644
--- a/generators/python/procedures.js
+++ b/generators/python/procedures.js
@@ -65,8 +65,8 @@ Blockly.Python['procedures_defreturn'] = function(block) {
branch = Blockly.Python.PASS;
}
var args = [];
- for (var x = 0; x < block.arguments_.length; x++) {
- args[x] = Blockly.Python.variableDB_.getName(block.arguments_[x],
+ for (var i = 0; i < block.arguments_.length; i++) {
+ args[i] = Blockly.Python.variableDB_.getName(block.arguments_[i],
Blockly.Variables.NAME_TYPE);
}
var code = 'def ' + funcName + '(' + args.join(', ') + '):\n' +
@@ -87,8 +87,8 @@ Blockly.Python['procedures_callreturn'] = function(block) {
var funcName = Blockly.Python.variableDB_.getName(block.getFieldValue('NAME'),
Blockly.Procedures.NAME_TYPE);
var args = [];
- for (var x = 0; x < block.arguments_.length; x++) {
- args[x] = Blockly.Python.valueToCode(block, 'ARG' + x,
+ for (var i = 0; i < block.arguments_.length; i++) {
+ args[i] = Blockly.Python.valueToCode(block, 'ARG' + i,
Blockly.Python.ORDER_NONE) || 'None';
}
var code = funcName + '(' + args.join(', ') + ')';
@@ -100,8 +100,8 @@ Blockly.Python['procedures_callnoreturn'] = function(block) {
var funcName = Blockly.Python.variableDB_.getName(block.getFieldValue('NAME'),
Blockly.Procedures.NAME_TYPE);
var args = [];
- for (var x = 0; x < block.arguments_.length; x++) {
- args[x] = Blockly.Python.valueToCode(block, 'ARG' + x,
+ for (var i = 0; i < block.arguments_.length; i++) {
+ args[i] = Blockly.Python.valueToCode(block, 'ARG' + i,
Blockly.Python.ORDER_NONE) || 'None';
}
var code = funcName + '(' + args.join(', ') + ')\n';
diff --git a/generators/python/text.js b/generators/python/text.js
index 3ae0ffc8e..84e19872a 100644
--- a/generators/python/text.js
+++ b/generators/python/text.js
@@ -38,32 +38,35 @@ Blockly.Python['text'] = function(block) {
Blockly.Python['text_join'] = function(block) {
// Create a string made up of any number of elements of any type.
//Should we allow joining by '-' or ',' or any other characters?
- var code;
- if (block.itemCount_ == 0) {
- return ['\'\'', Blockly.Python.ORDER_ATOMIC];
- } else if (block.itemCount_ == 1) {
- var argument0 = Blockly.Python.valueToCode(block, 'ADD0',
- Blockly.Python.ORDER_NONE) || '\'\'';
- code = 'str(' + argument0 + ')';
- return [code, Blockly.Python.ORDER_FUNCTION_CALL];
- } else if (block.itemCount_ == 2) {
- var argument0 = Blockly.Python.valueToCode(block, 'ADD0',
- Blockly.Python.ORDER_NONE) || '\'\'';
- var argument1 = Blockly.Python.valueToCode(block, 'ADD1',
- Blockly.Python.ORDER_NONE) || '\'\'';
- var code = 'str(' + argument0 + ') + str(' + argument1 + ')';
- return [code, Blockly.Python.ORDER_UNARY_SIGN];
- } else {
- var code = [];
- for (var n = 0; n < block.itemCount_; n++) {
- code[n] = Blockly.Python.valueToCode(block, 'ADD' + n,
- Blockly.Python.ORDER_NONE) || '\'\'';
- }
- var tempVar = Blockly.Python.variableDB_.getDistinctName('temp_value',
- Blockly.Variables.NAME_TYPE);
- code = '\'\'.join([str(' + tempVar + ') for ' + tempVar + ' in [' +
- code.join(', ') + ']])';
- return [code, Blockly.Python.ORDER_FUNCTION_CALL];
+ switch (block.itemCount_) {
+ case 0:
+ return ['\'\'', Blockly.Python.ORDER_ATOMIC];
+ break;
+ case 1:
+ var element = Blockly.Python.valueToCode(block, 'ADD0',
+ Blockly.Python.ORDER_NONE) || '\'\'';
+ var code = 'str(' + element + ')';
+ return [code, Blockly.Python.ORDER_FUNCTION_CALL];
+ break;
+ case 2:
+ var element0 = Blockly.Python.valueToCode(block, 'ADD0',
+ Blockly.Python.ORDER_NONE) || '\'\'';
+ var element1 = Blockly.Python.valueToCode(block, 'ADD1',
+ Blockly.Python.ORDER_NONE) || '\'\'';
+ var code = 'str(' + element0 + ') + str(' + element1 + ')';
+ return [code, Blockly.Python.ORDER_ADDITIVE];
+ break;
+ default:
+ var elements = [];
+ for (var i = 0; i < block.itemCount_; i++) {
+ elements[i] = Blockly.Python.valueToCode(block, 'ADD' + i,
+ Blockly.Python.ORDER_NONE) || '\'\'';
+ }
+ var tempVar = Blockly.Python.variableDB_.getDistinctName('x',
+ Blockly.Variables.NAME_TYPE);
+ var code = '\'\'.join([str(' + tempVar + ') for ' + tempVar + ' in [' +
+ elements.join(', ') + ']])';
+ return [code, Blockly.Python.ORDER_FUNCTION_CALL];
}
};
@@ -71,23 +74,23 @@ Blockly.Python['text_append'] = function(block) {
// Append to a variable in place.
var varName = Blockly.Python.variableDB_.getName(block.getFieldValue('VAR'),
Blockly.Variables.NAME_TYPE);
- var argument0 = Blockly.Python.valueToCode(block, 'TEXT',
+ var value = Blockly.Python.valueToCode(block, 'TEXT',
Blockly.Python.ORDER_NONE) || '\'\'';
- return varName + ' = str(' + varName + ') + str(' + argument0 + ')\n';
+ return varName + ' = str(' + varName + ') + str(' + value + ')\n';
};
Blockly.Python['text_length'] = function(block) {
// Is the string null or array empty?
- var argument0 = Blockly.Python.valueToCode(block, 'VALUE',
+ var text = Blockly.Python.valueToCode(block, 'VALUE',
Blockly.Python.ORDER_NONE) || '\'\'';
- return ['len(' + argument0 + ')', Blockly.Python.ORDER_FUNCTION_CALL];
+ return ['len(' + text + ')', Blockly.Python.ORDER_FUNCTION_CALL];
};
Blockly.Python['text_isEmpty'] = function(block) {
// Is the string null or array empty?
- var argument0 = Blockly.Python.valueToCode(block, 'VALUE',
+ var text = Blockly.Python.valueToCode(block, 'VALUE',
Blockly.Python.ORDER_NONE) || '\'\'';
- var code = 'not len(' + argument0 + ')';
+ var code = 'not len(' + text + ')';
return [code, Blockly.Python.ORDER_LOGICAL_NOT];
};
@@ -95,20 +98,21 @@ Blockly.Python['text_indexOf'] = function(block) {
// Search the text for a substring.
// Should we allow for non-case sensitive???
var operator = block.getFieldValue('END') == 'FIRST' ? 'find' : 'rfind';
- var argument0 = Blockly.Python.valueToCode(block, 'FIND',
+ var substring = Blockly.Python.valueToCode(block, 'FIND',
Blockly.Python.ORDER_NONE) || '\'\'';
- var argument1 = Blockly.Python.valueToCode(block, 'VALUE',
+ var text = Blockly.Python.valueToCode(block, 'VALUE',
Blockly.Python.ORDER_MEMBER) || '\'\'';
- var code = argument1 + '.' + operator + '(' + argument0 + ') + 1';
- return [code, Blockly.Python.ORDER_ADDITIVE];
+ var code = text + '.' + operator + '(' + substring + ')';
+ if (Blockly.Python.ONE_BASED_INDEXING) {
+ return [code + ' + 1', Blockly.Python.ORDER_ADDITIVE];
+ }
+ return [code, Blockly.Python.ORDER_FUNCTION_CALL];
};
Blockly.Python['text_charAt'] = function(block) {
// Get letter at index.
// Note: Until January 2013 this block did not have the WHERE input.
var where = block.getFieldValue('WHERE') || 'FROM_START';
- var at = Blockly.Python.valueToCode(block, 'AT',
- Blockly.Python.ORDER_UNARY_SIGN) || '1';
var text = Blockly.Python.valueToCode(block, 'VALUE',
Blockly.Python.ORDER_MEMBER) || '\'\'';
switch (where) {
@@ -119,18 +123,12 @@ Blockly.Python['text_charAt'] = function(block) {
var code = text + '[-1]';
return [code, Blockly.Python.ORDER_MEMBER];
case 'FROM_START':
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at)) {
- // If the index is a naked number, decrement it right now.
- at = parseInt(at, 10) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at = 'int(' + at + ' - 1)';
- }
+ var at = Blockly.Python.getAdjustedInt(block, 'AT');
var code = text + '[' + at + ']';
return [code, Blockly.Python.ORDER_MEMBER];
case 'FROM_END':
- var code = text + '[-' + at + ']';
+ var at = Blockly.Python.getAdjustedInt(block, 'AT', 1, true);
+ var code = text + '[' + at + ']';
return [code, Blockly.Python.ORDER_MEMBER];
case 'RANDOM':
Blockly.Python.definitions_['import_random'] = 'import random';
@@ -147,53 +145,46 @@ Blockly.Python['text_charAt'] = function(block) {
Blockly.Python['text_getSubstring'] = function(block) {
// Get substring.
- var text = Blockly.Python.valueToCode(block, 'STRING',
- Blockly.Python.ORDER_MEMBER) || '\'\'';
var where1 = block.getFieldValue('WHERE1');
var where2 = block.getFieldValue('WHERE2');
- var at1 = Blockly.Python.valueToCode(block, 'AT1',
- Blockly.Python.ORDER_ADDITIVE) || '1';
- var at2 = Blockly.Python.valueToCode(block, 'AT2',
- Blockly.Python.ORDER_ADDITIVE) || '1';
- if (where1 == 'FIRST' || (where1 == 'FROM_START' && at1 == '1')) {
- at1 = '';
- } else if (where1 == 'FROM_START') {
- // Blockly uses one-based indicies.
- if (Blockly.isNumber(at1)) {
- // If the index is a naked number, decrement it right now.
- at1 = parseInt(at1, 10) - 1;
- } else {
- // If the index is dynamic, decrement it in code.
- at1 = 'int(' + at1 + ' - 1)';
- }
- } else if (where1 == 'FROM_END') {
- if (Blockly.isNumber(at1)) {
- at1 = -parseInt(at1, 10);
- } else {
- at1 = '-int(' + at1 + ')';
- }
+ var text = Blockly.Python.valueToCode(block, 'STRING',
+ Blockly.Python.ORDER_MEMBER) || '\'\'';
+ switch (where1) {
+ case 'FROM_START':
+ var at1 = Blockly.Python.getAdjustedInt(block, 'AT1');
+ if (at1 == '0') {
+ at1 = '';
+ }
+ break;
+ case 'FROM_END':
+ var at1 = Blockly.Python.getAdjustedInt(block, 'AT1', 1, true);
+ break;
+ case 'FIRST':
+ var at1 = '';
+ break;
+ default:
+ throw 'Unhandled option (text_getSubstring)';
}
- if (where2 == 'LAST' || (where2 == 'FROM_END' && at2 == '1')) {
- at2 = '';
- } else if (where1 == 'FROM_START') {
- if (Blockly.isNumber(at2)) {
- at2 = parseInt(at2, 10);
- } else {
- at2 = 'int(' + at2 + ')';
- }
- } else if (where1 == 'FROM_END') {
- if (Blockly.isNumber(at2)) {
- // If the index is a naked number, increment it right now.
- at2 = 1 - parseInt(at2, 10);
- if (at2 == 0) {
+ switch (where2) {
+ case 'FROM_START':
+ var at2 = Blockly.Python.getAdjustedInt(block, 'AT2', 1);
+ break;
+ case 'FROM_END':
+ var at2 = Blockly.Python.getAdjustedInt(block, 'AT2', 0, true);
+ // Ensure that if the result calculated is 0 that sub-sequence will
+ // include all elements as expected.
+ if (!Blockly.isNumber(String(at2))) {
+ Blockly.Python.definitions_['import_sys'] = 'import sys';
+ at2 += ' or sys.maxsize';
+ } else if (at2 == '0') {
at2 = '';
}
- } else {
- // If the index is dynamic, increment it in code.
- // Add special case for -0.
- Blockly.Python.definitions_['import_sys'] = 'import sys';
- at2 = 'int(1 - ' + at2 + ') or sys.maxsize';
- }
+ break;
+ case 'LAST':
+ var at2 = '';
+ break;
+ default:
+ throw 'Unhandled option (text_getSubstring)';
}
var code = text + '[' + at1 + ' : ' + at2 + ']';
return [code, Blockly.Python.ORDER_MEMBER];
@@ -207,10 +198,10 @@ Blockly.Python['text_changeCase'] = function(block) {
'TITLECASE': '.title()'
};
var operator = OPERATORS[block.getFieldValue('CASE')];
- var argument0 = Blockly.Python.valueToCode(block, 'TEXT',
+ var text = Blockly.Python.valueToCode(block, 'TEXT',
Blockly.Python.ORDER_MEMBER) || '\'\'';
- var code = argument0 + operator;
- return [code, Blockly.Python.ORDER_MEMBER];
+ var code = text + operator;
+ return [code, Blockly.Python.ORDER_FUNCTION_CALL];
};
Blockly.Python['text_trim'] = function(block) {
@@ -221,17 +212,17 @@ Blockly.Python['text_trim'] = function(block) {
'BOTH': '.strip()'
};
var operator = OPERATORS[block.getFieldValue('MODE')];
- var argument0 = Blockly.Python.valueToCode(block, 'TEXT',
+ var text = Blockly.Python.valueToCode(block, 'TEXT',
Blockly.Python.ORDER_MEMBER) || '\'\'';
- var code = argument0 + operator;
- return [code, Blockly.Python.ORDER_MEMBER];
+ var code = text + operator;
+ return [code, Blockly.Python.ORDER_FUNCTION_CALL];
};
Blockly.Python['text_print'] = function(block) {
// Print statement.
- var argument0 = Blockly.Python.valueToCode(block, 'TEXT',
+ var msg = Blockly.Python.valueToCode(block, 'TEXT',
Blockly.Python.ORDER_NONE) || '\'\'';
- return 'print(' + argument0 + ')\n';
+ return 'print(' + msg + ')\n';
};
Blockly.Python['text_prompt_ext'] = function(block) {
diff --git a/javascript_compressed.js b/javascript_compressed.js
index ad00ad4be..aaf4a1560 100644
--- a/javascript_compressed.js
+++ b/javascript_compressed.js
@@ -11,28 +11,32 @@ Blockly.JavaScript.ORDER_OVERRIDES=[[Blockly.JavaScript.ORDER_FUNCTION_CALL,Bloc
Blockly.JavaScript.ORDER_ADDITION],[Blockly.JavaScript.ORDER_LOGICAL_AND,Blockly.JavaScript.ORDER_LOGICAL_AND],[Blockly.JavaScript.ORDER_LOGICAL_OR,Blockly.JavaScript.ORDER_LOGICAL_OR]];Blockly.JavaScript.ONE_BASED_INDEXING=!0;
Blockly.JavaScript.init=function(a){Blockly.JavaScript.definitions_=Object.create(null);Blockly.JavaScript.functionNames_=Object.create(null);Blockly.JavaScript.variableDB_?Blockly.JavaScript.variableDB_.reset():Blockly.JavaScript.variableDB_=new Blockly.Names(Blockly.JavaScript.RESERVED_WORDS_);var b=[];a=Blockly.Variables.allVariables(a);if(a.length){for(var c=0;cc?Blockly.JavaScript.valueToCode(a,b,Blockly.JavaScript.ORDER_SUBTRACTION)||f:d?Blockly.JavaScript.valueToCode(a,b,Blockly.JavaScript.ORDER_UNARY_NEGATION)||f:Blockly.JavaScript.valueToCode(a,b,e)||f;if(Blockly.isNumber(a))a=parseFloat(a)+
+c,d&&(a=-a);else{if(0c&&(a=a+" - "+-c,g=Blockly.JavaScript.ORDER_SUBTRACTION);d&&(a=c?"-("+a+")":"-"+a,g=Blockly.JavaScript.ORDER_UNARY_NEGATION);g=Math.floor(g);e=Math.floor(e);g&&e>=g&&(a="("+a+")")}return a};Blockly.JavaScript.colour={};Blockly.JavaScript.colour_picker=function(a){return["'"+a.getFieldValue("COLOUR")+"'",Blockly.JavaScript.ORDER_ATOMIC]};Blockly.JavaScript.colour_random=function(a){return[Blockly.JavaScript.provideFunction_("colourRandom",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"() {"," var num = Math.floor(Math.random() * Math.pow(2, 24));"," return '#' + ('00000' + num.toString(16)).substr(-6);","}"])+"()",Blockly.JavaScript.ORDER_FUNCTION_CALL]};
Blockly.JavaScript.colour_rgb=function(a){var b=Blockly.JavaScript.valueToCode(a,"RED",Blockly.JavaScript.ORDER_COMMA)||0,c=Blockly.JavaScript.valueToCode(a,"GREEN",Blockly.JavaScript.ORDER_COMMA)||0;a=Blockly.JavaScript.valueToCode(a,"BLUE",Blockly.JavaScript.ORDER_COMMA)||0;return[Blockly.JavaScript.provideFunction_("colourRgb",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(r, g, b) {"," r = Math.max(Math.min(Number(r), 100), 0) * 2.55;"," g = Math.max(Math.min(Number(g), 100), 0) * 2.55;",
" b = Math.max(Math.min(Number(b), 100), 0) * 2.55;"," r = ('0' + (Math.round(r) || 0).toString(16)).slice(-2);"," g = ('0' + (Math.round(g) || 0).toString(16)).slice(-2);"," b = ('0' + (Math.round(b) || 0).toString(16)).slice(-2);"," return '#' + r + g + b;","}"])+"("+b+", "+c+", "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]};
Blockly.JavaScript.colour_blend=function(a){var b=Blockly.JavaScript.valueToCode(a,"COLOUR1",Blockly.JavaScript.ORDER_COMMA)||"'#000000'",c=Blockly.JavaScript.valueToCode(a,"COLOUR2",Blockly.JavaScript.ORDER_COMMA)||"'#000000'";a=Blockly.JavaScript.valueToCode(a,"RATIO",Blockly.JavaScript.ORDER_COMMA)||.5;return[Blockly.JavaScript.provideFunction_("colourBlend",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(c1, c2, ratio) {"," ratio = Math.max(Math.min(Number(ratio), 1), 0);"," var r1 = parseInt(c1.substring(1, 3), 16);",
" var g1 = parseInt(c1.substring(3, 5), 16);"," var b1 = parseInt(c1.substring(5, 7), 16);"," var r2 = parseInt(c2.substring(1, 3), 16);"," var g2 = parseInt(c2.substring(3, 5), 16);"," var b2 = parseInt(c2.substring(5, 7), 16);"," var r = Math.round(r1 * (1 - ratio) + r2 * ratio);"," var g = Math.round(g1 * (1 - ratio) + g2 * ratio);"," var b = Math.round(b1 * (1 - ratio) + b2 * ratio);"," r = ('0' + (r || 0).toString(16)).slice(-2);"," g = ('0' + (g || 0).toString(16)).slice(-2);"," b = ('0' + (b || 0).toString(16)).slice(-2);",
-" return '#' + r + g + b;","}"])+"("+b+", "+c+", "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]};Blockly.JavaScript.lists={};Blockly.JavaScript.lists_create_empty=function(a){return["[]",Blockly.JavaScript.ORDER_ATOMIC]};Blockly.JavaScript.lists_create_with=function(a){for(var b=Array(a.itemCount_),c=0;c b.toString() ? 1 : -1; },",
-' "IGNORE_CASE": function(a, b) {'," return a.toString().toLowerCase() > b.toString().toLowerCase() ? 1 : -1; },"," };"," var compare = compareFuncs[type];"," return function(a, b) { return compare(a, b) * direction; }","}"]);return["("+b+").slice().sort("+d+'("'+a+'", '+c+"))",Blockly.JavaScript.ORDER_FUNCTION_CALL]};
+' "IGNORE_CASE": function(a, b) {'," return a.toString().toLowerCase() > b.toString().toLowerCase() ? 1 : -1; },"," };"," var compare = compareFuncs[type];"," return function(a, b) { return compare(a, b) * direction; }","}"]);return[b+".slice().sort("+d+'("'+a+'", '+c+"))",Blockly.JavaScript.ORDER_FUNCTION_CALL]};
Blockly.JavaScript.lists_split=function(a){var b=Blockly.JavaScript.valueToCode(a,"INPUT",Blockly.JavaScript.ORDER_MEMBER),c=Blockly.JavaScript.valueToCode(a,"DELIM",Blockly.JavaScript.ORDER_NONE)||"''";a=a.getFieldValue("MODE");if("SPLIT"==a)b||(b="''"),a="split";else if("JOIN"==a)b||(b="[]"),a="join";else throw"Unknown mode: "+a;return[b+"."+a+"("+c+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]};Blockly.JavaScript.logic={};
Blockly.JavaScript.controls_if=function(a){for(var b=0,c=Blockly.JavaScript.valueToCode(a,"IF"+b,Blockly.JavaScript.ORDER_NONE)||"false",d=Blockly.JavaScript.statementToCode(a,"DO"+b),e="if ("+c+") {\n"+d+"}",b=1;b<=a.elseifCount_;b++)c=Blockly.JavaScript.valueToCode(a,"IF"+b,Blockly.JavaScript.ORDER_NONE)||"false",d=Blockly.JavaScript.statementToCode(a,"DO"+b),e+=" else if ("+c+") {\n"+d+"}";a.elseCount_&&(d=Blockly.JavaScript.statementToCode(a,"ELSE"),e+=" else {\n"+d+"}");return e+"\n"};
Blockly.JavaScript.logic_compare=function(a){var b={EQ:"==",NEQ:"!=",LT:"<",LTE:"<=",GT:">",GTE:">="}[a.getFieldValue("OP")],c="=="==b||"!="==b?Blockly.JavaScript.ORDER_EQUALITY:Blockly.JavaScript.ORDER_RELATIONAL,d=Blockly.JavaScript.valueToCode(a,"A",c)||"0";a=Blockly.JavaScript.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]};
@@ -71,16 +75,17 @@ Blockly.JavaScript.procedures_defreturn=function(a){var b=Blockly.JavaScript.var
Blockly.JavaScript.procedures_callreturn=function(a){for(var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE),c=[],d=0;d",GTE:">="}[a.getFieldValue("OP")],c=Blockly.Lua.valueToCode(a,"A",Blockly.Lua.ORDER_RELATIONAL)||"0";a=Blockly.Lua.valueToCode(a,"B",Blockly.Lua.ORDER_RELATIONAL)||"0";return[c+" "+b+" "+a,Blockly.Lua.ORDER_RELATIONAL]};
Blockly.Lua.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"and":"or",c="and"==b?Blockly.Lua.ORDER_AND:Blockly.Lua.ORDER_OR,d=Blockly.Lua.valueToCode(a,"A",c);a=Blockly.Lua.valueToCode(a,"B",c);if(d||a){var e="and"==b?"true":"false";d||(d=e);a||(a=e)}else a=d="false";return[d+" "+b+" "+a,c]};Blockly.Lua.logic_negate=function(a){return["not "+(Blockly.Lua.valueToCode(a,"BOOL",Blockly.Lua.ORDER_UNARY)||"true"),Blockly.Lua.ORDER_UNARY]};
Blockly.Lua.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"true":"false",Blockly.Lua.ORDER_ATOMIC]};Blockly.Lua.logic_null=function(a){return["nil",Blockly.Lua.ORDER_ATOMIC]};Blockly.Lua.logic_ternary=function(a){var b=Blockly.Lua.valueToCode(a,"IF",Blockly.Lua.ORDER_AND)||"false",c=Blockly.Lua.valueToCode(a,"THEN",Blockly.Lua.ORDER_AND)||"nil";a=Blockly.Lua.valueToCode(a,"ELSE",Blockly.Lua.ORDER_OR)||"nil";return[b+" and "+c+" or "+a,Blockly.Lua.ORDER_OR]};Blockly.Lua.loops={};Blockly.Lua.CONTINUE_STATEMENT="goto continue\n";Blockly.Lua.addContinueLabel=function(a){return-1c?Blockly.PHP.valueToCode(a,b,Blockly.PHP.ORDER_SUBTRACTION)||g:d?Blockly.PHP.valueToCode(a,b,Blockly.PHP.ORDER_UNARY_NEGATION)||g:Blockly.PHP.valueToCode(a,b,e)||g;if(Blockly.isNumber(a))a=parseFloat(a)+c,d&&(a=-a);else{if(0c&&
+(a=a+" - "+-c,f=Blockly.PHP.ORDER_SUBTRACTION);d&&(a=c?"-("+a+")":"-"+a,f=Blockly.PHP.ORDER_UNARY_NEGATION);f=Math.floor(f);e=Math.floor(e);f&&e>=f&&(a="("+a+")")}return a};Blockly.PHP.colour={};Blockly.PHP.colour_picker=function(a){return["'"+a.getFieldValue("COLOUR")+"'",Blockly.PHP.ORDER_ATOMIC]};Blockly.PHP.colour_random=function(a){return[Blockly.PHP.provideFunction_("colour_random",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"() {"," return '#' . str_pad(dechex(mt_rand(0, 0xFFFFFF)), 6, '0', STR_PAD_LEFT);","}"])+"()",Blockly.PHP.ORDER_FUNCTION_CALL]};
+Blockly.PHP.colour_rgb=function(a){var b=Blockly.PHP.valueToCode(a,"RED",Blockly.PHP.ORDER_COMMA)||0,c=Blockly.PHP.valueToCode(a,"GREEN",Blockly.PHP.ORDER_COMMA)||0;a=Blockly.PHP.valueToCode(a,"BLUE",Blockly.PHP.ORDER_COMMA)||0;return[Blockly.PHP.provideFunction_("colour_rgb",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($r, $g, $b) {"," $r = round(max(min($r, 100), 0) * 2.55);"," $g = round(max(min($g, 100), 0) * 2.55);"," $b = round(max(min($b, 100), 0) * 2.55);"," $hex = '#';"," $hex .= str_pad(dechex($r), 2, '0', STR_PAD_LEFT);",
+" $hex .= str_pad(dechex($g), 2, '0', STR_PAD_LEFT);"," $hex .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT);"," return $hex;","}"])+"("+b+", "+c+", "+a+")",Blockly.PHP.ORDER_FUNCTION_CALL]};
Blockly.PHP.colour_blend=function(a){var b=Blockly.PHP.valueToCode(a,"COLOUR1",Blockly.PHP.ORDER_COMMA)||"'#000000'",c=Blockly.PHP.valueToCode(a,"COLOUR2",Blockly.PHP.ORDER_COMMA)||"'#000000'";a=Blockly.PHP.valueToCode(a,"RATIO",Blockly.PHP.ORDER_COMMA)||.5;return[Blockly.PHP.provideFunction_("colour_blend",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($c1, $c2, $ratio) {"," $ratio = max(min($ratio, 1), 0);"," $r1 = hexdec(substr($c1, 1, 2));"," $g1 = hexdec(substr($c1, 3, 2));"," $b1 = hexdec(substr($c1, 5, 2));",
-" $r2 = hexdec(substr($c2, 1, 2));"," $g2 = hexdec(substr($c2, 3, 2));"," $b2 = hexdec(substr($c2, 5, 2));"," $r = round($r1 * (1 - $ratio) + $r2 * $ratio);"," $g = round($g1 * (1 - $ratio) + $g2 * $ratio);"," $b = round($b1 * (1 - $ratio) + $b2 * $ratio);",' $hex = "#";',' $hex .= str_pad(dechex($r), 2, "0", STR_PAD_LEFT);',' $hex .= str_pad(dechex($g), 2, "0", STR_PAD_LEFT);',' $hex .= str_pad(dechex($b), 2, "0", STR_PAD_LEFT);'," return $hex;","}"])+"("+b+", "+c+", "+a+")",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.lists={};Blockly.PHP.lists_create_empty=function(a){return["array()",Blockly.PHP.ORDER_ATOMIC]};Blockly.PHP.lists_create_with=function(a){for(var b=Array(a.itemCount_),c=0;c "strnatcasecmp",',' "TEXT" => "strcmp",',' "IGNORE_CASE" => "strcasecmp"'," );"," $sortCmp = $sortCmpFuncs[$type];"," $list2 = $list;",
-" usort($list2, $sortCmp);"," if ($direction == -1) {"," $list2 = array_reverse($list2);"," }"," return $list2;","}"])+"("+b+', "'+a+'", '+c+")",Blockly.PHP.ORDER_FUNCTION_CALL]};
-Blockly.PHP.lists_split=function(a){var b=Blockly.PHP.valueToCode(a,"INPUT",Blockly.PHP.ORDER_MEMBER),c=Blockly.PHP.valueToCode(a,"DELIM",Blockly.PHP.ORDER_NONE)||"''";a=a.getFieldValue("MODE");if("SPLIT"==a)b||(b="''"),a="explode";else if("JOIN"==a)b||(b="array()"),a="implode";else throw"Unknown mode: "+a;return[a+"("+c+", "+b+")",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.logic={};Blockly.PHP.controls_if=function(a){for(var b=0,c=Blockly.PHP.valueToCode(a,"IF"+b,Blockly.PHP.ORDER_NONE)||"false",d=Blockly.PHP.statementToCode(a,"DO"+b),e="if ("+c+") {\n"+d+"}",b=1;b<=a.elseifCount_;b++)c=Blockly.PHP.valueToCode(a,"IF"+b,Blockly.PHP.ORDER_NONE)||"false",d=Blockly.PHP.statementToCode(a,"DO"+b),e+=" else if ("+c+") {\n"+d+"}";a.elseCount_&&(d=Blockly.PHP.statementToCode(a,"ELSE"),e+=" else {\n"+d+"}");return e+"\n"};
+Blockly.PHP.lists_indexOf=function(a){var b=Blockly.PHP.valueToCode(a,"FIND",Blockly.PHP.ORDER_NONE)||"''",c=Blockly.PHP.valueToCode(a,"VALUE",Blockly.PHP.ORDER_MEMBER)||"[]";if(Blockly.PHP.ONE_BASED_INDEXING)var d=" 0",e=" + 1";else d=" -1",e="";return[("FIRST"==a.getFieldValue("END")?Blockly.PHP.provideFunction_("indexOf",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($haystack, $needle) {"," for ($index = 0; $index < count($haystack); $index++) {"," if ($haystack[$index] == $needle) return $index"+
+e+";"," }"," return "+d+";","}"]):Blockly.PHP.provideFunction_("lastIndexOf",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($haystack, $needle) {"," $last = "+d+";"," for ($index = 0; $index < count($haystack); $index++) {"," if ($haystack[$index] == $needle) $last = $index"+e+";"," }"," return $last;","}"]))+"("+c+", "+b+")",Blockly.PHP.ORDER_FUNCTION_CALL]};
+Blockly.PHP.lists_getIndex=function(a){var b=a.getFieldValue("MODE")||"GET";switch(a.getFieldValue("WHERE")||"FROM_START"){case "FIRST":if("GET"==b){var c=Blockly.PHP.valueToCode(a,"VALUE",Blockly.PHP.ORDER_MEMBER)||"array()";return[c+"[0]",Blockly.PHP.ORDER_MEMBER]}if("GET_REMOVE"==b)return c=Blockly.PHP.valueToCode(a,"VALUE",Blockly.PHP.ORDER_NONE)||"array()",["array_shift("+c+")",Blockly.PHP.ORDER_FUNCTION_CALL];if("REMOVE"==b)return c=Blockly.PHP.valueToCode(a,"VALUE",Blockly.PHP.ORDER_NONE)||
+"array()","array_shift("+c+");\n";break;case "LAST":if("GET"==b)return c=Blockly.PHP.valueToCode(a,"VALUE",Blockly.PHP.ORDER_NONE)||"array()",["end("+c+")",Blockly.PHP.ORDER_FUNCTION_CALL];if("GET_REMOVE"==b)return c=Blockly.PHP.valueToCode(a,"VALUE",Blockly.PHP.ORDER_NONE)||"array()",["array_pop("+c+")",Blockly.PHP.ORDER_FUNCTION_CALL];if("REMOVE"==b)return c=Blockly.PHP.valueToCode(a,"VALUE",Blockly.PHP.ORDER_NONE)||"array()","array_pop("+c+");\n";break;case "FROM_START":var d=Blockly.PHP.getAdjusted(a,
+"AT");if("GET"==b)return c=Blockly.PHP.valueToCode(a,"VALUE",Blockly.PHP.ORDER_MEMBER)||"array()",[c+"["+d+"]",Blockly.PHP.ORDER_MEMBER];if("GET_REMOVE"==b)return c=Blockly.PHP.valueToCode(a,"VALUE",Blockly.PHP.ORDER_COMMA)||"array()",["array_splice("+c+", "+d+", 1)[0]",Blockly.PHP.ORDER_FUNCTION_CALL];if("REMOVE"==b)return c=Blockly.PHP.valueToCode(a,"VALUE",Blockly.PHP.ORDER_COMMA)||"array()","array_splice("+c+", "+d+", 1);\n";break;case "FROM_END":if("GET"==b)return c=Blockly.PHP.valueToCode(a,
+"VALUE",Blockly.PHP.ORDER_COMMA)||"array()",d=Blockly.PHP.getAdjusted(a,"AT",1,!0),["array_slice("+c+", "+d+", 1)[0]",Blockly.PHP.ORDER_FUNCTION_CALL];if("GET_REMOVE"==b||"REMOVE"==b){c=Blockly.PHP.valueToCode(a,"VALUE",Blockly.PHP.ORDER_NONE)||"array()";d=Blockly.PHP.getAdjusted(a,"AT",1,!1,Blockly.PHP.ORDER_SUBTRACTION);c="array_splice("+c+", count("+c+") - "+d+", 1)[0]";if("GET_REMOVE"==b)return[c,Blockly.PHP.ORDER_FUNCTION_CALL];if("REMOVE"==b)return c+";\n"}break;case "RANDOM":c=Blockly.PHP.valueToCode(a,
+"VALUE",Blockly.PHP.ORDER_NONE)||"array()";if("GET"==b)return b=Blockly.PHP.provideFunction_("lists_get_random_item",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($list) {"," return $list[rand(0,count($list)-1)];","}"]),[b+"("+c+")",Blockly.PHP.ORDER_FUNCTION_CALL];if("GET_REMOVE"==b)return b=Blockly.PHP.provideFunction_("lists_get_remove_random_item",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"(&$list) {"," $x = rand(0,count($list)-1);"," unset($list[$x]);"," return array_values($list);",
+"}"]),[b+"("+c+")",Blockly.PHP.ORDER_FUNCTION_CALL];if("REMOVE"==b)return b=Blockly.PHP.provideFunction_("lists_remove_random_item",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"(&$list) {"," unset($list[rand(0,count($list)-1)]);","}"]),b+"("+c+");\n"}throw"Unhandled combination (lists_getIndex).";};
+Blockly.PHP.lists_setIndex=function(a){var b=a.getFieldValue("MODE")||"GET",c=a.getFieldValue("WHERE")||"FROM_START",d=Blockly.PHP.valueToCode(a,"TO",Blockly.PHP.ORDER_ASSIGNMENT)||"null";switch(c){case "FIRST":if("SET"==b)return c=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_MEMBER)||"array()",c+"[0] = "+d+";\n";if("INSERT"==b)return c=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_COMMA)||"array()","array_unshift("+c+", "+d+");\n";break;case "LAST":c=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_COMMA)||
+"array()";if("SET"==b)return b=Blockly.PHP.provideFunction_("lists_set_last_item",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"(&$list, $value) {"," $list[count($list) - 1] = $value;","}"]),b+"("+c+", "+d+");\n";if("INSERT"==b)return"array_push("+c+", "+d+");\n";break;case "FROM_START":var e=Blockly.PHP.getAdjusted(a,"AT");if("SET"==b)return c=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_MEMBER)||"array()",c+"["+e+"] = "+d+";\n";if("INSERT"==b)return c=Blockly.PHP.valueToCode(a,"LIST",
+Blockly.PHP.ORDER_COMMA)||"array()","array_splice("+c+", "+e+", 0, "+d+");\n";break;case "FROM_END":c=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_COMMA)||"array()";e=Blockly.PHP.getAdjusted(a,"AT",1);if("SET"==b)return b=Blockly.PHP.provideFunction_("lists_set_from_end",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"(&$list, $at, $value) {"," $list[count($list) - $at] = $value;","}"]),b+"("+c+", "+e+", "+d+");\n";if("INSERT"==b)return b=Blockly.PHP.provideFunction_("lists_insert_from_end",
+["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"(&$list, $at, $value) {"," return array_splice($list, count($list) - $at, 0, $value);","}"]),b+"("+c+", "+e+", "+d+");\n";break;case "RANDOM":c=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_REFERENCE)||"array()";c.match(/^\$\w+$/)?a="":(a=Blockly.PHP.variableDB_.getDistinctName("tmp_list",Blockly.Variables.NAME_TYPE),e=a+" = &"+c+";\n",c=a,a=e);e=Blockly.PHP.variableDB_.getDistinctName("tmp_x",Blockly.Variables.NAME_TYPE);a+=e+" = rand(0, count("+
+c+")-1);\n";if("SET"==b)return a+(c+"["+e+"] = "+d+";\n");if("INSERT"==b)return a+("array_splice("+c+", "+e+", 0, "+d+");\n")}throw"Unhandled combination (lists_setIndex).";};
+Blockly.PHP.lists_getSublist=function(a){var b=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_COMMA)||"array()",c=a.getFieldValue("WHERE1"),d=a.getFieldValue("WHERE2");if("FIRST"!=c||"LAST"!=d)if(b.match(/^\$\w+$/)||"FROM_END"!=c&&"FROM_START"==d){switch(c){case "FROM_START":var e=Blockly.PHP.getAdjusted(a,"AT1");break;case "FROM_END":e=Blockly.PHP.getAdjusted(a,"AT1",1,!1,Blockly.PHP.ORDER_SUBTRACTION);e="count("+b+") - "+e;break;case "FIRST":e="0";break;default:throw"Unhandled option (lists_getSublist).";
+}switch(d){case "FROM_START":a=Blockly.PHP.getAdjusted(a,"AT2",0,!1,Blockly.PHP.ORDER_SUBTRACTION);c=a+" - ";c=Blockly.isNumber(String(e))||String(e).match(/^\(.+\)$/)?c+e:c+("("+e+")");c+=" + 1";break;case "FROM_END":a=Blockly.PHP.getAdjusted(a,"AT2",0,!1,Blockly.PHP.ORDER_SUBTRACTION);c="count("+b+") - "+a+" - ";c=Blockly.isNumber(String(e))||String(e).match(/^\(.+\)$/)?c+e:c+("("+e+")");break;case "LAST":c="count("+b+") - ";c=Blockly.isNumber(String(e))||String(e).match(/^\(.+\)$/)?c+e:c+("("+
+e+")");break;default:throw"Unhandled option (lists_getSublist).";}b="array_slice("+b+", "+e+", "+c+")"}else e=Blockly.PHP.getAdjusted(a,"AT1"),a=Blockly.PHP.getAdjusted(a,"AT2"),b=Blockly.PHP.provideFunction_("lists_get_sublist",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($list, $where1, $at1, $where2, $at2) {"," if ($where1 == 'FROM_END') {"," $at1 = count($list) - 1 - $at1;"," } else if ($where1 == 'FIRST') {"," $at1 = 0;"," } else if ($where1 != 'FROM_START'){"," throw new Exception('Unhandled option (lists_get_sublist).');",
+" }"," $length = 0;"," if ($where2 == 'FROM_START') {"," $length = $at2 - $at1 + 1;"," } else if ($where2 == 'FROM_END') {"," $length = count($list) - $at1 - $at2;"," } else if ($where2 == 'LAST') {"," $length = count($list) - $at1;"," } else {"," throw new Exception('Unhandled option (lists_get_sublist).');"," }"," return array_slice($list, $at1, $length);","}"])+"("+b+", '"+c+"', "+e+", '"+d+"', "+a+")";return[b,Blockly.PHP.ORDER_FUNCTION_CALL]};
+Blockly.PHP.lists_sort=function(a){var b=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_COMMA)||"array()",c="1"===a.getFieldValue("DIRECTION")?1:-1;a=a.getFieldValue("TYPE");return[Blockly.PHP.provideFunction_("lists_sort",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($list, $type, $direction) {"," $sortCmpFuncs = array(",' "NUMERIC" => "strnatcasecmp",',' "TEXT" => "strcmp",',' "IGNORE_CASE" => "strcasecmp"'," );"," $sortCmp = $sortCmpFuncs[$type];"," $list2 = $list;"," usort($list2, $sortCmp);",
+" if ($direction == -1) {"," $list2 = array_reverse($list2);"," }"," return $list2;","}"])+"("+b+', "'+a+'", '+c+")",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.lists_split=function(a){var b=Blockly.PHP.valueToCode(a,"INPUT",Blockly.PHP.ORDER_COMMA),c=Blockly.PHP.valueToCode(a,"DELIM",Blockly.PHP.ORDER_COMMA)||"''";a=a.getFieldValue("MODE");if("SPLIT"==a)b||(b="''"),a="explode";else if("JOIN"==a)b||(b="array()"),a="implode";else throw"Unknown mode: "+a;return[a+"("+c+", "+b+")",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.logic={};Blockly.PHP.controls_if=function(a){for(var b=0,c=Blockly.PHP.valueToCode(a,"IF"+b,Blockly.PHP.ORDER_NONE)||"false",d=Blockly.PHP.statementToCode(a,"DO"+b),e="if ("+c+") {\n"+d+"}",b=1;b<=a.elseifCount_;b++)c=Blockly.PHP.valueToCode(a,"IF"+b,Blockly.PHP.ORDER_NONE)||"false",d=Blockly.PHP.statementToCode(a,"DO"+b),e+=" else if ("+c+") {\n"+d+"}";a.elseCount_&&(d=Blockly.PHP.statementToCode(a,"ELSE"),e+=" else {\n"+d+"}");return e+"\n"};
Blockly.PHP.logic_compare=function(a){var b={EQ:"==",NEQ:"!=",LT:"<",LTE:"<=",GT:">",GTE:">="}[a.getFieldValue("OP")],c="=="==b||"!="==b?Blockly.PHP.ORDER_EQUALITY:Blockly.PHP.ORDER_RELATIONAL,d=Blockly.PHP.valueToCode(a,"A",c)||"0";a=Blockly.PHP.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]};
Blockly.PHP.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"&&":"||",c="&&"==b?Blockly.PHP.ORDER_LOGICAL_AND:Blockly.PHP.ORDER_LOGICAL_OR,d=Blockly.PHP.valueToCode(a,"A",c);a=Blockly.PHP.valueToCode(a,"B",c);if(d||a){var e="&&"==b?"true":"false";d||(d=e);a||(a=e)}else a=d="false";return[d+" "+b+" "+a,c]};Blockly.PHP.logic_negate=function(a){var b=Blockly.PHP.ORDER_LOGICAL_NOT;return["!"+(Blockly.PHP.valueToCode(a,"BOOL",b)||"true"),b]};
Blockly.PHP.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"true":"false",Blockly.PHP.ORDER_ATOMIC]};Blockly.PHP.logic_null=function(a){return["null",Blockly.PHP.ORDER_ATOMIC]};Blockly.PHP.logic_ternary=function(a){var b=Blockly.PHP.valueToCode(a,"IF",Blockly.PHP.ORDER_CONDITIONAL)||"false",c=Blockly.PHP.valueToCode(a,"THEN",Blockly.PHP.ORDER_CONDITIONAL)||"null";a=Blockly.PHP.valueToCode(a,"ELSE",Blockly.PHP.ORDER_CONDITIONAL)||"null";return[b+" ? "+c+" : "+a,Blockly.PHP.ORDER_CONDITIONAL]};Blockly.PHP.loops={};
@@ -44,7 +50,7 @@ a="for ("+b+" = "+c+"; "+b+(f?" <= ":" >= ")+d+"; "+b;b=Math.abs(parseFloat(e));
a+=d+" = ",a=Blockly.isNumber(e)?a+(Math.abs(e)+";\n"):a+("abs("+e+");\n"),a=a+("if ("+f+" > "+c+") {\n")+(Blockly.PHP.INDENT+d+" = -"+d+";\n"),a+="}\n",a+="for ("+b+" = "+f+"; "+d+" >= 0 ? "+b+" <= "+c+" : "+b+" >= "+c+"; "+b+" += "+d+") {\n"+g+"}\n";return a};
Blockly.PHP.controls_forEach=function(a){var b=Blockly.PHP.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_ASSIGNMENT)||"[]",d=Blockly.PHP.statementToCode(a,"DO"),d=Blockly.PHP.addLoopTrap(d,a.id);return""+("foreach ("+c+" as "+b+") {\n"+d+"}\n")};
Blockly.PHP.controls_flow_statements=function(a){switch(a.getFieldValue("FLOW")){case "BREAK":return"break;\n";case "CONTINUE":return"continue;\n"}throw"Unknown flow statement.";};Blockly.PHP.math={};Blockly.PHP.math_number=function(a){a=parseFloat(a.getFieldValue("NUM"));Infinity==a?a="INF":-Infinity==a&&(a="-INF");return[a,Blockly.PHP.ORDER_ATOMIC]};
-Blockly.PHP.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.PHP.ORDER_ADDITION],MINUS:[" - ",Blockly.PHP.ORDER_SUBTRACTION],MULTIPLY:[" * ",Blockly.PHP.ORDER_MULTIPLICATION],DIVIDE:[" / ",Blockly.PHP.ORDER_DIVISION],POWER:[null,Blockly.PHP.ORDER_COMMA]}[a.getFieldValue("OP")],c=b[0],b=b[1],d=Blockly.PHP.valueToCode(a,"A",b)||"0";a=Blockly.PHP.valueToCode(a,"B",b)||"0";return c?[d+c+a,b]:["pow("+d+", "+a+")",Blockly.PHP.ORDER_FUNCTION_CALL]};
+Blockly.PHP.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.PHP.ORDER_ADDITION],MINUS:[" - ",Blockly.PHP.ORDER_SUBTRACTION],MULTIPLY:[" * ",Blockly.PHP.ORDER_MULTIPLICATION],DIVIDE:[" / ",Blockly.PHP.ORDER_DIVISION],POWER:[" ** ",Blockly.PHP.ORDER_POWER]}[a.getFieldValue("OP")],c=b[0],b=b[1],d=Blockly.PHP.valueToCode(a,"A",b)||"0";a=Blockly.PHP.valueToCode(a,"B",b)||"0";return[d+c+a,b]};
Blockly.PHP.math_single=function(a){var b=a.getFieldValue("OP"),c;if("NEG"==b)return a=Blockly.PHP.valueToCode(a,"NUM",Blockly.PHP.ORDER_UNARY_NEGATION)||"0","-"==a[0]&&(a=" "+a),["-"+a,Blockly.PHP.ORDER_UNARY_NEGATION];a="SIN"==b||"COS"==b||"TAN"==b?Blockly.PHP.valueToCode(a,"NUM",Blockly.PHP.ORDER_DIVISION)||"0":Blockly.PHP.valueToCode(a,"NUM",Blockly.PHP.ORDER_NONE)||"0";switch(b){case "ABS":c="abs("+a+")";break;case "ROOT":c="sqrt("+a+")";break;case "LN":c="log("+a+")";break;case "EXP":c="exp("+
a+")";break;case "POW10":c="pow(10,"+a+")";break;case "ROUND":c="round("+a+")";break;case "ROUNDUP":c="ceil("+a+")";break;case "ROUNDDOWN":c="floor("+a+")";break;case "SIN":c="sin("+a+" / 180 * pi())";break;case "COS":c="cos("+a+" / 180 * pi())";break;case "TAN":c="tan("+a+" / 180 * pi())"}if(c)return[c,Blockly.PHP.ORDER_FUNCTION_CALL];switch(b){case "LOG10":c="log("+a+") / log(10)";break;case "ASIN":c="asin("+a+") / pi() * 180";break;case "ACOS":c="acos("+a+") / pi() * 180";break;case "ATAN":c="atan("+
a+") / pi() * 180";break;default:throw"Unknown math operator: "+b;}return[c,Blockly.PHP.ORDER_DIVISION]};Blockly.PHP.math_constant=function(a){return{PI:["M_PI",Blockly.PHP.ORDER_ATOMIC],E:["M_E",Blockly.PHP.ORDER_ATOMIC],GOLDEN_RATIO:["(1 + sqrt(5)) / 2",Blockly.PHP.ORDER_DIVISION],SQRT2:["M_SQRT2",Blockly.PHP.ORDER_ATOMIC],SQRT1_2:["M_SQRT1_2",Blockly.PHP.ORDER_ATOMIC],INFINITY:["INF",Blockly.PHP.ORDER_ATOMIC]}[a.getFieldValue("CONSTANT")]};
@@ -53,28 +59,26 @@ Blockly.PHP.math_number_property=function(a){var b=Blockly.PHP.valueToCode(a,"NU
b+" > 0";break;case "NEGATIVE":d=b+" < 0";break;case "DIVISIBLE_BY":a=Blockly.PHP.valueToCode(a,"DIVISOR",Blockly.PHP.ORDER_MODULUS)||"0",d=b+" % "+a+" == 0"}return[d,Blockly.PHP.ORDER_EQUALITY]};Blockly.PHP.math_change=function(a){var b=Blockly.PHP.valueToCode(a,"DELTA",Blockly.PHP.ORDER_ADDITION)||"0";return Blockly.PHP.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE)+" += "+b+";\n"};Blockly.PHP.math_round=Blockly.PHP.math_single;Blockly.PHP.math_trig=Blockly.PHP.math_single;
Blockly.PHP.math_on_list=function(a){var b=a.getFieldValue("OP");switch(b){case "SUM":a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_FUNCTION_CALL)||"array()";a="array_sum("+a+")";break;case "MIN":a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_FUNCTION_CALL)||"array()";a="min("+a+")";break;case "MAX":a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_FUNCTION_CALL)||"array()";a="max("+a+")";break;case "AVERAGE":b=Blockly.PHP.provideFunction_("math_mean",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+
"($myList) {"," return array_sum($myList) / count($myList);","}"]);a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_NONE)||"array()";a=b+"("+a+")";break;case "MEDIAN":b=Blockly.PHP.provideFunction_("math_median",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($arr) {"," sort($arr,SORT_NUMERIC);"," return (count($arr) % 2) ? $arr[floor(count($arr)/2)] : "," ($arr[floor(count($arr)/2)] + $arr[floor(count($arr)/2) - 1]) / 2;","}"]);a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_NONE)||
-"[]";a=b+"("+a+")";break;case "MODE":b=Blockly.PHP.provideFunction_("math_modes",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($values) {"," $v = array_count_values($values);"," arsort($v);"," foreach($v as $k => $v){$total = $k; break;}"," return array($total);","}"]);a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_NONE)||"[]";a=b+"("+a+")";break;case "STD_DEV":b=Blockly.PHP.provideFunction_("math_standard_deviation",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($numbers) {",
-" $n = count($numbers);"," if (!$n) return null;"," $mean = array_sum($numbers) / count($numbers);"," foreach($numbers as $key => $num) $devs[$key] = pow($num - $mean, 2);"," return sqrt(array_sum($devs) / (count($devs) - 1));","}"]);a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_NONE)||"[]";a=b+"("+a+")";break;case "RANDOM":b=Blockly.PHP.provideFunction_("math_random_list",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($list) {"," $x = rand(0, count($list)-1);"," return $list[$x];",
-"}"]);a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_NONE)||"[]";a=b+"("+a+")";break;default:throw"Unknown operator: "+b;}return[a,Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.math_modulo=function(a){var b=Blockly.PHP.valueToCode(a,"DIVIDEND",Blockly.PHP.ORDER_MODULUS)||"0";a=Blockly.PHP.valueToCode(a,"DIVISOR",Blockly.PHP.ORDER_MODULUS)||"0";return[b+" % "+a,Blockly.PHP.ORDER_MODULUS]};
+"[]";a=b+"("+a+")";break;case "MODE":b=Blockly.PHP.provideFunction_("math_modes",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($values) {"," if (empty($values)) return array();"," $counts = array_count_values($values);"," arsort($counts); // Sort counts in descending order"," $modes = array_keys($counts, current($counts), true);"," return $modes;","}"]);a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_NONE)||"[]";a=b+"("+a+")";break;case "STD_DEV":b=Blockly.PHP.provideFunction_("math_standard_deviation",
+["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($numbers) {"," $n = count($numbers);"," if (!$n) return null;"," $mean = array_sum($numbers) / count($numbers);"," foreach($numbers as $key => $num) $devs[$key] = pow($num - $mean, 2);"," return sqrt(array_sum($devs) / (count($devs) - 1));","}"]);a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_NONE)||"[]";a=b+"("+a+")";break;case "RANDOM":b=Blockly.PHP.provideFunction_("math_random_list",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+
+"($list) {"," $x = rand(0, count($list)-1);"," return $list[$x];","}"]);a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_NONE)||"[]";a=b+"("+a+")";break;default:throw"Unknown operator: "+b;}return[a,Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.math_modulo=function(a){var b=Blockly.PHP.valueToCode(a,"DIVIDEND",Blockly.PHP.ORDER_MODULUS)||"0";a=Blockly.PHP.valueToCode(a,"DIVISOR",Blockly.PHP.ORDER_MODULUS)||"0";return[b+" % "+a,Blockly.PHP.ORDER_MODULUS]};
Blockly.PHP.math_constrain=function(a){var b=Blockly.PHP.valueToCode(a,"VALUE",Blockly.PHP.ORDER_COMMA)||"0",c=Blockly.PHP.valueToCode(a,"LOW",Blockly.PHP.ORDER_COMMA)||"0";a=Blockly.PHP.valueToCode(a,"HIGH",Blockly.PHP.ORDER_COMMA)||"Infinity";return["min(max("+b+", "+c+"), "+a+")",Blockly.PHP.ORDER_FUNCTION_CALL]};
Blockly.PHP.math_random_int=function(a){var b=Blockly.PHP.valueToCode(a,"FROM",Blockly.PHP.ORDER_COMMA)||"0";a=Blockly.PHP.valueToCode(a,"TO",Blockly.PHP.ORDER_COMMA)||"0";return[Blockly.PHP.provideFunction_("math_random_int",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($a, $b) {"," if ($a > $b) {"," return rand($b, $a);"," }"," return rand($a, $b);","}"])+"("+b+", "+a+")",Blockly.PHP.ORDER_FUNCTION_CALL]};
Blockly.PHP.math_random_float=function(a){return["(float)rand()/(float)getrandmax()",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.procedures={};
-Blockly.PHP.procedures_defreturn=function(a){for(var b=Blockly.Variables.allVariables(a),c=b.length-1;0<=c;c--){var d=b[c];-1==a.arguments_.indexOf(d)?b[c]=Blockly.PHP.variableDB_.getName(d,Blockly.Variables.NAME_TYPE):b.splice(c,1)}b=b.length?" global "+b.join(", ")+";\n":"";c=Blockly.PHP.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE);d=Blockly.PHP.statementToCode(a,"STACK");Blockly.PHP.STATEMENT_PREFIX&&(d=Blockly.PHP.prefixLines(Blockly.PHP.STATEMENT_PREFIX.replace(/%1/g,"'"+
-a.id+"'"),Blockly.PHP.INDENT)+d);Blockly.PHP.INFINITE_LOOP_TRAP&&(d=Blockly.PHP.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+d);var e=Blockly.PHP.valueToCode(a,"RETURN",Blockly.PHP.ORDER_NONE)||"";e&&(e=" return "+e+";\n");for(var g=[],f=0;fc?"int("+a+" - "+-c+")":"int("+a+")",d&&(a="-"+a));return a};Blockly.Python.colour={};Blockly.Python.colour_picker=function(a){return["'"+a.getFieldValue("COLOUR")+"'",Blockly.Python.ORDER_ATOMIC]};Blockly.Python.colour_random=function(a){Blockly.Python.definitions_.import_random="import random";return["'#%06x' % random.randint(0, 2**24 - 1)",Blockly.Python.ORDER_FUNCTION_CALL]};
Blockly.Python.colour_rgb=function(a){var b=Blockly.Python.provideFunction_("colour_rgb",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(r, g, b):"," r = round(min(100, max(0, r)) * 2.55)"," g = round(min(100, max(0, g)) * 2.55)"," b = round(min(100, max(0, b)) * 2.55)"," return '#%02x%02x%02x' % (r, g, b)"]),c=Blockly.Python.valueToCode(a,"RED",Blockly.Python.ORDER_NONE)||0,d=Blockly.Python.valueToCode(a,"GREEN",Blockly.Python.ORDER_NONE)||0;a=Blockly.Python.valueToCode(a,"BLUE",Blockly.Python.ORDER_NONE)||
0;return[b+"("+c+", "+d+", "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};
Blockly.Python.colour_blend=function(a){var b=Blockly.Python.provideFunction_("colour_blend",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(colour1, colour2, ratio):"," r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16)"," g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16)"," b1, b2 = int(colour1[5:7], 16), int(colour2[5:7], 16)"," ratio = min(1, max(0, ratio))"," r = round(r1 * (1 - ratio) + r2 * ratio)"," g = round(g1 * (1 - ratio) + g2 * ratio)"," b = round(b1 * (1 - ratio) + b2 * ratio)",
-" return '#%02x%02x%02x' % (r, g, b)"]),c=Blockly.Python.valueToCode(a,"COLOUR1",Blockly.Python.ORDER_NONE)||"'#000000'",d=Blockly.Python.valueToCode(a,"COLOUR2",Blockly.Python.ORDER_NONE)||"'#000000'";a=Blockly.Python.valueToCode(a,"RATIO",Blockly.Python.ORDER_NONE)||0;return[b+"("+c+", "+d+", "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.lists={};Blockly.Python.lists_create_empty=function(a){return["[]",Blockly.Python.ORDER_ATOMIC]};Blockly.Python.lists_create_with=function(a){for(var b=Array(a.itemCount_),c=0;c",GTE:">="}[a.getFieldValue("OP")],c=Blockly.Python.ORDER_RELATIONAL,d=Blockly.Python.valueToCode(a,"A",c)||"0";a=Blockly.Python.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]};
@@ -38,10 +38,10 @@ Blockly.Python.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"a
Blockly.Python.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"True":"False",Blockly.Python.ORDER_ATOMIC]};Blockly.Python.logic_null=function(a){return["None",Blockly.Python.ORDER_ATOMIC]};
Blockly.Python.logic_ternary=function(a){var b=Blockly.Python.valueToCode(a,"IF",Blockly.Python.ORDER_CONDITIONAL)||"False",c=Blockly.Python.valueToCode(a,"THEN",Blockly.Python.ORDER_CONDITIONAL)||"None";a=Blockly.Python.valueToCode(a,"ELSE",Blockly.Python.ORDER_CONDITIONAL)||"None";return[c+" if "+b+" else "+a,Blockly.Python.ORDER_CONDITIONAL]};Blockly.Python.loops={};Blockly.Python.controls_repeat_ext=function(a){var b=a.getField("TIMES")?String(parseInt(a.getFieldValue("TIMES"),10)):Blockly.Python.valueToCode(a,"TIMES",Blockly.Python.ORDER_NONE)||"0",b=Blockly.isNumber(b)?parseInt(b,10):"int("+b+")",c=Blockly.Python.statementToCode(a,"DO"),c=Blockly.Python.addLoopTrap(c,a.id)||Blockly.Python.PASS;return"for "+Blockly.Python.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE)+" in range("+b+"):\n"+c};
Blockly.Python.controls_repeat=Blockly.Python.controls_repeat_ext;Blockly.Python.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.Python.valueToCode(a,"BOOL",b?Blockly.Python.ORDER_LOGICAL_NOT:Blockly.Python.ORDER_NONE)||"False",d=Blockly.Python.statementToCode(a,"DO"),d=Blockly.Python.addLoopTrap(d,a.id)||Blockly.Python.PASS;b&&(c="not "+c);return"while "+c+":\n"+d};
-Blockly.Python.controls_for=function(a){var b=Blockly.Python.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Python.valueToCode(a,"FROM",Blockly.Python.ORDER_NONE)||"0",d=Blockly.Python.valueToCode(a,"TO",Blockly.Python.ORDER_NONE)||"0",e=Blockly.Python.valueToCode(a,"BY",Blockly.Python.ORDER_NONE)||"1",g=Blockly.Python.statementToCode(a,"DO"),g=Blockly.Python.addLoopTrap(g,a.id)||Blockly.Python.PASS,f="",h=function(){return Blockly.Python.provideFunction_("upRange",
+Blockly.Python.controls_for=function(a){var b=Blockly.Python.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Python.valueToCode(a,"FROM",Blockly.Python.ORDER_NONE)||"0",d=Blockly.Python.valueToCode(a,"TO",Blockly.Python.ORDER_NONE)||"0",e=Blockly.Python.valueToCode(a,"BY",Blockly.Python.ORDER_NONE)||"1",f=Blockly.Python.statementToCode(a,"DO"),f=Blockly.Python.addLoopTrap(f,a.id)||Blockly.Python.PASS,g="",h=function(){return Blockly.Python.provideFunction_("upRange",
["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(start, stop, step):"," while start <= stop:"," yield start"," start += abs(step)"])},k=function(){return Blockly.Python.provideFunction_("downRange",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(start, stop, step):"," while start >= stop:"," yield start"," start -= abs(step)"])};a=function(a,b,c){return"("+a+" <= "+b+") and "+h()+"("+a+", "+b+", "+c+") or "+k()+"("+a+", "+b+", "+c+")"};if(Blockly.isNumber(c)&&Blockly.isNumber(d)&&
-Blockly.isNumber(e))c=parseFloat(c),d=parseFloat(d),e=Math.abs(parseFloat(e)),0===c%1&&0===d%1&&0===e%1?(c<=d?(d++,a=0==c&&1==e?d:c+", "+d,1!=e&&(a+=", "+e)):(d--,a=c+", "+d+", -"+e),a="range("+a+")"):(a=ca?Blockly.Python.ORDER_UNARY_SIGN:Blockly.Python.ORDER_ATOMIC;return[a,b]};
Blockly.Python.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.Python.ORDER_ADDITIVE],MINUS:[" - ",Blockly.Python.ORDER_ADDITIVE],MULTIPLY:[" * ",Blockly.Python.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",Blockly.Python.ORDER_MULTIPLICATIVE],POWER:[" ** ",Blockly.Python.ORDER_EXPONENTIATION]}[a.getFieldValue("OP")],c=b[0],b=b[1],d=Blockly.Python.valueToCode(a,"A",b)||"0";a=Blockly.Python.valueToCode(a,"B",b)||"0";return[d+c+a,b]};
Blockly.Python.math_single=function(a){var b=a.getFieldValue("OP"),c;if("NEG"==b)return c=Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_UNARY_SIGN)||"0",["-"+c,Blockly.Python.ORDER_UNARY_SIGN];Blockly.Python.definitions_.import_math="import math";a="SIN"==b||"COS"==b||"TAN"==b?Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_MULTIPLICATIVE)||"0":Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_NONE)||"0";switch(b){case "ABS":c="math.fabs("+a+")";break;case "ROOT":c="math.sqrt("+
@@ -60,20 +60,20 @@ Blockly.Python.math_on_list=function(a){var b=a.getFieldValue("OP");a=Blockly.Py
Blockly.Python.math_modulo=function(a){var b=Blockly.Python.valueToCode(a,"DIVIDEND",Blockly.Python.ORDER_MULTIPLICATIVE)||"0";a=Blockly.Python.valueToCode(a,"DIVISOR",Blockly.Python.ORDER_MULTIPLICATIVE)||"0";return[b+" % "+a,Blockly.Python.ORDER_MULTIPLICATIVE]};
Blockly.Python.math_constrain=function(a){var b=Blockly.Python.valueToCode(a,"VALUE",Blockly.Python.ORDER_NONE)||"0",c=Blockly.Python.valueToCode(a,"LOW",Blockly.Python.ORDER_NONE)||"0";a=Blockly.Python.valueToCode(a,"HIGH",Blockly.Python.ORDER_NONE)||"float('inf')";return["min(max("+b+", "+c+"), "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};
Blockly.Python.math_random_int=function(a){Blockly.Python.definitions_.import_random="import random";var b=Blockly.Python.valueToCode(a,"FROM",Blockly.Python.ORDER_NONE)||"0";a=Blockly.Python.valueToCode(a,"TO",Blockly.Python.ORDER_NONE)||"0";return["random.randint("+b+", "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.math_random_float=function(a){Blockly.Python.definitions_.import_random="import random";return["random.random()",Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.procedures={};
-Blockly.Python.procedures_defreturn=function(a){for(var b=Blockly.Variables.allVariables(a),c=b.length-1;0<=c;c--){var d=b[c];-1==a.arguments_.indexOf(d)?b[c]=Blockly.Python.variableDB_.getName(d,Blockly.Variables.NAME_TYPE):b.splice(c,1)}b=b.length?" global "+b.join(", ")+"\n":"";c=Blockly.Python.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE);d=Blockly.Python.statementToCode(a,"STACK");Blockly.Python.STATEMENT_PREFIX&&(d=Blockly.Python.prefixLines(Blockly.Python.STATEMENT_PREFIX.replace(/%1/g,"'"+
-a.id+"'"),Blockly.Python.INDENT)+d);Blockly.Python.INFINITE_LOOP_TRAP&&(d=Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g,'"'+a.id+'"')+d);var e=Blockly.Python.valueToCode(a,"RETURN",Blockly.Python.ORDER_NONE)||"";e?e=" return "+e+"\n":d||(d=Blockly.Python.PASS);for(var g=[],f=0;ftest colour picker
- static colour
+
+
+ static colour
+
+
#ff6600
@@ -21,7 +25,11 @@
test rgb
- from rgb
+
+
+ from rgb
+
+
@@ -88,7 +96,11 @@
- test name
+
+
+ test name
+
+
@@ -105,7 +117,11 @@
- test name
+
+
+ test name
+
+
@@ -137,7 +153,11 @@
- test name
+
+
+ test name
+
+
TRUE
@@ -192,7 +212,11 @@
test blend
- blend
+
+
+ blend
+
+
diff --git a/tests/generators/functions.xml b/tests/generators/functions.xml
index ce450b11a..b189ed355 100644
--- a/tests/generators/functions.xml
+++ b/tests/generators/functions.xml
@@ -8,7 +8,11 @@
- test recurse
+
+
+ test recurse
+
+
@@ -53,7 +57,11 @@
- procedure with global
+
+
+ procedure with global
+
+
proc z
@@ -84,7 +92,11 @@
- procedure no return
+
+
+ procedure no return
+
+
TRUE
@@ -111,7 +123,11 @@
- procedure return
+
+
+ procedure return
+
+
FALSE
@@ -192,7 +208,11 @@
test function
- function with arguments
+
+
+ function with arguments
+
+
@@ -218,7 +238,11 @@
- function with side effect
+
+
+ function with side effect
+
+
func z
@@ -247,7 +271,11 @@
- function with global
+
+
+ function with global
+
+
@@ -267,7 +295,11 @@
- function with scope
+
+
+ function with scope
+
+
func a
@@ -280,7 +312,11 @@
- function return
+
+
+ function return
+
+
TRUE
@@ -296,7 +332,11 @@
- function no return
+
+
+ function no return
+
+
FALSE
diff --git a/tests/generators/index.html b/tests/generators/index.html
index 5ae75e553..a5003ca51 100644
--- a/tests/generators/index.html
+++ b/tests/generators/index.html
@@ -153,17 +153,23 @@ function toXml() {
}
function toJavaScript() {
+ var oneBasedIndexing = document.getElementById('indexing').checked;
+ Blockly.JavaScript.ONE_BASED_INDEXING = oneBasedIndexing;
var code = '\'use strict\';\n\n'
code += Blockly.JavaScript.workspaceToCode(workspace);
setOutput(code);
}
function toPython() {
+ var oneBasedIndexing = document.getElementById('indexing').checked;
+ Blockly.Python.ONE_BASED_INDEXING = oneBasedIndexing;
var code = Blockly.Python.workspaceToCode(workspace);
setOutput(code);
}
function toPhp() {
+ var oneBasedIndexing = document.getElementById('indexing').checked;
+ Blockly.PHP.ONE_BASED_INDEXING = oneBasedIndexing;
var code = Blockly.PHP.workspaceToCode(workspace);
setOutput(code);
}
@@ -174,6 +180,8 @@ function toLua() {
}
function toDart() {
+ var oneBasedIndexing = document.getElementById('indexing').checked;
+ Blockly.Dart.ONE_BASED_INDEXING = oneBasedIndexing;
var code = Blockly.Dart.workspaceToCode(workspace);
setOutput(code);
}
@@ -212,9 +220,22 @@ h1 {
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -305,6 +326,10 @@ h1 {
+
+ Generate with one-based indexing
+
+
Generate:
diff --git a/tests/generators/lists.xml b/tests/generators/lists.xml
index d803a14ad..88e4946b5 100644
--- a/tests/generators/lists.xml
+++ b/tests/generators/lists.xml
@@ -1,934 +1,65 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- test create
- Describe this function...
-
-
- test create empty
-
-
-
-
-
-
-
-
-
-
- test create items
-
-
-
-
-
- TRUE
-
-
-
-
- love
-
-
-
-
-
-
-
-
-
- TRUE
-
-
-
-
- love
-
-
-
-
-
-
- test create repeated
-
-
-
-
- Eject
-
-
-
-
- 3
-
-
-
-
-
-
-
-
-
- Eject
-
-
-
-
- Eject
-
-
-
-
- Eject
-
-
-
-
-
-
-
-
-
-
-
-
- test empty
- Describe this function...
-
-
- not empty
- FALSE
-
-
-
-
-
-
-
- 0
-
-
-
-
-
-
-
-
- empty
- TRUE
-
-
-
-
-
-
-
-
-
-
-
-
-
- test length
- Describe this function...
-
-
- zero length
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
- one length
-
-
-
-
-
-
-
- cat
-
-
-
-
-
-
-
-
- 1
-
-
-
-
- three length
-
-
-
-
-
-
-
- cat
-
-
-
-
- TRUE
-
-
-
-
-
-
-
-
-
-
-
- 3
-
-
-
-
-
-
-
-
-
-
- test find
- Describe this function...
-
-
- find first
-
-
- FIRST
-
-
-
-
-
- Alice
-
-
-
-
- Eve
-
-
-
-
- Bob
-
-
-
-
- Eve
-
-
-
-
-
-
- Eve
-
-
-
-
-
-
- 2
-
-
-
-
- find last
-
-
- LAST
-
-
-
-
-
- Alice
-
-
-
-
- Eve
-
-
-
-
- Bob
-
-
-
-
- Eve
-
-
-
-
-
-
- Eve
-
-
-
-
-
-
- 4
-
-
-
-
- find none
-
-
- FIRST
-
-
-
-
-
- Alice
-
-
-
-
- Bob
-
-
-
-
- Carol
-
-
-
-
- Dave
-
-
-
-
-
-
- Eve
-
-
-
-
-
-
- 0
-
-
-
-
-
-
-
-
-
-
- test get
- Describe this function...
-
-
- list
-
-
-
-
-
- Kirk
-
-
-
-
- Spock
-
-
-
-
- McCoy
-
-
-
-
-
-
- get first
-
-
-
- GET
- FIRST
-
-
- list
-
-
-
-
-
-
- Kirk
-
-
-
-
- get last
-
-
-
- GET
- LAST
-
-
- list
-
-
-
-
-
-
- McCoy
-
-
-
-
- get random
- TRUE
-
-
-
- POSITIVE
-
-
- FIRST
-
-
- list
-
-
-
-
-
- GET
- RANDOM
-
-
- list
-
-
-
-
-
-
-
-
-
-
- get #
-
-
-
- GET
- FROM_START
-
-
- list
-
-
-
-
- 2
-
-
-
-
-
-
- Spock
-
-
-
-
- get #-end
-
-
-
- GET
- FROM_END
-
-
- list
-
-
-
-
- 3
-
-
-
-
-
-
- Kirk
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- test get remove
- Describe this function...
-
-
- list
-
-
-
-
-
- Kirk
-
-
-
-
- Spock
-
-
-
-
- McCoy
-
-
-
-
-
-
- getremove first
-
-
-
- GET_REMOVE
- FIRST
-
-
- list
-
-
-
-
-
-
- Kirk
-
-
-
-
- getremove first list
-
-
- list
-
-
-
-
-
-
-
- Spock
-
-
-
-
- McCoy
-
-
-
-
-
-
- list
-
-
-
-
-
- Kirk
-
-
-
-
- Spock
-
-
-
-
- McCoy
-
-
-
-
-
-
- getremove last
-
-
-
- GET_REMOVE
- LAST
-
-
- list
-
-
-
-
-
-
- McCoy
-
-
-
-
- getremove last list
-
-
- list
-
-
-
-
-
-
-
- Kirk
-
-
-
-
- Spock
-
-
-
-
-
-
- list
-
-
-
-
-
- Kirk
-
-
-
-
- Spock
-
-
-
-
- McCoy
-
-
-
-
-
-
- getremove random
- TRUE
-
-
- EQ
-
-
- FIRST
-
-
- list
-
-
-
-
-
- GET_REMOVE
- RANDOM
-
-
- list
-
-
-
-
-
-
-
-
- 0
-
-
-
-
-
-
- getremove random list
-
-
-
-
- list
-
-
-
-
-
-
- 2
-
-
-
-
- list
-
-
-
-
-
- Kirk
-
-
-
-
- Spock
-
-
-
-
- McCoy
-
-
-
-
-
-
- getremove #
-
-
-
- GET_REMOVE
- FROM_START
-
-
- list
-
-
-
-
- 2
-
-
-
-
-
-
- Spock
-
-
-
-
- getremove # list
-
-
- list
-
-
-
-
-
-
-
- Kirk
-
-
-
-
- McCoy
-
-
-
-
-
-
- list
-
-
-
-
-
- Kirk
-
-
-
-
- Spock
-
-
-
-
- McCoy
-
-
-
-
-
-
- getremove #-end
-
-
-
- GET_REMOVE
- FROM_END
-
-
- list
-
-
-
-
- 3
-
-
-
-
-
-
- Kirk
-
-
+
-
- getremove #-end list
-
-
- list
-
-
-
-
-
-
-
- Spock
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
- McCoy
-
-
+
-
+
@@ -960,14 +91,2926 @@
-
- test remove
- Describe this function...
+
+
+
+
+ check number of calls
+ Checks that the number of calls is one in order to confirm that a function was only called once.
+
+
+ test name
+
+
+ number of calls
+
+
+
+
+
+
+ test name
+
+
+
+
+ number of calls
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ test create
+ Tests the "create list with" and "create empty list" blocks.
+
+
+
+
+ create empty
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ create items
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+ love
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+ love
+
+
+
+
+
+
+
+
+ create repeated
+
+
+
+
+
+
+ Eject
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+ Eject
+
+
+
+
+ Eject
+
+
+
+
+ Eject
+
+
+
+
+
+
+
+
+ create repeated order
+
+
+
+
+
+
+ Eject
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ Eject
+
+
+
+
+ Eject
+
+
+
+
+ Eject
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get empty list
+ Creates an empty list for use with the empty test.
+
+
+
+
+
+ test empty
+ Tests the "is empty" block.
+
+
+ FALSE
+
+
+ not empty
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ TRUE
+
+
+ empty
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+ empty complex
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+ empty order
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test length
+ Tests the "length" block.
+
+
+
+
+ zero length
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+ one length
+
+
+
+
+
+
+
+
+
+ cat
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+ three length
+
+
+
+
+
+
+
+
+
+ cat
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+ two length order
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+ cat
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+ test find simple
+ Tests the "find" block with a variable.
+
+
+ list
+
+
+
+
+
+ Alice
+
+
+
+
+ Eve
+
+
+
+
+ Bob
+
+
+
+
+ Eve
+
+
+
+
+
+
+
+
+ find first simple
+
+
+
+
+ FIRST
+
+
+ list
+
+
+
+
+ Eve
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ find last simple
+
+
+
+
+ LAST
+
+
+ list
+
+
+
+
+ Eve
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+ find none simple
+
+
+
+
+ FIRST
+
+
+ list
+
+
+
+
+ Dave
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get names
+ Creates a list for use with the find test.
+
+
+ number of calls
+
+
+ 1
+
+
+
+
+
+
+
+
+
+ Alice
+
+
+
+
+ Eve
+
+
+
+
+ Bob
+
+
+
+
+ Eve
+
+
+
+
+
+
+ test find complex
+ Tests the "find" block with a function call.
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ find first complex
+
+
+
+
+ FIRST
+
+
+
+
+
+
+
+ Eve
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+ find first complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ find first order complex
+
+
+
+
+ FIRST
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Eve
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+ find first order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ find last complex
+
+
+
+
+ LAST
+
+
+
+
+
+
+
+ Eve
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ find last complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ find last order complex
+
+
+
+
+ LAST
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Eve
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ find last order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ find none complex
+
+
+
+
+ FIRST
+
+
+
+
+
+
+
+ Dave
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+ find none complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ find none order complex
+
+
+
+
+ FIRST
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dave
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+ find none order complex
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test get simple
+ Tests the "get" block with a variable.
list
-
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+ get first simple
+
+
+
+
+
+ GET
+ FIRST
+
+
+ list
+
+
+
+
+
+
+ Kirk
+
+
+
+
+
+
+ get last simple
+
+
+
+
+
+ GET
+ LAST
+
+
+ list
+
+
+
+
+
+
+ McCoy
+
+
+
+
+ TRUE
+
+
+ get random simple
+
+
+
+
+ GT
+
+
+ FIRST
+
+
+ list
+
+
+
+
+
+ GET
+ RANDOM
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+ get # simple
+
+
+
+
+
+ GET
+ FROM_START
+
+
+ list
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Spock
+
+
+
+
+
+
+ get # order simple
+
+
+
+
+
+ GET
+ FROM_START
+
+
+ list
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Spock
+
+
+
+
+
+
+ get #-end simple
+
+
+
+
+
+ GET
+ FROM_END
+
+
+ list
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+
+
+ get #-end order simple
+
+
+
+
+
+ GET
+ FROM_END
+ The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index.
+
+
+ list
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get star wars
+ Creates a list for use with the get test.
+
+
+ number of calls
+
+
+ 1
+
+
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ test get complex
+ Tests the "get" block with a function call.
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get first complex
+
+
+
+
+
+ GET
+ FIRST
+
+
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+
+
+
+
+
+ get first complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get first order complex
+
+
+
+
+
+ GET
+ FIRST
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+
+
+
+
+
+ get first order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get last complex
+
+
+
+
+
+ GET
+ LAST
+
+
+
+
+
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+
+ get last complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get last order complex
+
+
+
+
+
+ GET
+ LAST
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+
+ get last order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+ TRUE
+
+
+ get random complex
+
+
+
+
+ GT
+
+
+ FIRST
+
+
+ list
+
+
+
+
+
+ GET
+ RANDOM
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get random complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+ TRUE
+
+
+ get random order complex
+
+
+
+
+ GT
+
+
+ FIRST
+
+
+ list
+
+
+
+
+
+ GET
+ RANDOM
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get random order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get # complex
+
+
+
+
+
+ GET
+ FROM_START
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Spock
+
+
+
+
+
+
+
+
+
+ get # complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get # order complex
+
+
+
+
+
+ GET
+ FROM_START
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Spock
+
+
+
+
+
+
+
+
+
+ get # order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get #-end complex
+
+
+
+
+
+ GET
+ FROM_END
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+
+
+
+
+
+ get #-end complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get #-end order complex
+
+
+
+
+
+ GET
+ FROM_END
+ The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index.
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+
+
+
+
+
+ get #-end order complex
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test getRemove
+ Tests the "get and remove" block.
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+ getremove first
+
+
+
+
+
+ GET_REMOVE
+ FIRST
+
+
+ list
+
+
+
+
+
+
+ Kirk
+
+
+
+
+
+
+ getremove first list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+ getremove first order
+
+
+
+
+
+ GET_REMOVE
+ FIRST
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+
+
+ getremove first order list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+ getremove last
+
+
+
+
+
+ GET_REMOVE
+ LAST
+
+
+ list
+
+
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ getremove last list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+ getremove last order
+
+
+
+
+
+ GET_REMOVE
+ LAST
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ getremove last order list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ TRUE
+
+
+ getremove random
+
+
+
+
+ EQ
+
+
+ FIRST
+
+
+ list
+
+
+
+
+
+ GET_REMOVE
+ RANDOM
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+ getremove random list
+
+
+
+
+
+
+ list
+
+
+
+
+
+
+ 2
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ TRUE
+
+
+ getremove random order
+
+
+
+
+ EQ
+
+
+ FIRST
+
+
+ list
+
+
+
+
+
+ GET_REMOVE
+ RANDOM
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+ getremove random order list
+
+
+
+
+
+
+ list
+
+
+
+
+
+
+ 2
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+ getremove #
+
+
+
+
+
+ GET_REMOVE
+ FROM_START
+
+
+ list
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Spock
+
+
+
+
+
+
+ getremove # list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+ getremove # order
+
+
+
+
+
+ GET_REMOVE
+ FROM_START
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Spock
+
+
+
+
+
+
+ getremove # order list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+ getremove #-end
+
+
+
+
+
+ GET_REMOVE
+ FROM_END
+
+
+ list
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+
+
+ getremove #-end list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+ getremove #-end order
+
+
+
+
+
+ GET_REMOVE
+ FROM_END
+ The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index.
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+
+
+ getremove #-end order list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test remove
+ Tests the "remove" block.
+
+
+ list
+
+
@@ -998,14 +3041,18 @@
- remove first list
+
+
+ remove first list
+
+
list
-
+
@@ -1023,7 +3070,7 @@
list
-
+
@@ -1046,31 +3093,47 @@
REMOVE
- LAST
+ FIRST
-
- list
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
- remove last list
+
+
+ remove first order list
+
+
list
-
+
- Kirk
+ Spock
- Spock
+ McCoy
@@ -1079,7 +3142,7 @@
list
-
+
@@ -1102,7 +3165,7 @@
REMOVE
- RANDOM
+ LAST
list
@@ -1110,26 +3173,36 @@
- remove random list
+
+
+ remove last list
+
+
-
-
-
- list
-
-
+
+ list
-
- 2
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
list
-
+
@@ -1150,29 +3223,40 @@
-
+
REMOVE
- FROM_START
+ LAST
-
- list
-
-
-
-
- 2
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
- remove # list
+
+
+ remove last order list
+
+
list
-
+
@@ -1181,7 +3265,7 @@
- McCoy
+ Spock
@@ -1190,7 +3274,7 @@
list
-
+
@@ -1211,42 +3295,454 @@
-
+
REMOVE
- FROM_END
+ RANDOM
list
-
-
- 3
-
-
- remove #-end list
+
+
+ remove random list
+
+
-
- list
+
+
+
+ list
+
+
-
-
-
-
- Spock
-
-
-
-
- McCoy
-
-
+
+ 2
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+ REMOVE
+ RANDOM
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+
+ remove random order list
+
+
+
+
+
+
+ list
+
+
+
+
+
+
+ 2
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+ REMOVE
+ FROM_START
+
+
+ list
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ remove # list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+ REMOVE
+ FROM_START
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ remove # order list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Kirk
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+ REMOVE
+ FROM_END
+
+
+ list
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ remove #-end list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Kirk
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+ REMOVE
+ FROM_END
+ The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index.
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+ remove #-end order list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Spock
+
+
+
+
+ McCoy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1278,14 +3774,14 @@
-
+
test set
- Describe this function...
+ Tests the "set" block.
- x
+ list
-
+
@@ -1311,7 +3807,7 @@
FIRST
- x
+ list
@@ -1321,14 +3817,18 @@
- set first list
+
+
+ set first list
+
+
- x
+ list
-
+
@@ -1349,9 +3849,9 @@
- x
+ list
-
+
@@ -1374,31 +3874,47 @@
SET
- LAST
+ FIRST
-
- x
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
- Beverly
+ Jean-Luc
- set last list
+
+
+ set first order list
+
+
- x
+ list
-
+
- Picard
+ Jean-Luc
@@ -1408,16 +3924,16 @@
- Beverly
+ Crusher
- x
+ list
-
+
@@ -1440,39 +3956,54 @@
SET
- RANDOM
+ LAST
- x
+ list
- Data
+ Beverly
- set random list
+
+
+ set last list
+
+
-
-
-
- x
+
+ list
+
+
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Beverly
-
-
- 3
-
-
- x
+ list
-
+
@@ -1493,34 +4024,45 @@
-
+
SET
- FROM_START
+ LAST
-
- x
-
-
-
-
- 3
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
- Pulaski
+ Beverly
- set # list
+
+
+ set last order list
+
+
- x
+ list
-
+
@@ -1534,16 +4076,16 @@
- Pulaski
+ Beverly
- x
+ list
-
+
@@ -1564,52 +4106,504 @@
-
+
SET
- FROM_END
+ RANDOM
- x
-
-
-
-
- 1
+ list
- Pulaski
+ Data
- set #-end list
+
+
+ set random list
+
+
-
- x
+
+
+
+ list
+
+
-
-
-
-
- Picard
-
-
-
-
- Riker
-
-
-
-
- Pulaski
-
-
+
+ 3
+
+
+ list
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Crusher
+
+
+
+
+
+
+
+ SET
+ RANDOM
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+ Data
+
+
+
+
+
+
+ set random order list
+
+
+
+
+
+
+ list
+
+
+
+
+
+
+ 3
+
+
+
+
+ list
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Crusher
+
+
+
+
+
+
+
+ SET
+ FROM_START
+
+
+ list
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+ Pulaski
+
+
+
+
+
+
+ set # list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Pulaski
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Crusher
+
+
+
+
+
+
+
+ SET
+ FROM_START
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+ Pulaski
+
+
+
+
+
+
+ set # order list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Pulaski
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Crusher
+
+
+
+
+
+
+
+ SET
+ FROM_END
+
+
+ list
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+ Pulaski
+
+
+
+
+
+
+ set #-end list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Pulaski
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Crusher
+
+
+
+
+
+
+
+ SET
+ FROM_END
+ The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index.
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Pulaski
+
+
+
+
+
+
+ set #-end order list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Picard
+
+
+
+
+ Pulaski
+
+
+
+
+ Crusher
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1641,14 +4635,14 @@
-
+
test insert
- Describe this function...
+ Tests the "insert" block.
- x
+ list
-
+
@@ -1674,7 +4668,7 @@
FIRST
- x
+ list
@@ -1684,14 +4678,18 @@
- insert first list
+
+
+ insert first list
+
+
- x
+ list
-
+
@@ -1717,9 +4715,9 @@
- x
+ list
-
+
@@ -1742,10 +4740,22 @@
INSERT
- LAST
+ FIRST
-
- x
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
@@ -1755,42 +4765,46 @@
- insert last list
+
+
+ insert first order list
+
+
- x
+ list
-
+
- Picard
+ Data
- Riker
+ Picard
- Crusher
+ Riker
- Data
+ Crusher
- x
+ list
-
+
@@ -1813,10 +4827,10 @@
INSERT
- RANDOM
+ LAST
- x
+ list
@@ -1826,26 +4840,46 @@
- insert random list
+
+
+ insert last list
+
+
-
-
-
- x
+
+ list
+
+
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Crusher
+
+
+
+
+ Data
-
-
- 4
-
-
- x
+ list
-
+
@@ -1866,17 +4900,24 @@
-
+
INSERT
- FROM_START
+ LAST
-
- x
-
-
-
-
- 3
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
@@ -1886,14 +4927,18 @@
- insert # list
+
+
+ insert last order list
+
+
- x
+ list
-
+
@@ -1907,21 +4952,21 @@
- Data
+ Crusher
- Crusher
+ Data
- x
+ list
-
+
@@ -1942,17 +4987,12 @@
-
+
INSERT
- FROM_END
+ RANDOM
- x
-
-
-
-
- 1
+ list
@@ -1962,37 +5002,509 @@
- insert #-end list
+
+
+ insert random list
+
+
-
- x
+
+
+
+ list
+
+
-
-
-
-
- Picard
-
-
-
-
- Riker
-
-
-
-
- Data
-
-
-
-
- Crusher
-
-
+
+ 4
+
+
+ list
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Crusher
+
+
+
+
+
+
+
+ INSERT
+ RANDOM
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+ Data
+
+
+
+
+
+
+ insert random order list
+
+
+
+
+
+
+ list
+
+
+
+
+
+
+ 4
+
+
+
+
+ list
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Crusher
+
+
+
+
+
+
+
+ INSERT
+ FROM_START
+
+
+ list
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+ Data
+
+
+
+
+
+
+ insert # list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Data
+
+
+
+
+ Crusher
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Crusher
+
+
+
+
+
+
+
+ INSERT
+ FROM_START
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+ Data
+
+
+
+
+
+
+ insert # order list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Data
+
+
+
+
+ Crusher
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Crusher
+
+
+
+
+
+
+
+ INSERT
+ FROM_END
+
+
+ list
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+ Data
+
+
+
+
+
+
+ insert #-end list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Data
+
+
+
+
+ Crusher
+
+
+
+
+
+
+ list
+
+
+
+
+
+ Picard
+
+
+
+
+ Riker
+
+
+
+
+ Crusher
+
+
+
+
+
+
+
+ INSERT
+ FROM_END
+ The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index.
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Data
+
+
+
+
+
+
+ insert #-end order list
+
+
+
+
+ list
+
+
+
+
+
+
+
+ Picard
+
+
+
+
+ Data
+
+
+
+
+ Riker
+
+
+
+
+ Crusher
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2024,14 +5536,14 @@
-
- test sublist
- Describe this function...
+
+ test sublist simple
+ Tests the "get sub-list" block with a variable.
list
-
+
@@ -2062,7 +5574,11 @@
- sublist # start
+
+
+ sublist # simple
+
+
@@ -2074,19 +5590,27 @@
-
- 2
+
+
+
+ 1
+
+
-
- 3
+
+
+
+ 2
+
+
-
+
@@ -2102,64 +5626,782 @@
- sublist # end
+
+
+ sublist # simple order
+
+
- FROM_END
- FROM_END
+ FROM_START
+ FROM_START
list
-
- 3
+
+
+
+ TRUE
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
-
- 2
+
+
+
+ TRUE
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
-
+
- Discovery
+ Challenger
- Atlantis
+ Discovery
- sublist first-last
+
+
+ sublist #-end simple
+
+
-
- FIRST
- LAST
+
+ FROM_END
+ FROM_END
list
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
-
- list
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+
+
+ sublist #-end simple order
+
+
+
+
+
+ FROM_END
+ FROM_END
+ The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index.
+
+
+ list
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+
+
+
+
+ sublist first-last simple
+
+
+
+
+
+ FIRST
+ LAST
+
+
+ list
+
+
+
+
+
+
+ list
+
+
+
+
+ changing list
+
+
+
+
+
+ Columbia
+
+
+
+
+ Challenger
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+ Endeavour
+
+
+
+
+
+
+ list copy
+
+
+
+ FIRST
+ LAST
+
+
+ changing list
+
+
+
+
+
+
+
+ REMOVE
+ RANDOM
+
+
+ changing list
+
+
+
+
+
+
+ sublist first-last simple copy check
+
+
+
+
+ list copy
+
+
+
+
+ list
+
+
+
+
+
+
+ sublist # #-end simple
+
+
+
+
+
+ FROM_START
+ FROM_END
+
+
+ list
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+ Challenger
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+
+
+
+
+ sublist #-end # simple
+
+
+
+
+
+ FROM_END
+ FROM_START
+
+
+ list
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+
+
+
+
+ sublist first # simple
+
+
+
+
+
+ FIRST
+ FROM_START
+
+
+ list
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ Columbia
+
+
+
+
+ Challenger
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+
+
+
+
+ sublist first #-end simple
+
+
+
+
+
+ FIRST
+ FROM_END
+
+
+ list
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ Columbia
+
+
+
+
+ Challenger
+
+
+
+
+
+
+
+
+ sublist # last simple
+
+
+
+
+
+ FROM_START
+ LAST
+
+
+ list
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ Atlantis
+
+
+
+
+ Endeavour
+
+
+
+
+
+
+
+
+ sublist #-end last simple
+
+
+
+
+
+ FROM_END
+ LAST
+
+
+ list
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ Challenger
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+ Endeavour
+
+
+
+
+
+
+
+
+ sublist all with # #-end simple
+
+
+
+
+
+ FROM_START
+ FROM_END
+
+
+ list
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ list
+
+
+
+
+
+
+ sublist all with #-end # simple
+
+
+
+
+
+ FROM_END
+ FROM_START
+
+
+ list
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+ list
+
+
+
+
+
+
+ sublist all with # #-end math simple
+
+
+
+
+
+ FROM_START
+ FROM_END
+ Checks that the whole list is properly retrieved even if the value for start and end is not a simple number. This is especially important in generators where sublist uses [x:length - y] for # #-end.
+
+
+ list
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2169,14 +6411,1154 @@
-
- test join
- Describe this function...
+
+ get space shuttles
+ Creates a list for use with the sublist test.
-
+
+ number of calls
+
+
+ 1
+
+
+
+
+
+
+
+
+
+ Columbia
+
+
+
+
+ Challenger
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+ Endeavour
+
+
+
+
+
+
+ test sublist complex
+ Tests the "get sub-list" block with a function call.
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist # start complex
+
+
+
+
+
+ FROM_START
+ FROM_START
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+ Challenger
+
+
+
+
+ Discovery
+
+
+
+
+
+
+
+
+
+
+
+ sublist # start complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist # start order complex
+
+
+
+
+
+ FROM_START
+ FROM_START
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Challenger
+
+
+
+
+ Discovery
+
+
+
+
+
+
+
+
+
+
+
+ sublist # start order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist # end complex
+
+
+
+
+
+ FROM_END
+ FROM_END
+ The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index.
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+
+
+
+
+ sublist # end complex number of calls
+
+
+
+
+ number of calls
+
+
+
+
+ 1
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist # end order complex
+
+
+
+
+
+ FROM_END
+ FROM_END
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+
+
+
+
+
+
+
+ sublist # end order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist first-last complex
+
+
+
+
+
+ FIRST
+ LAST
+
+
+
+
+
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+ sublist first-last complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist # #-end complex
+
+
+
+
+
+ FROM_START
+ FROM_END
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+ Challenger
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+
+
+
+
+
+
+
+ sublist # #-end complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist #-end # complex
+
+
+
+
+
+ FROM_END
+ FROM_START
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+
+
+
+
+
+
+
+ sublist #-end # complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist first # complex
+
+
+
+
+
+ FIRST
+ FROM_START
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ Columbia
+
+
+
+
+ Challenger
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+
+
+
+
+
+
+
+ sublist first # complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist first #-end complex
+
+
+
+
+
+ FIRST
+ FROM_END
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ Columbia
+
+
+
+
+ Challenger
+
+
+
+
+
+
+
+
+
+
+
+ sublist first #-end complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist # last complex
+
+
+
+
+
+ FROM_START
+ LAST
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ Atlantis
+
+
+
+
+ Endeavour
+
+
+
+
+
+
+
+
+
+
+
+ sublist # last complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist #-end last simple
+
+
+
+
+
+ FROM_END
+ LAST
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ Challenger
+
+
+
+
+ Discovery
+
+
+
+
+ Atlantis
+
+
+
+
+ Endeavour
+
+
+
+
+
+
+
+
+
+
+
+ sublist #-end last simple
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist all with # #-end complex
+
+
+
+
+
+ FROM_START
+ FROM_END
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+ sublist all with # #-end complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist all with #-end # complex
+
+
+
+
+
+ FROM_END
+ FROM_START
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+ sublist all with #-end # complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ sublist all with # #-end math complex
+
+
+
+
+
+ FROM_START
+ FROM_END
+ Checks that the whole list is properly retrieved even if the value for start and end is not a simple number. This is especially important in generators where sublist uses [x:length - y] for # #-end.
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+ sublist all with # #-end math complex
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test join
+ Tests the "join" block.
+
+
list
-
+
@@ -2197,7 +7579,11 @@
- join
+
+
+ join
+
+
@@ -2219,43 +7605,89 @@
Vulcan,Klingon,Borg
+
+
+
+
+ join order
+
+
+
+
+
+ JOIN
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+ ,
+
+
+
+
+
+
+ Vulcan,Klingon,Borg
+
+
+
+
-
+
test split
- Describe this function...
+ Tests the "split" block.
-
- list
+
+ text
-
-
- SPLIT
-
-
- Vulcan,Klingon,Borg
-
-
-
-
- ,
-
-
+
+ Vulcan,Klingon,Borg
- split
+
+
+ split
+
+
-
- list
+
+
+ SPLIT
+
+
+ text
+
+
+
+
+ ,
+
+
-
+
@@ -2274,53 +7706,114 @@
+
+
+
+
+ split order
+
+
+
+
+
+ SPLIT
+
+
+
+
+ TRUE
+
+
+
+
+ text
+
+
+
+
+
+
+
+
+
+ ,
+
+
+
+
+
+
+
+
+
+ Vulcan
+
+
+
+
+ Klingon
+
+
+
+
+ Borg
+
+
+
+
+
+
-
+
test sort alphabetic
- Describe this function...
+ Tests the "alphabetic sort" block.
-
+
list
-
- TEXT
- 1
-
-
-
-
-
- Vulcan
-
-
-
-
- klingon
-
-
-
-
- Borg
-
-
+
+
+
+
+ Vulcan
+
+
+
+
+ klingon
+
+
+
+
+ Borg
- sort alphabetic ascending
+
+
+ sort alphabetic ascending
+
+
-
- list
+
+ TEXT
+ 1
+
+
+ list
+
+
-
+
@@ -2339,53 +7832,109 @@
+
+
+
+
+ sort alphabetic ascending order
+
+
+
+
+ TEXT
+ 1
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Borg
+
+
+
+
+ Vulcan
+
+
+
+
+ klingon
+
+
+
+
+
+
-
+
test sort ignoreCase
- Describe this function...
+ Tests the "alphabetic sort ignore case" block.
-
+
list
-
- IGNORE_CASE
- 1
-
-
-
-
-
- Vulcan
-
-
-
-
- klingon
-
-
-
-
- Borg
-
-
+
+
+
+
+ Vulcan
+
+
+
+
+ klingon
+
+
+
+
+ Borg
- sort ignore case ascending
+
+
+ sort ignore case ascending
+
+
-
- list
+
+ IGNORE_CASE
+ 1
+
+
+ list
+
+
-
+
@@ -2404,53 +7953,109 @@
+
+
+
+
+ sort ignore case ascending order
+
+
+
+
+ IGNORE_CASE
+ 1
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Borg
+
+
+
+
+ klingon
+
+
+
+
+ Vulcan
+
+
+
+
+
+
-
+
test sort numeric
- Describe this function...
+ Tests the "numeric sort" block.
-
+
list
-
- NUMERIC
- -1
-
-
-
-
-
- 8
-
-
-
-
- 18
-
-
-
-
- -1
-
-
+
+
+
+
+ 8
+
+
+
+
+ 18
+
+
+
+
+ -1
- sort numeric descending
+
+
+ sort numeric descending
+
+
-
- list
+
+ NUMERIC
+ -1
+
+
+ list
+
+
-
+
@@ -2469,9 +8074,61 @@
+
+
+
+
+ sort numeric descending order
+
+
+
+
+ NUMERIC
+ -1
+
+
+
+
+ TRUE
+
+
+
+
+ list
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 18
+
+
+
+
+ 8
+
+
+
+
+ -1
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/tests/generators/logic.xml b/tests/generators/logic.xml
index b702b5ee3..acea1c752 100644
--- a/tests/generators/logic.xml
+++ b/tests/generators/logic.xml
@@ -2,7 +2,11 @@
- True
+
+
+ True
+
+
TRUE
@@ -11,7 +15,11 @@
- False
+
+
+ False
+
+
FALSE
@@ -20,7 +28,11 @@
- Not true
+
+
+ Not true
+
+
TRUE
@@ -33,7 +45,11 @@
- Not false
+
+
+ Not false
+
+
FALSE
@@ -89,7 +105,7 @@
- if false
+ if false
@@ -119,7 +135,11 @@
- if true
+
+
+ if true
+
+
TRUE
@@ -144,7 +164,7 @@
- if/else false
+ if/else false
@@ -159,7 +179,11 @@
- if/else false
+
+
+ if/else false
+
+
TRUE
@@ -194,12 +218,16 @@
- if/else true
+ if/else true
- if/else true
+
+
+ if/else true
+
+
TRUE
@@ -224,7 +252,7 @@
- elseif 1
+ elseif 1
@@ -249,17 +277,21 @@
- elseif 2
+ elseif 2
- elseif 3
+ elseif 3
- elseif 4
+
+
+ elseif 4
+
+
TRUE
@@ -297,7 +329,11 @@
test equalities
- Equal yes
+
+
+ Equal yes
+
+
TRUE
@@ -316,7 +352,11 @@
- Equal no
+
+
+ Equal no
+
+
FALSE
@@ -335,7 +375,11 @@
- Not equal yes
+
+
+ Not equal yes
+
+
TRUE
@@ -354,7 +398,11 @@
- Not equal no
+
+
+ Not equal no
+
+
FALSE
@@ -373,7 +421,11 @@
- Smaller yes
+
+
+ Smaller yes
+
+
TRUE
@@ -392,7 +444,11 @@
- Smaller no
+
+
+ Smaller no
+
+
FALSE
@@ -411,7 +467,11 @@
- Greater yes
+
+
+ Greater yes
+
+
TRUE
@@ -430,7 +490,11 @@
- Greater no
+
+
+ Greater no
+
+
FALSE
@@ -449,7 +513,11 @@
- Smaller-equal yes
+
+
+ Smaller-equal yes
+
+
TRUE
@@ -468,7 +536,11 @@
- Smaller-equal no
+
+
+ Smaller-equal no
+
+
FALSE
@@ -487,7 +559,11 @@
- Greater-equal yes
+
+
+ Greater-equal yes
+
+
TRUE
@@ -506,7 +582,11 @@
- Greater-equal no
+
+
+ Greater-equal no
+
+
FALSE
@@ -552,7 +632,11 @@
test or
- Or true/true
+
+
+ Or true/true
+
+
TRUE
@@ -571,7 +655,11 @@
- Or false/true
+
+
+ Or false/true
+
+
TRUE
@@ -590,7 +678,11 @@
- Or true/false
+
+
+ Or true/false
+
+
TRUE
@@ -609,7 +701,11 @@
- Or false/false
+
+
+ Or false/false
+
+
FALSE
@@ -639,7 +735,11 @@
test and
- And true/true
+
+
+ And true/true
+
+
TRUE
@@ -658,7 +758,11 @@
- And false/true
+
+
+ And false/true
+
+
FALSE
@@ -677,7 +781,11 @@
- And true/false
+
+
+ And true/false
+
+
FALSE
@@ -696,7 +804,11 @@
- And false/false
+
+
+ And false/false
+
+
FALSE
@@ -726,7 +838,11 @@
test ternary
- if true
+
+
+ if true
+
+
@@ -753,7 +869,11 @@
- if true
+
+
+ if true
+
+
diff --git a/tests/generators/loops1.xml b/tests/generators/loops1.xml
index 70fb34c1c..7cdff0786 100644
--- a/tests/generators/loops1.xml
+++ b/tests/generators/loops1.xml
@@ -62,7 +62,11 @@
- for loop
+
+
+ for loop
+
+
log
@@ -93,7 +97,7 @@
- while 0
+ while 0
@@ -106,7 +110,7 @@
- until 0
+ until 0
@@ -147,7 +151,11 @@
- while 10
+
+
+ while 10
+
+
count
@@ -196,7 +204,11 @@
- until 10
+
+
+ until 10
+
+
count
@@ -254,7 +266,11 @@
- repeat 10
+
+
+ repeat 10
+
+
count
diff --git a/tests/generators/loops2.xml b/tests/generators/loops2.xml
index 4307f6d10..c35623a5d 100644
--- a/tests/generators/loops2.xml
+++ b/tests/generators/loops2.xml
@@ -51,7 +51,11 @@
- count up ints
+
+
+ count up ints
+
+
log
@@ -100,7 +104,11 @@
- count down ints
+
+
+ count down ints
+
+
log
@@ -154,7 +162,11 @@
- count with floats
+
+
+ count with floats
+
+
loglist
@@ -263,7 +275,11 @@
- count up non-trivial ints
+
+
+ count up non-trivial ints
+
+
loglist
@@ -377,7 +393,11 @@
- count down non-trivial ints
+
+
+ count down non-trivial ints
+
+
loglist
@@ -481,7 +501,11 @@
- count with floats
+
+
+ count with floats
+
+
loglist
@@ -589,7 +613,11 @@
- count up
+
+
+ count up
+
+
log
@@ -633,7 +661,11 @@
- count down
+
+
+ count down
+
+
log
@@ -702,7 +734,11 @@
- count up non-trivial
+
+
+ count up non-trivial
+
+
loglist
@@ -791,7 +827,11 @@
- count down non-trivial
+
+
+ count down non-trivial
+
+
loglist
diff --git a/tests/generators/loops3.xml b/tests/generators/loops3.xml
index 6cd5e0c75..508b88729 100644
--- a/tests/generators/loops3.xml
+++ b/tests/generators/loops3.xml
@@ -93,7 +93,11 @@
- while continue
+
+
+ while continue
+
+
log
@@ -184,7 +188,11 @@
- until continue
+
+
+ until continue
+
+
log
@@ -252,7 +260,11 @@
- count continue
+
+
+ count continue
+
+
log
@@ -335,7 +347,11 @@
- for continue
+
+
+ for continue
+
+
log
@@ -439,7 +455,11 @@
- while break
+
+
+ while break
+
+
count
@@ -512,7 +532,11 @@
- until break
+
+
+ until break
+
+
count
@@ -580,7 +604,11 @@
- count break
+
+
+ count break
+
+
log
@@ -663,7 +691,11 @@
- for break
+
+
+ for break
+
+
log
diff --git a/tests/generators/math.xml b/tests/generators/math.xml
index 38b28c3b5..9c1f644f8 100644
--- a/tests/generators/math.xml
+++ b/tests/generators/math.xml
@@ -1,11 +1,11 @@
-
+
-
+
@@ -61,11 +61,16 @@
-
- test operations on single
+
+ test single
+ Tests the "single" block.
- sqrt
+
+
+ sqrt
+
+
ROOT
@@ -83,7 +88,11 @@
- abs
+
+
+ abs
+
+
ABS
@@ -101,7 +110,11 @@
- negate
+
+
+ negate
+
+
NEG
@@ -119,7 +132,11 @@
- ln
+
+
+ ln
+
+
LN
@@ -137,7 +154,11 @@
- log10
+
+
+ log10
+
+
LOG10
@@ -155,7 +176,11 @@
- exp
+
+
+ exp
+
+
EXP
@@ -173,7 +198,11 @@
- power10
+
+
+ power10
+
+
POW10
@@ -204,11 +233,16 @@
-
+
test arithmetic
+ Tests the "arithmetic" block for all operations and checks parenthesis are properly generated for different orders.
- add
+
+
+ add
+
+
ADD
@@ -231,7 +265,11 @@
- subtract
+
+
+ subtract
+
+
MINUS
@@ -254,73 +292,280 @@
- multiply
+
+
+ subtract order with add
+
+
- MULTIPLY
+ MINUS
- 4
+ 1
-
- 2.5
+
+ ADD
+
+
+ 0
+
+
+
+
+ 2
+
+
- 10
+ -1
- divide
+
+
+ subtract order with subtract
+
+
- DIVIDE
+ MINUS
- 8.2
+ 1
-
- -5
+
+ MINUS
+
+
+ 0
+
+
+
+
+ 2
+
+
- -1.64
+ 3
- power
+
+
+ multiply
+
+
- POWER
+ MULTIPLY
- 10
+ 4
- 4
+ 2.5
- 10000
+ 10
+
+
+
+
+ multiply order
+
+
+
+
+ MULTIPLY
+
+
+ 4
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+ 2.5
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+ divide
+
+
+
+
+ DIVIDE
+
+
+ 8.2
+
+
+
+
+ -5
+
+
+
+
+
+
+ -1.64
+
+
+
+
+
+
+ divide order
+
+
+
+
+ DIVIDE
+
+
+ 8.2
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+ -5
+
+
+
+
+
+
+
+
+ -1.64
+
+
+
+
+
+
+ power
+
+
+
+
+ POWER
+
+
+ 10
+
+
+
+
+ 4
+
+
+
+
+
+
+ 10000
+
+
+
+
+
+
+ power order
+
+
+
+
+ POWER
+
+
+ 10
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+ 10000
+
+
+
+
+
+
+
+
+
+
+
+
@@ -332,11 +577,16 @@
-
+
test trig
+ Tests the "trig" block.
- sin
+
+
+ sin
+
+
SIN
@@ -354,7 +604,11 @@
- cos
+
+
+ cos
+
+
COS
@@ -372,7 +626,11 @@
- tan
+
+
+ tan
+
+
TAN
@@ -390,7 +648,11 @@
- asin
+
+
+ asin
+
+
ASIN
@@ -408,7 +670,11 @@
- acos
+
+
+ acos
+
+
ACOS
@@ -426,7 +692,11 @@
- atan
+
+
+ atan
+
+
ATAN
@@ -455,11 +725,16 @@
-
+
test constant
+ Tests the "constant" blocks.
- const pi
+
+
+ const pi
+
+
ROUNDDOWN
@@ -487,7 +762,11 @@
- const e
+
+
+ const e
+
+
ROUNDDOWN
@@ -515,7 +794,11 @@
- const golden
+
+
+ const golden
+
+
ROUNDDOWN
@@ -543,7 +826,11 @@
- const sqrt 2
+
+
+ const sqrt 2
+
+
ROUNDDOWN
@@ -571,7 +858,11 @@
- const sqrt 0.5
+
+
+ const sqrt 0.5
+
+
ROUNDDOWN
@@ -599,8 +890,12 @@
- const infinity
TRUE
+
+
+ const infinity
+
+
LT
@@ -629,12 +924,17 @@
-
+
test number properties
+ Tests the "number property" blocks.
- even
TRUE
+
+
+ even
+
+
@@ -648,8 +948,12 @@
- odd
FALSE
+
+
+ odd
+
+
@@ -663,8 +967,12 @@
- prime 5
TRUE
+
+
+ prime 5
+
+
@@ -678,8 +986,12 @@
- prime 25
FALSE
+
+
+ prime 25
+
+
@@ -693,8 +1005,12 @@
- prime negative
FALSE
+
+
+ prime negative
+
+
@@ -708,8 +1024,12 @@
- whole
FALSE
+
+
+ whole
+
+
@@ -723,8 +1043,12 @@
- positive
TRUE
+
+
+ positive
+
+
@@ -738,8 +1062,12 @@
- negative
TRUE
+
+
+ negative
+
+
@@ -753,8 +1081,12 @@
- divisible
TRUE
+
+
+ divisible
+
+
@@ -790,11 +1122,16 @@
-
+
test round
+ Tests the "round" block.
- round
+
+
+ round
+
+
ROUND
@@ -812,7 +1149,11 @@
- round up
+
+
+ round up
+
+
ROUNDUP
@@ -830,7 +1171,11 @@
- round down
+
+
+ round down
+
+
ROUNDDOWN
@@ -853,8 +1198,9 @@
-
+
test change
+ Tests the "change" block.
varToChange
@@ -873,7 +1219,11 @@
- change
+
+
+ change
+
+
varToChange
@@ -891,176 +1241,16 @@
-
-
-
-
-
- assert list equal
-
-
- equal
-
-
- TRUE
-
-
-
-
-
-
-
- NEQ
-
-
-
-
- a
-
-
-
-
-
-
-
-
- b
-
-
-
-
-
-
-
-
- equal
-
-
- FALSE
-
-
-
-
-
-
- x
-
-
- 1
-
-
-
-
-
-
- a
-
-
-
-
-
-
-
-
- NEQ
-
-
-
- GET
- FROM_START
-
-
- a
-
-
-
-
- x
-
-
-
-
-
-
-
- GET
- FROM_START
-
-
- b
-
-
-
-
- x
-
-
-
-
-
-
-
-
- equal
-
-
- FALSE
-
-
-
-
- BREAK
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- equal
-
-
-
-
-
-
- list equality
-
-
- a
-
-
-
-
- b
-
-
-
-
-
-
-
-
-
-
-
-
- equal
-
-
-
-
+
test operations on list
+ Tests the "list operation" blocks.
- sum
+
+
+ sum
+
+
@@ -1094,7 +1284,11 @@
- min
+
+
+ min
+
+
@@ -1128,7 +1322,11 @@
- max
+
+
+ max
+
+
@@ -1162,7 +1360,11 @@
- average
+
+
+ average
+
+
@@ -1196,7 +1398,11 @@
- median
+
+
+ median
+
+
@@ -1234,22 +1440,62 @@
-
- modes
- TRUE
+
+
+
+ modes
+
+
-
-
-
-
-
-
+
+
+ MODE
+
+
+
+
+
+ 3
+
+
+
+
+ 4
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+ modes multiple
+
+
+
MODE
-
+
3
@@ -1265,45 +1511,14 @@
3
-
-
-
-
-
-
-
-
-
- 3
-
-
-
-
-
-
-
-
- standard dev
-
-
-
- STD_DEV
-
-
-
-
+
- 3
+ 1
-
+
- 3
-
-
-
-
- 3
+ 4
@@ -1311,46 +1526,74 @@
-
- 0
+
+
+
+
+ 3
+
+
+
+
+ 4
+
+
-
- random
- TRUE
+
+
+
+ standard dev
+
+
-
- GT
-
-
- FIRST
-
-
-
-
-
- 3
-
-
-
-
- 4
-
-
-
-
- 5
-
-
+
+
+ STD_DEV
+
+
+
+
+
+ 3
-
-
-
- RANDOM
-
-
+
+
+ 3
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ TRUE
+
+
+ random
+
+
+
+
+ GT
+
+
+ FIRST
+
+
@@ -1369,17 +1612,43 @@
+
+
+
+ RANDOM
+
+
+
+
+
+ 3
+
+
+
+
+ 4
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
+
+
+ 0
-
-
- 0
-
-
-
+
@@ -1397,11 +1666,16 @@
-
+
test mod
+ Tests the "mod" block.
- mod
+
+
+ mod
+
+
@@ -1424,11 +1698,16 @@
-
+
test constraint
+ Tests the "constrain" block.
- constraint
+
+
+ constraint
+
+
@@ -1456,8 +1735,9 @@
-
+
test random integer
+ Tests the "random integer" block.
rand
@@ -1477,8 +1757,12 @@
- randRange
TRUE
+
+
+ randRange
+
+
AND
@@ -1516,8 +1800,12 @@
- randInteger
TRUE
+
+
+ randInteger
+
+
@@ -1536,8 +1824,9 @@
-
+
test random fraction
+ Tests the "random fraction" block.
rand
@@ -1546,8 +1835,12 @@
- randFloat
TRUE
+
+
+ randFloat
+
+
AND
@@ -1588,4 +1881,4 @@
-
+
\ No newline at end of file
diff --git a/tests/generators/text.xml b/tests/generators/text.xml
index 39a5879a9..baf62d80f 100644
--- a/tests/generators/text.xml
+++ b/tests/generators/text.xml
@@ -1,32 +1,47 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -46,40 +61,35 @@
-
- test length
+
+
+
+
+ check number of calls
+ Checks that the number of calls is one in order to confirm that a function was only called once.
-
- length
-
-
-
-
- Google
-
-
-
-
-
-
- 6
+
+ test name
+
+
+ number of calls
-
- length
+
+
+
+ test name
+
+
-
-
-
-
-
-
+
+ number of calls
- 0
+ 1
@@ -87,14 +97,238 @@
-
+
+ test create
+ Tests the "create text with" block with varying number of inputs.
+
+
+
+
+ no text
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ create single
+
+
+
+
+
+
+
+ Hello
+
+
+
+
+
+
+ Hello
+
+
+
+
+
+
+ create single number
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+ create double text
+
+
+
+
+
+
+
+ K
+
+
+
+
+ 9
+
+
+
+
+
+
+ K9
+
+
+
+
+
+
+ create double text numbers
+
+
+
+
+
+
+
+ 4
+
+
+
+
+ 2
+
+
+
+
+
+
+ 42
+
+
+
+
+
+
+ create triple
+
+
+
+
+
+
+
+ 1
+
+
+
+
+ 2
+
+
+
+
+ 3
+
+
+
+
+
+
+ 123
+
+
+
+
+
+
+ create order
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+ TRUE
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+ M
+
+
+
+
+
+
+ 10M
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get empty
+ Creates an empty string for use with the empty test.
+
+
+
+
+
+
+
test empty
+ Tests the "is empty" block".
- not empty
FALSE
+
+
+ not empty
+
+
-
+
Google
@@ -104,10 +338,14 @@
- empty
TRUE
+
+
+ empty
+
+
-
+
@@ -115,80 +353,137 @@
+
+
+ TRUE
+
+
+ empty complex
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+ empty order
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- test create text
+
+ test length
+ Tests the "length" block.
- single text
+
+
+ zero length
+
+
-
-
-
+
+
- Hello
+
-
- Hello
+
+ 0
- double text
+
+
+ non-zero length
+
+
-
-
-
+
+
- K
-
-
-
-
- 9
+ Google
-
- K9
+
+ 6
- triple text
+
+
+ length order
+
+
-
-
-
-
- 1
-
-
-
-
- 2
-
-
-
-
- 3
+
+
+
+
+
+ TRUE
+
+
+
+
+ car
+
+
+
+
+
-
- 123
+
+ 3
@@ -198,8 +493,9 @@
-
- test append item
+
+ test append
+ Tests the "append text" block with different types of parameters.
item
@@ -218,7 +514,11 @@
- append text
+
+
+ append text
+
+
item
@@ -247,7 +547,11 @@
- append number
+
+
+ append number
+
+
item
@@ -258,6 +562,57 @@
1234
+
+
+ item
+
+
+ Something
+
+
+
+
+ item
+
+
+
+
+ TRUE
+
+
+
+
+ Positive
+
+
+
+
+
+
+
+
+
+
+
+ append order
+
+
+
+
+ item
+
+
+
+
+ Something Positive
+
+
+
+
+
+
+
+
@@ -271,94 +626,108 @@
-
- test substring
+
+ test find simple
+ Tests the "find" block with a variable.
text
- 123456789
+ Banana
- substring # start
+
+
+ find first simple
+
+
-
-
- FROM_START
- FROM_START
-
+
+ FIRST
+
text
-
-
- 2
-
-
-
-
- 3
+
+
+ an
-
- 23
+
+
+
+ 1
+
+
- substring # end
+
+
+ find last simple
+
+
-
-
- FROM_END
- FROM_END
-
+
+ LAST
+
text
-
-
- 3
-
-
-
-
- 2
+
+
+ an
-
- 78
+
+
+
+ 3
+
+
- substring first-last
+
+
+ find none simple
+
+
-
-
- FIRST
- LAST
-
+
+ FIRST
+
text
+
+
+ Peel
+
+
-
- text
+
+
+
+ -1
+
+
@@ -370,40 +739,49 @@
-
- test find
+
+ get fruit
+ Creates a string for use with the find test.
-
- first find
-
-
- FIRST
-
-
- Banana
-
-
-
-
- an
-
-
+
+ number of calls
+
+
+ 1
-
+
+
+
+
+ Banana
+
+
+
+
+ test find complex
+ Tests the "find" block with a function call.
+
+
+ number of calls
+
- 2
+ 0
- last find
+
+
+ find first complex
+
+
- LAST
+ FIRST
-
- Banana
+
+
@@ -414,159 +792,331 @@
-
- 4
+
+
+
+ 1
+
+
-
- no find
-
-
- FIRST
-
-
- Banana
-
-
-
-
- Peel
-
-
-
-
-
-
- 0
-
-
-
-
-
-
-
-
-
-
- test letter
-
-
- letter #
-
-
-
- FROM_START
-
-
- Blockly
-
-
-
-
- 3
-
-
-
-
-
-
- o
-
-
-
-
- letter # from end
-
-
-
- FROM_END
-
+
+
+
+
+
- Blockly
-
-
-
-
- 3
-
-
-
-
-
-
- k
-
-
-
-
- first letter
-
-
-
- FIRST
-
-
- Blockly
-
-
-
-
-
-
- B
+ find first complex
-
- last letter
-
-
-
- LAST
-
-
- Blockly
-
-
-
-
-
-
- y
+
+ number of calls
+
+
+ 0
-
- random letter
- TRUE
+
+
+
+ find first order complex
+
+
-
-
- POSITIVE
-
-
- FIRST
-
-
- Blockly
+
+ FIRST
+
+
+
+
+ TRUE
-
-
-
- RANDOM
-
-
- Blockly
-
-
+
+
+
+
+
+
+
+
+
+
+ an
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+ find first order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ find last complex
+
+
+
+
+ LAST
+
+
+
+
+
+
+
+ an
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ find last complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ find last order complex
+
+
+
+
+ LAST
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+ find last order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ find none complex
+
+
+
+
+ FIRST
+
+
+
+
+
+
+
+ Peel
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+ find none complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ find none order complex
+
+
+
+
+ FIRST
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Peel
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+ find none order complex
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -578,62 +1128,2768 @@
-
- test case
+
+ test get simple
+ Tests the "get letter" block with a variable.
-
- uppercase
-
-
- UPPERCASE
-
-
- Hello World
-
-
-
-
-
+
+ text
+
- HELLO WORLD
+ Blockly
- lowercase
+
+
+ get first simple
+
+
+
+
+
+ FIRST
+
+
+ text
+
+
+
+
+
+
+ B
+
+
+
+
+
+
+ get last simple
+
+
+
+
+
+ LAST
+
+
+ text
+
+
+
+
+
+
+ y
+
+
+
+
+ TRUE
+
+
+ get random simple
+
+
+
+
+ GT
+
+
+ FIRST
+
+
+ text
+
+
+
+
+
+ RANDOM
+
+
+ text
+
+
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+ get # simple
+
+
+
+
+
+ FROM_START
+
+
+ text
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ o
+
+
+
+
+
+
+ get # order simple
+
+
+
+
+
+ FROM_START
+
+
+ text
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+ o
+
+
+
+
+
+
+ get #-end simple
+
+
+
+
+
+ FROM_END
+
+
+ text
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ k
+
+
+
+
+
+
+ get #-end order simple
+
+
+
+
+
+ FROM_END
+ The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index.
+
+
+ text
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+ k
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get Blockly
+ Creates a string for use with the get test.
+
+
+ number of calls
+
+
+ 1
+
+
+
+
+
+
+ Blockly
+
+
+
+
+ test get complex
+ Tests the "get letter" block with a function call.
+
+
+ text
+
+
+ Blockly
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get first complex
+
+
+
+
+
+ FIRST
+
+
+
+
+
+
+
+
+
+ B
+
+
+
+
+
+
+
+
+
+ get first complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get first order complex
+
+
+
+
+
+ FIRST
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ B
+
+
+
+
+
+
+
+
+
+ get first order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get last complex
+
+
+
+
+
+ LAST
+
+
+
+
+
+
+
+
+
+ y
+
+
+
+
+
+
+
+
+
+ get last complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get last order complex
+
+
+
+
+
+ LAST
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ y
+
+
+
+
+
+
+
+
+
+ get last order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+ TRUE
+
+
+ get random complex
+
+
+
+
+ GT
+
+
+ FIRST
+
+
+ text
+
+
+
+
+
+ RANDOM
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get random complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+ TRUE
+
+
+ get random order complex
+
+
+
+
+ GT
+
+
+ FIRST
+
+
+ text
+
+
+
+
+
+ RANDOM
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get random order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get # complex
+
+
+
+
+
+ FROM_START
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ o
+
+
+
+
+
+
+
+
+
+ get # complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get # order complex
+
+
+
+
+
+ FROM_START
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+ o
+
+
+
+
+
+
+
+
+
+ get # order complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get #-end complex
+
+
+
+
+
+ FROM_END
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ k
+
+
+
+
+
+
+
+
+
+ get #-end complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ get #-end order complex
+
+
+
+
+
+ FROM_END
+ The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index.
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+ k
+
+
+
+
+
+
+
+
+
+ get #-end order complex
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ get numbers
+ Creates a string for use with the substring test.
+
+
+ number of calls
+
+
+ 1
+
+
+
+
+
+
+ 123456789
+
+
+
+
+ test substring simple
+ Tests the "get substring" block with a variable.
+
+
+ text
+
+
+ 123456789
+
+
+
+
+
+
+ substring # simple
+
+
+
+
+
+ FROM_START
+ FROM_START
+
+
+ text
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ 23
+
+
+
+
+
+
+ substring # simple order
+
+
+
+
+
+ FROM_START
+ FROM_START
+
+
+ text
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+
+
+
+
+ substring #-end simple
+
+
+
+
+
+ FROM_END
+ FROM_END
+
+
+ text
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 78
+
+
+
+
+
+
+ substring #-end simple order
+
+
+
+
+
+ FROM_END
+ FROM_END
+ The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index.
+
+
+ text
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+ 78
+
+
+
+
+
+
+ substring first-last simple
+
+
+
+
+
+ FIRST
+ LAST
+
+
+ text
+
+
+
+
+
+
+ text
+
+
+
+
+
+
+ substring # #-end simple
+
+
+
+
+
+ FROM_START
+ FROM_END
+
+
+ text
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 2345678
+
+
+
+
+
+
+ substring #-end # simple
+
+
+
+
+
+ FROM_END
+ FROM_START
+
+
+ text
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+ substring first # simple
+
+
+
+
+
+ FIRST
+ FROM_START
+
+
+ text
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+ 1234
+
+
+
+
+
+
+ substring first #-end simple
+
+
+
+
+
+ FIRST
+ FROM_END
+
+
+ text
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 12345678
+
+
+
+
+
+
+ substring # last simple
+
+
+
+
+
+ FROM_START
+ LAST
+
+
+ text
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+ 789
+
+
+
+
+
+
+ substring #-end last simple
+
+
+
+
+
+ FROM_END
+ LAST
+
+
+ text
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ 789
+
+
+
+
+
+
+ substring all with # #-end simple
+
+
+
+
+
+ FROM_START
+ FROM_END
+
+
+ text
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ 123456789
+
+
+
+
+
+
+ substring all with #-end # simple
+
+
+
+
+
+ FROM_END
+ FROM_START
+
+
+ text
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+ 123456789
+
+
+
+
+
+
+ substring all with # #-end math simple
+
+
+
+
+
+ FROM_START
+ FROM_END
+ Checks that the whole string is properly retrieved even if the value for start and end is not a simple number. This is especially important in generators where substring uses [x:length - y] for # #-end.
+
+
+ text
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+ 123456789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test substring complex
+ Tests the "get substring" block with a function call.
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring # complex
+
+
+
+
+
+ FROM_START
+ FROM_START
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ 23
+
+
+
+
+
+
+
+
+
+ substring # complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring # complex order
+
+
+
+
+
+ FROM_START
+ FROM_START
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TRUE
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+
+
+
+
+
+
+
+ substring # complex order
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring #-end complex
+
+
+
+
+
+ FROM_END
+ FROM_END
+ The order for index for #-end is addition because this will catch errors in generators where most perform the operation ... - index.
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 78
+
+
+
+
+
+
+
+
+
+ substring #-end complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring #-end order order
+
+
+
+
+
+ FROM_END
+ FROM_END
+
+
+
+
+ TRUE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+ 78
+
+
+
+
+
+
+
+
+
+ substring #-end order order
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring first-last
+
+
+
+
+
+ FIRST
+ LAST
+
+
+
+
+
+
+
+
+
+ text
+
+
+
+
+
+
+
+
+
+ substring first-last
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring # #-end complex
+
+
+
+
+
+ FROM_START
+ FROM_END
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 2345678
+
+
+
+
+
+
+
+
+
+ substring # #-end complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring #-end # complex
+
+
+
+
+
+ FROM_END
+ FROM_START
+
+
+
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+ 34
+
+
+
+
+
+
+
+
+
+ substring #-end # complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring first # complex
+
+
+
+
+
+ FIRST
+ FROM_START
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+ 1234
+
+
+
+
+
+
+
+
+
+ substring first # complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring first #-end complex
+
+
+
+
+
+ FIRST
+ FROM_END
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 12345678
+
+
+
+
+
+
+
+
+
+ substring first #-end complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring # last complex
+
+
+
+
+
+ FROM_START
+ LAST
+
+
+
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+ 789
+
+
+
+
+
+
+
+
+
+ substring # last complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring #-end last complex
+
+
+
+
+
+ FROM_END
+ LAST
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ 789
+
+
+
+
+
+
+
+
+
+ substring #-end last complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring all with # #-end complex
+
+
+
+
+
+ FROM_START
+ FROM_END
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ 123456789
+
+
+
+
+
+
+
+
+
+ substring all with # #-end complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring all with #-end # complex
+
+
+
+
+
+ FROM_END
+ FROM_START
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+ 123456789
+
+
+
+
+
+
+
+
+
+ substring all with #-end # complex
+
+
+
+
+ number of calls
+
+
+ 0
+
+
+
+
+
+
+ substring all with # #-end math complex
+
+
+
+
+
+ FROM_START
+ FROM_END
+ Checks that the whole string is properly retrieved even if the value for start and end is not a simple number. This is especially important in generators where substring uses [x:length - y] for # #-end.
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+ ADD
+
+
+ 0
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+ 123456789
+
+
+
+
+
+
+
+
+
+ substring all with # #-end math complex
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test case
+ Tests the "change casing" block.
+
+
+ text
+
+
+ Hello World
+
+
+
+
+
+
+ uppercase
+
+
- LOWERCASE
+ UPPERCASE
-
- Hello World
+
+ text
- hello world
+ HELLO WORLD
- titlecase
+
+
+ uppercase order
+
+
- TITLECASE
+ UPPERCASE
-
- heLLo WorlD
+
+
+
+ TRUE
+
+
+
+
+ text
+
+
+
+
+
- Hello World
+ HELLO WORLD
+
+
+ text
+
+
+ Hello World
+
+
+
+
+
+
+ lowercase
+
+
+
+
+ LOWERCASE
+
+
+ text
+
+
+
+
+
+
+ hello world
+
+
+
+
+
+
+ lowercase order
+
+
+
+
+ LOWERCASE
+
+
+
+
+ TRUE
+
+
+
+
+ text
+
+
+
+
+
+
+
+
+
+
+
+ hello world
+
+
+
+
+ text
+
+
+ heLLo WorlD
+
+
+
+
+
+
+ titlecase
+
+
+
+
+ TITLECASE
+
+
+ text
+
+
+
+
+
+
+ Hello World
+
+
+
+
+
+
+ titlecase order
+
+
+
+
+ TITLECASE
+
+
+
+
+ TRUE
+
+
+
+
+ text
+
+
+
+
+
+
+
+
+
+
+
+ Hello World
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -641,62 +3897,193 @@
-
+
test trim
+ Tests the "trim" block.
-
- trim both
-
-
- BOTH
-
-
- abc def
-
-
-
-
-
+
+ text
+
- abc def
+ abc def
- trim left
+
+
+ trim both
+
+
- LEFT
+ BOTH
-
- abc def
+
+ text
- abc def
+ abc def
- trim right
+
+
+ trim both order
+
+
- RIGHT
+ BOTH
-
- abc def
+
+
+
+ TRUE
+
+
+
+
+ text
+
+
+
+
+
- abc def
+ abc def
+
+
+
+
+ trim left
+
+
+
+
+ LEFT
+
+
+ text
+
+
+
+
+
+
+ abc def
+
+
+
+
+
+
+ trim left order
+
+
+
+
+ LEFT
+
+
+
+
+ TRUE
+
+
+
+
+ text
+
+
+
+
+
+
+
+
+
+
+
+ abc def
+
+
+
+
+
+
+ trim right
+
+
+
+
+ RIGHT
+
+
+ text
+
+
+
+
+
+
+ abc def
+
+
+
+
+
+
+ trim right order
+
+
+
+
+ RIGHT
+
+
+
+
+ TRUE
+
+
+
+
+ text
+
+
+
+
+
+
+
+
+
+
+
+ abc def
+
+
+
+
+
+
+
+
+
+
@@ -704,4 +4091,4 @@
-
+
\ No newline at end of file
diff --git a/tests/generators/unittest.js b/tests/generators/unittest.js
index 560e6b91f..d2b94e66d 100644
--- a/tests/generators/unittest.js
+++ b/tests/generators/unittest.js
@@ -45,11 +45,12 @@ Blockly.Blocks['unittest_assertequals'] = {
this.setColour(65);
this.setPreviousStatement(true);
this.setNextStatement(true);
- this.appendDummyInput()
- .appendField(new Blockly.FieldTextInput('test name'), 'MESSAGE');
- this.appendValueInput('ACTUAL', null)
+ this.appendValueInput('MESSAGE')
+ .appendField('name')
+ .setCheck('String');
+ this.appendValueInput('ACTUAL')
.appendField('actual');
- this.appendValueInput('EXPECTED', null)
+ this.appendValueInput('EXPECTED')
.appendField('expected');
this.setTooltip('Tests that "actual == expected".');
},
@@ -64,9 +65,10 @@ Blockly.Blocks['unittest_assertvalue'] = {
this.setColour(65);
this.setPreviousStatement(true);
this.setNextStatement(true);
- this.appendDummyInput()
- .appendField(new Blockly.FieldTextInput('test name'), 'MESSAGE');
- this.appendValueInput('ACTUAL', Boolean)
+ this.appendValueInput('MESSAGE', 'test name')
+ .appendField('name')
+ .setCheck('String');
+ this.appendValueInput('ACTUAL')
.appendField('assert')
.appendField(new Blockly.FieldDropdown(
[['true', 'TRUE'], ['false', 'FALSE'], ['null', 'NULL']]), 'EXPECTED');
@@ -92,3 +94,24 @@ Blockly.Blocks['unittest_fail'] = {
return ['unittestResults'];
}
};
+
+Blockly.Blocks['unittest_adjustindex'] = {
+ // Adjusts the indexing based on current setting.
+ init: function() {
+ this.jsonInit({
+ "message0": "adjusted %1",
+ "args0": [
+ {
+ "type": "input_value",
+ "name": "INDEX",
+ "check": "Number"
+ }
+ ],
+ "inputsInline": true,
+ "output": "Number",
+ "colour": 65,
+ "tooltip": "Adjusts the value based on whether generated code is using " +
+ "zero or one based indexing"
+ });
+ }
+};
diff --git a/tests/generators/unittest_dart.js b/tests/generators/unittest_dart.js
index 280595fc3..f1334c993 100644
--- a/tests/generators/unittest_dart.js
+++ b/tests/generators/unittest_dart.js
@@ -111,7 +111,8 @@ Blockly.Dart['unittest_main'].defineAssert_ = function() {
Blockly.Dart['unittest_assertequals'] = function(block) {
// Asserts that a value equals another value.
- var message = Blockly.Dart.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.Dart.valueToCode(block, 'MESSAGE',
+ Blockly.Dart.ORDER_NONE) || '';
var actual = Blockly.Dart.valueToCode(block, 'ACTUAL',
Blockly.Dart.ORDER_NONE) || 'null';
var expected = Blockly.Dart.valueToCode(block, 'EXPECTED',
@@ -122,7 +123,8 @@ Blockly.Dart['unittest_assertequals'] = function(block) {
Blockly.Dart['unittest_assertvalue'] = function(block) {
// Asserts that a value is true, false, or null.
- var message = Blockly.Dart.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.Dart.valueToCode(block, 'MESSAGE',
+ Blockly.Dart.ORDER_NONE) || '';
var actual = Blockly.Dart.valueToCode(block, 'ACTUAL',
Blockly.Dart.ORDER_NONE) || 'null';
var expected = block.getFieldValue('EXPECTED');
@@ -141,7 +143,8 @@ Blockly.Dart['unittest_fail'] = function(block) {
// Always assert an error.
var resultsVar = Blockly.Dart.variableDB_.getName('unittestResults',
Blockly.Variables.NAME_TYPE);
- var message = Blockly.Dart.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.Dart.valueToCode(block, 'MESSAGE',
+ Blockly.Dart.ORDER_NONE) || '';
var functionName = Blockly.Dart.provideFunction_(
'unittest_fail',
[ 'void ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
@@ -154,3 +157,21 @@ Blockly.Dart['unittest_fail'] = function(block) {
'}']);
return functionName + '(' + message + ');\n';
};
+
+Blockly.Dart['unittest_adjustindex'] = function(block) {
+ var index = Blockly.Dart.valueToCode(block, 'INDEX',
+ Blockly.Dart.ORDER_ADDITIVE) || '0';
+ // Adjust index if using one-based indexing.
+ if (Blockly.Dart.ONE_BASED_INDEXING) {
+ if (Blockly.isNumber(index)) {
+ // If the index is a naked number, adjust it right now.
+ return [parseFloat(index) + 1, Blockly.Dart.ORDER_ATOMIC];
+ } else {
+ // If the index is dynamic, adjust it in code.
+ index = index + ' + 1';
+ }
+ } else if (Blockly.isNumber(index)) {
+ return [index, Blockly.Dart.ORDER_ATOMIC];
+ }
+ return [index, Blockly.Dart.ORDER_ADDITIVE];
+};
diff --git a/tests/generators/unittest_javascript.js b/tests/generators/unittest_javascript.js
index ed5415c0b..991568614 100644
--- a/tests/generators/unittest_javascript.js
+++ b/tests/generators/unittest_javascript.js
@@ -35,15 +35,15 @@ Blockly.JavaScript['unittest_main'] = function(block) {
' var report = [];',
' var summary = [];',
' var fails = 0;',
- ' for (var x = 0; x < ' + resultsVar + '.length; x++) {',
- ' if (' + resultsVar + '[x][0]) {',
+ ' for (var i = 0; i < ' + resultsVar + '.length; i++) {',
+ ' if (' + resultsVar + '[i][0]) {',
' summary.push(".");',
' } else {',
' summary.push("F");',
' fails++;',
' report.push("");',
- ' report.push("FAIL: " + ' + resultsVar + '[x][2]);',
- ' report.push(' + resultsVar + '[x][1]);',
+ ' report.push("FAIL: " + ' + resultsVar + '[i][2]);',
+ ' report.push(' + resultsVar + '[i][1]);',
' }',
' }',
' report.unshift(summary.join(""));',
@@ -115,7 +115,8 @@ Blockly.JavaScript['unittest_main'].defineAssert_ = function(block) {
Blockly.JavaScript['unittest_assertequals'] = function(block) {
// Asserts that a value equals another value.
- var message = Blockly.JavaScript.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.JavaScript.valueToCode(block, 'MESSAGE',
+ Blockly.JavaScript.ORDER_NONE) || '';
var actual = Blockly.JavaScript.valueToCode(block, 'ACTUAL',
Blockly.JavaScript.ORDER_COMMA) || 'null';
var expected = Blockly.JavaScript.valueToCode(block, 'EXPECTED',
@@ -126,7 +127,8 @@ Blockly.JavaScript['unittest_assertequals'] = function(block) {
Blockly.JavaScript['unittest_assertvalue'] = function(block) {
// Asserts that a value is true, false, or null.
- var message = Blockly.JavaScript.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.JavaScript.valueToCode(block, 'MESSAGE',
+ Blockly.JavaScript.ORDER_NONE) || '';
var actual = Blockly.JavaScript.valueToCode(block, 'ACTUAL',
Blockly.JavaScript.ORDER_COMMA) || 'null';
var expected = block.getFieldValue('EXPECTED');
@@ -145,7 +147,8 @@ Blockly.JavaScript['unittest_fail'] = function(block) {
// Always assert an error.
var resultsVar = Blockly.JavaScript.variableDB_.getName('unittestResults',
Blockly.Variables.NAME_TYPE);
- var message = Blockly.JavaScript.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.JavaScript.valueToCode(block, 'MESSAGE',
+ Blockly.JavaScript.ORDER_NONE) || '';
var functionName = Blockly.JavaScript.provideFunction_(
'unittest_fail',
[ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
@@ -158,3 +161,21 @@ Blockly.JavaScript['unittest_fail'] = function(block) {
'}']);
return functionName + '(' + message + ');\n';
};
+
+Blockly.JavaScript['unittest_adjustindex'] = function(block) {
+ var index = Blockly.JavaScript.valueToCode(block, 'INDEX',
+ Blockly.JavaScript.ORDER_ADDITION) || '0';
+ // Adjust index if using one-based indexing.
+ if (Blockly.JavaScript.ONE_BASED_INDEXING) {
+ if (Blockly.isNumber(index)) {
+ // If the index is a naked number, adjust it right now.
+ return [parseFloat(index) + 1, Blockly.JavaScript.ORDER_ATOMIC];
+ } else {
+ // If the index is dynamic, adjust it in code.
+ index = index + ' + 1';
+ }
+ } else if (Blockly.isNumber(index)) {
+ return [index, Blockly.JavaScript.ORDER_ATOMIC];
+ }
+ return [index, Blockly.JavaScript.ORDER_ADDITION];
+};
diff --git a/tests/generators/unittest_lua.js b/tests/generators/unittest_lua.js
index 75261f0a2..d687b091b 100644
--- a/tests/generators/unittest_lua.js
+++ b/tests/generators/unittest_lua.js
@@ -105,13 +105,15 @@ Blockly.Lua['unittest_main'].defineAssert_ = function(block) {
' actual = "{" .. table.concat(actual, ", ") .. "}"',
' end',
' end',
- ' if actual == expected then',
+ ' if actual == expected or (type(actual) == "number" and ' +
+ 'type(expected) == "number" and math.abs(actual - expected) < ' +
+ '1e-9) then ',
' table.insert(' + resultsVar +
', {success=true, log="OK", title=message})',
' else',
' table.insert(' + resultsVar + ', {success=false, ' +
'log=string.format("Expected: %s\\nActual: %s"' +
- ', expected, actual), title=message})',
+ ', tostring(expected), tostring(actual)), title=message})',
' end',
'end']);
return functionName;
@@ -119,7 +121,8 @@ Blockly.Lua['unittest_main'].defineAssert_ = function(block) {
Blockly.Lua['unittest_assertequals'] = function(block) {
// Asserts that a value equals another value.
- var message = Blockly.Lua.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.Lua.valueToCode(block, 'MESSAGE',
+ Blockly.Lua.ORDER_NONE) || '';
var actual = Blockly.Lua.valueToCode(block, 'ACTUAL',
Blockly.Lua.ORDER_NONE) || 'nil';
var expected = Blockly.Lua.valueToCode(block, 'EXPECTED',
@@ -130,7 +133,8 @@ Blockly.Lua['unittest_assertequals'] = function(block) {
Blockly.Lua['unittest_assertvalue'] = function(block) {
// Asserts that a value is true, false, or null.
- var message = Blockly.Lua.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.Lua.valueToCode(block, 'MESSAGE',
+ Blockly.Lua.ORDER_NONE) || '';
var actual = Blockly.Lua.valueToCode(block, 'ACTUAL',
Blockly.Lua.ORDER_NONE) || 'nil';
var expected = block.getFieldValue('EXPECTED');
@@ -149,7 +153,8 @@ Blockly.Lua['unittest_fail'] = function(block) {
// Always assert an error.
var resultsVar = Blockly.Lua.variableDB_.getName('unittestResults',
Blockly.Variables.NAME_TYPE);
- var message = Blockly.Lua.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.Lua.valueToCode(block, 'MESSAGE',
+ Blockly.Lua.ORDER_NONE) || '';
var functionName = Blockly.Lua.provideFunction_(
'unittest_fail',
['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(message)',
@@ -161,3 +166,14 @@ Blockly.Lua['unittest_fail'] = function(block) {
'end']);
return functionName + '(' + message + ')\n';
};
+
+Blockly.Lua['unittest_adjustindex'] = function(block) {
+ var index = Blockly.Lua.valueToCode(block, 'INDEX',
+ Blockly.Lua.ORDER_ADDITIVE) || '0';
+ if (Blockly.isNumber(index)) {
+ // If the index is a naked number, adjust it right now.
+ return [parseFloat(index) + 1, Blockly.Lua.ORDER_ATOMIC];
+ }
+ // If the index is dynamic, adjust it in code.
+ return [index + ' + 1', Blockly.Lua.ORDER_ATOMIC];
+};
diff --git a/tests/generators/unittest_php.js b/tests/generators/unittest_php.js
index 429831ae9..3a80502ba 100644
--- a/tests/generators/unittest_php.js
+++ b/tests/generators/unittest_php.js
@@ -78,45 +78,50 @@ Blockly.PHP['unittest_main'].defineAssert_ = function(block) {
Blockly.Variables.NAME_TYPE);
var functionName = Blockly.PHP.provideFunction_(
'assertEquals',
- [ ' function equals($a, $b) {',
- ' if ($a === $b) {',
- ' return true;',
- ' } else if ((is_numeric($a)) && (is_numeric($b)) &&',
- ' (round($a,15) == round($b,15))) {',
- ' return true;',
- ' } else if (is_array($a) && is_array($b)) {',
- ' if (count($a) != count($b)) {',
- ' return false;',
- ' }',
- ' for ($i = 0; $i < count($a); $i++) {',
- ' if (!equals($a[$i], $b[$i])) {',
- ' return false;',
- ' }',
- ' }',
- ' return true;',
- ' }',
- ' return false;',
- ' }',
- 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
- '($actual, $expected, $message) {',
- 'global ' + resultsVar + ';',
- ' // Asserts that a value equals another value.',
- ' if (!is_array(' + resultsVar + ')) {',
- ' throw new Exception("Orphaned assert: " . $message);',
- ' }',
- ' if (equals($actual, $expected)) {',
- ' array_push(' + resultsVar + ', [true, "OK", $message]);',
- ' } else {',
- ' array_push(' + resultsVar + ', [false, ' +
- '"Expected: " . $expected . "\\nActual: " . $actual, $message]);',
- ' }',
- '}']);
+ [' function equals($a, $b) {',
+ ' if ($a === $b) {',
+ ' return true;',
+ ' } else if ((is_numeric($a)) && (is_numeric($b)) &&',
+ ' (round($a,15) == round($b,15))) {',
+ ' return true;',
+ ' } else if (is_array($a) && is_array($b)) {',
+ ' if (count($a) != count($b)) {',
+ ' return false;',
+ ' }',
+ ' for ($i = 0; $i < count($a); $i++) {',
+ ' if (!equals($a[$i], $b[$i])) {',
+ ' return false;',
+ ' }',
+ ' }',
+ ' return true;',
+ ' }',
+ ' return false;',
+ ' }',
+ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
+ '($actual, $expected, $message) {',
+ 'global ' + resultsVar + ';',
+ ' // Asserts that a value equals another value.',
+ ' if (!is_array(' + resultsVar + ')) {',
+ ' throw new Exception("Orphaned assert: " . $message);',
+ ' }',
+ ' if (equals($actual, $expected)) {',
+ ' array_push(' + resultsVar + ', [true, "OK", $message]);',
+ ' } else {',
+ ' $expected = is_array($expected) ? implode(" ", $expected) : ' +
+ '$expected;',
+ ' $actual = is_array($actual) ? implode(" ", $actual) : ' +
+ '$actual;',
+ ' array_push(' + resultsVar + ', [false, ' +
+ '"Expected: " . $expected . "\\nActual: " . $actual, $message]);',
+ ' }',
+ '}']);
return functionName;
};
Blockly.PHP['unittest_assertequals'] = function(block) {
// Asserts that a value equals another value.
- var message = Blockly.PHP.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.PHP.valueToCode(block, 'MESSAGE',
+ Blockly.PHP.ORDER_NONE) || '';
var actual = Blockly.PHP.valueToCode(block, 'ACTUAL',
Blockly.PHP.ORDER_COMMA) || 'null';
var expected = Blockly.PHP.valueToCode(block, 'EXPECTED',
@@ -127,7 +132,8 @@ Blockly.PHP['unittest_assertequals'] = function(block) {
Blockly.PHP['unittest_assertvalue'] = function(block) {
// Asserts that a value is true, false, or null.
- var message = Blockly.PHP.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.PHP.valueToCode(block, 'MESSAGE',
+ Blockly.PHP.ORDER_NONE) || '';
var actual = Blockly.PHP.valueToCode(block, 'ACTUAL',
Blockly.PHP.ORDER_COMMA) || 'null';
var expected = block.getFieldValue('EXPECTED');
@@ -146,7 +152,8 @@ Blockly.PHP['unittest_fail'] = function(block) {
// Always assert an error.
var resultsVar = Blockly.PHP.variableDB_.getName('unittestResults',
Blockly.Variables.NAME_TYPE);
- var message = Blockly.PHP.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.PHP.valueToCode(block, 'MESSAGE',
+ Blockly.PHP.ORDER_NONE) || '';
var functionName = Blockly.PHP.provideFunction_(
'unittest_fail',
[ 'function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ +
@@ -160,3 +167,21 @@ Blockly.PHP['unittest_fail'] = function(block) {
'}']);
return functionName + '(' + message + ');\n';
};
+
+Blockly.PHP['unittest_adjustindex'] = function(block) {
+ var index = Blockly.PHP.valueToCode(block, 'INDEX',
+ Blockly.PHP.ORDER_ADDITION) || '0';
+ // Adjust index if using one-based indexing.
+ if (Blockly.PHP.ONE_BASED_INDEXING) {
+ if (Blockly.isNumber(index)) {
+ // If the index is a naked number, adjust it right now.
+ return [parseFloat(index) + 1, Blockly.PHP.ORDER_ATOMIC];
+ } else {
+ // If the index is dynamic, adjust it in code.
+ index = index + ' + 1';
+ }
+ } else if (Blockly.isNumber(index)) {
+ return [index, Blockly.PHP.ORDER_ATOMIC];
+ }
+ return [index, Blockly.PHP.ORDER_ADDITION];
+};
diff --git a/tests/generators/unittest_python.js b/tests/generators/unittest_python.js
index fc64d6efc..2b459aa30 100644
--- a/tests/generators/unittest_python.js
+++ b/tests/generators/unittest_python.js
@@ -89,7 +89,8 @@ Blockly.Python['unittest_main'].defineAssert_ = function() {
Blockly.Python['unittest_assertequals'] = function(block) {
// Asserts that a value equals another value.
- var message = Blockly.Python.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.Python.valueToCode(block, 'MESSAGE',
+ Blockly.Python.ORDER_NONE) || '';
var actual = Blockly.Python.valueToCode(block, 'ACTUAL',
Blockly.Python.ORDER_NONE) || 'None';
var expected = Blockly.Python.valueToCode(block, 'EXPECTED',
@@ -100,7 +101,8 @@ Blockly.Python['unittest_assertequals'] = function(block) {
Blockly.Python['unittest_assertvalue'] = function(block) {
// Asserts that a value is true, false, or null.
- var message = Blockly.Python.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.Python.valueToCode(block, 'MESSAGE',
+ Blockly.Python.ORDER_NONE) || '';
var actual = Blockly.Python.valueToCode(block, 'ACTUAL',
Blockly.Python.ORDER_NONE) || 'None';
var expected = block.getFieldValue('EXPECTED');
@@ -119,7 +121,8 @@ Blockly.Python['unittest_fail'] = function(block) {
// Always assert an error.
var resultsVar = Blockly.Python.variableDB_.getName('unittestResults',
Blockly.Variables.NAME_TYPE);
- var message = Blockly.Python.quote_(block.getFieldValue('MESSAGE'));
+ var message = Blockly.Python.valueToCode(block, 'MESSAGE',
+ Blockly.Python.ORDER_NONE) || '';
var functionName = Blockly.Python.provideFunction_(
'fail',
['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(message):',
@@ -129,3 +132,21 @@ Blockly.Python['unittest_fail'] = function(block) {
' ' + resultsVar + '.append((False, "Fail.", message))']);
return functionName + '(' + message + ')\n';
};
+
+Blockly.Python['unittest_adjustindex'] = function(block) {
+ var index = Blockly.Python.valueToCode(block, 'INDEX',
+ Blockly.Python.ORDER_ADDITIVE) || '0';
+ // Adjust index if using one-based indexing.
+ if (Blockly.Python.ONE_BASED_INDEXING) {
+ if (Blockly.isNumber(index)) {
+ // If the index is a naked number, adjust it right now.
+ return [parseFloat(index) + 1, Blockly.Python.ORDER_ATOMIC];
+ } else {
+ // If the index is dynamic, adjust it in code.
+ index = index + ' + 1';
+ }
+ } else if (Blockly.isNumber(index)) {
+ return [index, Blockly.Python.ORDER_ATOMIC];
+ }
+ return [index, Blockly.Python.ORDER_ADDITIVE];
+};
diff --git a/tests/generators/variables.xml b/tests/generators/variables.xml
index 544d897d0..a11d0a01a 100644
--- a/tests/generators/variables.xml
+++ b/tests/generators/variables.xml
@@ -10,7 +10,11 @@
- variable
+
+
+ variable
+
+
item
@@ -31,7 +35,11 @@
- reserved variable
+
+
+ reserved variable
+
+
if
diff --git a/tests/jsunit/connection_db_test.js b/tests/jsunit/connection_db_test.js
index 269d2d123..558edf100 100644
--- a/tests/jsunit/connection_db_test.js
+++ b/tests/jsunit/connection_db_test.js
@@ -22,8 +22,8 @@
function verify_DB_(msg, expected, db) {
var equal = (expected.length == db.length);
if (equal) {
- for (var x = 0; x < expected.length; x++) {
- if (expected[x] != db[x]) {
+ for (var i = 0; i < expected.length; i++) {
+ if (expected[i] != db[i]) {
equal = false;
break;
}