From 931499295ee9bf55b9b5978e6ae21234fd87fc3c Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 1 Dec 2021 20:43:08 -0800 Subject: [PATCH] refactor: convert python block generators to goog.module (#5771) * refactor: convert generators/python/colour.js to goog.module * refactor: convert generators/python/colour.js to named requires * chore: run clang-format * refactor: convert generators/python/lists.js to goog.module * refactor: convert generators/python/lists.js to named requires * chore: run clang-format * refactor: convert generators/python/logic.js to goog.module * refactor: convert generators/python/logic.js to named requires * chore: run clang-format * refactor: convert generators/python/loops.js to goog.module * refactor: convert generators/python/loops.js to named requires * chore: run clang-format * refactor: convert generators/python/math.js to goog.module * refactor: convert generators/python/math.js to named requires * chore: run clang-format * refactor: convert generators/python/procedures.js to goog.module * refactor: convert generators/python/procedures.js to named requires * chore: run clang-format * refactor: convert generators/python/text.js to goog.module * refactor: convert generators/python/text.js to named requires * chore: run clang-format * refactor: convert generators/python/variables_dynamic.js to named requires * refactor: convert generators/python/variables.js to named requires * chore: run clang-format * refactor: convert generators/python.js to goog.module * refactor: convert generators/python.js to named requires * chore: run clang-format * chore: remove spurious @private annotations * chore: rebuild --- generators/dart.js | 1 - generators/javascript.js | 1 - generators/lua.js | 1 - generators/php.js | 1 - generators/python.js | 140 +++++------ generators/python/colour.js | 84 ++++--- generators/python/lists.js | 272 ++++++++++------------ generators/python/logic.js | 102 ++++---- generators/python/loops.js | 122 +++++----- generators/python/math.js | 307 ++++++++++++------------- generators/python/procedures.js | 101 ++++---- generators/python/text.js | 244 +++++++++----------- generators/python/variables.js | 23 +- generators/python/variables_dynamic.js | 10 +- scripts/gulpfiles/chunks.json | 10 +- tests/deps.js | 20 +- 16 files changed, 675 insertions(+), 764 deletions(-) diff --git a/generators/dart.js b/generators/dart.js index 3be566bb3f2..d9e873a6ed0 100644 --- a/generators/dart.js +++ b/generators/dart.js @@ -33,7 +33,6 @@ const Dart = new Generator('Dart'); * This is not intended to be a security feature. Blockly is 100% client-side, * so bypassing this list is trivial. This is intended to prevent users from * accidentally clobbering a built-in object or function. - * @private */ Dart.addReservedWords( // https://www.dartlang.org/docs/spec/latest/dart-language-specification.pdf diff --git a/generators/javascript.js b/generators/javascript.js index 00d1b0b5acd..4b5bf9dbf52 100644 --- a/generators/javascript.js +++ b/generators/javascript.js @@ -35,7 +35,6 @@ const JavaScript = new Generator('JavaScript'); * This is not intended to be a security feature. Blockly is 100% client-side, * so bypassing this list is trivial. This is intended to prevent users from * accidentally clobbering a built-in object or function. - * @private */ JavaScript.addReservedWords( // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords diff --git a/generators/lua.js b/generators/lua.js index 2b24452f73f..8828f1ae93b 100644 --- a/generators/lua.js +++ b/generators/lua.js @@ -34,7 +34,6 @@ const Lua = new Generator('Lua'); * This is not intended to be a security feature. Blockly is 100% client-side, * so bypassing this list is trivial. This is intended to prevent users from * accidentally clobbering a built-in object or function. - * @private */ Lua.addReservedWords( // Special character diff --git a/generators/php.js b/generators/php.js index d4e671acc1a..703396a9a5d 100644 --- a/generators/php.js +++ b/generators/php.js @@ -33,7 +33,6 @@ const PHP = new Generator('PHP'); * This is not intended to be a security feature. Blockly is 100% client-side, * so bypassing this list is trivial. This is intended to prevent users from * accidentally clobbering a built-in object or function. - * @private */ PHP.addReservedWords( // http://php.net/manual/en/reserved.keywords.php diff --git a/generators/python.js b/generators/python.js index 8208a3941c1..b676bb83a81 100644 --- a/generators/python.js +++ b/generators/python.js @@ -6,35 +6,35 @@ /** * @fileoverview Helper functions for generating Python for blocks. - * @suppress {missingRequire|checkTypes|globalThis} + * @suppress {checkTypes|globalThis} */ 'use strict'; -goog.provide('Blockly.Python'); +goog.module('Blockly.Python'); +goog.module.declareLegacyNamespace(); -goog.require('Blockly.Generator'); -goog.require('Blockly.Names'); -goog.require('Blockly.Variables'); -goog.require('Blockly.inputTypes'); -goog.require('Blockly.utils.string'); -goog.requireType('Blockly.Block'); -goog.requireType('Blockly.Workspace'); +const stringUtils = goog.require('Blockly.utils.string'); +const Variables = goog.require('Blockly.Variables'); +const {Block} = goog.requireType('Blockly.Block'); +const {Generator} = goog.require('Blockly.Generator'); +const {inputTypes} = goog.require('Blockly.inputTypes'); +const {Names, NameType} = goog.require('Blockly.Names'); +const {Workspace} = goog.requireType('Blockly.Workspace'); /** * Python code generator. - * @type {!Blockly.Generator} + * @type {!Generator} */ -Blockly.Python = new Blockly.Generator('Python'); +const Python = new Generator('Python'); /** * List of illegal variable names. * This is not intended to be a security feature. Blockly is 100% client-side, * so bypassing this list is trivial. This is intended to prevent users from * accidentally clobbering a built-in object or function. - * @private */ -Blockly.Python.addReservedWords( +Python.addReservedWords( // import keyword // print(','.join(sorted(keyword.kwlist))) // https://docs.python.org/3/reference/lexical_analysis.html#keywords @@ -73,75 +73,74 @@ Blockly.Python.addReservedWords( 'issubclass,iter,len,license,list,locals,long,map,max,memoryview,min,' + 'next,object,oct,open,ord,pow,print,property,quit,range,raw_input,reduce,' + 'reload,repr,reversed,round,set,setattr,slice,sorted,staticmethod,str,' + - 'sum,super,tuple,type,unichr,unicode,vars,xrange,zip' -); + 'sum,super,tuple,type,unichr,unicode,vars,xrange,zip'); /** * Order of operation ENUMs. * http://docs.python.org/reference/expressions.html#summary */ -Blockly.Python.ORDER_ATOMIC = 0; // 0 "" ... -Blockly.Python.ORDER_COLLECTION = 1; // tuples, lists, dictionaries -Blockly.Python.ORDER_STRING_CONVERSION = 1; // `expression...` -Blockly.Python.ORDER_MEMBER = 2.1; // . [] -Blockly.Python.ORDER_FUNCTION_CALL = 2.2; // () -Blockly.Python.ORDER_EXPONENTIATION = 3; // ** -Blockly.Python.ORDER_UNARY_SIGN = 4; // + - -Blockly.Python.ORDER_BITWISE_NOT = 4; // ~ -Blockly.Python.ORDER_MULTIPLICATIVE = 5; // * / // % -Blockly.Python.ORDER_ADDITIVE = 6; // + - -Blockly.Python.ORDER_BITWISE_SHIFT = 7; // << >> -Blockly.Python.ORDER_BITWISE_AND = 8; // & -Blockly.Python.ORDER_BITWISE_XOR = 9; // ^ -Blockly.Python.ORDER_BITWISE_OR = 10; // | -Blockly.Python.ORDER_RELATIONAL = 11; // in, not in, is, is not, - // <, <=, >, >=, <>, !=, == -Blockly.Python.ORDER_LOGICAL_NOT = 12; // not -Blockly.Python.ORDER_LOGICAL_AND = 13; // and -Blockly.Python.ORDER_LOGICAL_OR = 14; // or -Blockly.Python.ORDER_CONDITIONAL = 15; // if else -Blockly.Python.ORDER_LAMBDA = 16; // lambda -Blockly.Python.ORDER_NONE = 99; // (...) +Python.ORDER_ATOMIC = 0; // 0 "" ... +Python.ORDER_COLLECTION = 1; // tuples, lists, dictionaries +Python.ORDER_STRING_CONVERSION = 1; // `expression...` +Python.ORDER_MEMBER = 2.1; // . [] +Python.ORDER_FUNCTION_CALL = 2.2; // () +Python.ORDER_EXPONENTIATION = 3; // ** +Python.ORDER_UNARY_SIGN = 4; // + - +Python.ORDER_BITWISE_NOT = 4; // ~ +Python.ORDER_MULTIPLICATIVE = 5; // * / // % +Python.ORDER_ADDITIVE = 6; // + - +Python.ORDER_BITWISE_SHIFT = 7; // << >> +Python.ORDER_BITWISE_AND = 8; // & +Python.ORDER_BITWISE_XOR = 9; // ^ +Python.ORDER_BITWISE_OR = 10; // | +Python.ORDER_RELATIONAL = 11; // in, not in, is, is not, + // <, <=, >, >=, <>, !=, == +Python.ORDER_LOGICAL_NOT = 12; // not +Python.ORDER_LOGICAL_AND = 13; // and +Python.ORDER_LOGICAL_OR = 14; // or +Python.ORDER_CONDITIONAL = 15; // if else +Python.ORDER_LAMBDA = 16; // lambda +Python.ORDER_NONE = 99; // (...) /** * List of outer-inner pairings that do NOT require parentheses. * @type {!Array>} */ -Blockly.Python.ORDER_OVERRIDES = [ +Python.ORDER_OVERRIDES = [ // (foo()).bar -> foo().bar // (foo())[0] -> foo()[0] - [Blockly.Python.ORDER_FUNCTION_CALL, Blockly.Python.ORDER_MEMBER], + [Python.ORDER_FUNCTION_CALL, Python.ORDER_MEMBER], // (foo())() -> foo()() - [Blockly.Python.ORDER_FUNCTION_CALL, Blockly.Python.ORDER_FUNCTION_CALL], + [Python.ORDER_FUNCTION_CALL, Python.ORDER_FUNCTION_CALL], // (foo.bar).baz -> foo.bar.baz // (foo.bar)[0] -> foo.bar[0] // (foo[0]).bar -> foo[0].bar // (foo[0])[1] -> foo[0][1] - [Blockly.Python.ORDER_MEMBER, Blockly.Python.ORDER_MEMBER], + [Python.ORDER_MEMBER, Python.ORDER_MEMBER], // (foo.bar)() -> foo.bar() // (foo[0])() -> foo[0]() - [Blockly.Python.ORDER_MEMBER, Blockly.Python.ORDER_FUNCTION_CALL], + [Python.ORDER_MEMBER, Python.ORDER_FUNCTION_CALL], // not (not foo) -> not not foo - [Blockly.Python.ORDER_LOGICAL_NOT, Blockly.Python.ORDER_LOGICAL_NOT], + [Python.ORDER_LOGICAL_NOT, Python.ORDER_LOGICAL_NOT], // a and (b and c) -> a and b and c - [Blockly.Python.ORDER_LOGICAL_AND, Blockly.Python.ORDER_LOGICAL_AND], + [Python.ORDER_LOGICAL_AND, Python.ORDER_LOGICAL_AND], // a or (b or c) -> a or b or c - [Blockly.Python.ORDER_LOGICAL_OR, Blockly.Python.ORDER_LOGICAL_OR] + [Python.ORDER_LOGICAL_OR, Python.ORDER_LOGICAL_OR] ]; /** * Whether the init method has been called. * @type {?boolean} */ -Blockly.Python.isInitialized = false; +Python.isInitialized = false; /** * Initialise the database of variable names. - * @param {!Blockly.Workspace} workspace Workspace to generate code from. - * @this {Blockly.Generator} + * @param {!Workspace} workspace Workspace to generate code from. + * @this {Generator} */ -Blockly.Python.init = function(workspace) { +Python.init = function(workspace) { // Call Blockly.Generator's init. Object.getPrototypeOf(this).init.call(this); @@ -151,7 +150,7 @@ Blockly.Python.init = function(workspace) { this.PASS = this.INDENT + 'pass\n'; if (!this.nameDB_) { - this.nameDB_ = new Blockly.Names(this.RESERVED_WORDS_); + this.nameDB_ = new Names(this.RESERVED_WORDS_); } else { this.nameDB_.reset(); } @@ -162,17 +161,19 @@ Blockly.Python.init = function(workspace) { const defvars = []; // Add developer variables (not created or named by the user). - const devVarList = Blockly.Variables.allDeveloperVariables(workspace); + const devVarList = Variables.allDeveloperVariables(workspace); for (let i = 0; i < devVarList.length; i++) { - defvars.push(this.nameDB_.getName(devVarList[i], - Blockly.Names.DEVELOPER_VARIABLE_TYPE) + ' = None'); + defvars.push( + this.nameDB_.getName(devVarList[i], Names.DEVELOPER_VARIABLE_TYPE) + + ' = None'); } // Add user variables, but only ones that are being used. - const variables = Blockly.Variables.allUsedVarModels(workspace); + const variables = Variables.allUsedVarModels(workspace); for (let i = 0; i < variables.length; i++) { - defvars.push(this.nameDB_.getName(variables[i].getId(), - Blockly.VARIABLE_CATEGORY_NAME) + ' = None'); + defvars.push( + this.nameDB_.getName(variables[i].getId(), NameType.VARIABLE) + + ' = None'); } this.definitions_['variables'] = defvars.join('\n'); @@ -184,7 +185,7 @@ Blockly.Python.init = function(workspace) { * @param {string} code Generated code. * @return {string} Completed code. */ -Blockly.Python.finish = function(code) { +Python.finish = function(code) { // Convert the definitions dictionary into a list. const imports = []; const definitions = []; @@ -211,7 +212,7 @@ Blockly.Python.finish = function(code) { * @param {string} line Line of generated code. * @return {string} Legal line of code. */ -Blockly.Python.scrubNakedValue = function(line) { +Python.scrubNakedValue = function(line) { return line + '\n'; }; @@ -221,10 +222,9 @@ Blockly.Python.scrubNakedValue = function(line) { * @return {string} Python string. * @protected */ -Blockly.Python.quote_ = function(string) { +Python.quote_ = function(string) { // Can't use goog.string.quote since % must also be escaped. - string = string.replace(/\\/g, '\\\\') - .replace(/\n/g, '\\\n'); + string = string.replace(/\\/g, '\\\\').replace(/\n/g, '\\\n'); // Follow the CPython behaviour of repr() for a non-byte string. let quote = '\''; @@ -245,7 +245,7 @@ Blockly.Python.quote_ = function(string) { * @return {string} Python string. * @protected */ -Blockly.Python.multiline_quote_ = function(string) { +Python.multiline_quote_ = function(string) { const lines = string.split(/\n/g).map(this.quote_); // Join with the following, plus a newline: // + '\n' + @@ -256,26 +256,26 @@ Blockly.Python.multiline_quote_ = function(string) { * Common tasks for generating Python from blocks. * Handles comments for the specified block and any connected value blocks. * Calls any statements following this block. - * @param {!Blockly.Block} block The current block. + * @param {!Block} block The current block. * @param {string} code The Python code created for this block. * @param {boolean=} opt_thisOnly True to generate code for only this statement. * @return {string} Python code with comments and subsequent blocks added. * @protected */ -Blockly.Python.scrub_ = function(block, code, opt_thisOnly) { +Python.scrub_ = function(block, code, opt_thisOnly) { let commentCode = ''; // Only collect comments for blocks that aren't inline. if (!block.outputConnection || !block.outputConnection.targetConnection) { // Collect comment for this block. let comment = block.getCommentText(); if (comment) { - comment = Blockly.utils.string.wrap(comment, this.COMMENT_WRAP - 3); + comment = stringUtils.wrap(comment, this.COMMENT_WRAP - 3); commentCode += this.prefixLines(comment + '\n', '# '); } // Collect comments for all value arguments. // Don't collect comments for nested statements. for (let i = 0; i < block.inputList.length; i++) { - if (block.inputList[i].type === Blockly.inputTypes.VALUE) { + if (block.inputList[i].type === inputTypes.VALUE) { const childBlock = block.inputList[i].connection.targetBlock(); if (childBlock) { comment = this.allNestedComments(childBlock); @@ -294,13 +294,13 @@ Blockly.Python.scrub_ = function(block, code, opt_thisOnly) { /** * Gets a property and adjusts the value, taking into account indexing. * If a static int, casts to an integer, otherwise returns a code string. - * @param {!Blockly.Block} block The block. + * @param {!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) { +Python.getAdjustedInt = function(block, atId, opt_delta, opt_negate) { let delta = opt_delta || 0; if (block.workspace.options.oneBasedIndex) { delta--; @@ -309,7 +309,7 @@ Blockly.Python.getAdjustedInt = function(block, atId, opt_delta, opt_negate) { const atOrder = delta ? this.ORDER_ADDITIVE : this.ORDER_NONE; let at = this.valueToCode(block, atId, atOrder) || defaultAtIndex; - if (Blockly.utils.string.isNumber(at)) { + if (stringUtils.isNumber(at)) { // If the index is a naked number, adjust it right now. at = parseInt(at, 10) + delta; if (opt_negate) { @@ -330,3 +330,5 @@ Blockly.Python.getAdjustedInt = function(block, atId, opt_delta, opt_negate) { } return at; }; + +exports = Python; diff --git a/generators/python/colour.js b/generators/python/colour.js index 7537b73293e..30cb6f463dd 100644 --- a/generators/python/colour.js +++ b/generators/python/colour.js @@ -9,63 +9,59 @@ */ 'use strict'; -goog.provide('Blockly.Python.colour'); +goog.module('Blockly.Python.colour'); -goog.require('Blockly.Python'); +const Python = goog.require('Blockly.Python'); -Blockly.Python['colour_picker'] = function(block) { +Python['colour_picker'] = function(block) { // Colour picker. - const code = Blockly.Python.quote_(block.getFieldValue('COLOUR')); - return [code, Blockly.Python.ORDER_ATOMIC]; + const code = Python.quote_(block.getFieldValue('COLOUR')); + return [code, Python.ORDER_ATOMIC]; }; -Blockly.Python['colour_random'] = function(block) { +Python['colour_random'] = function(block) { // Generate a random colour. - Blockly.Python.definitions_['import_random'] = 'import random'; + Python.definitions_['import_random'] = 'import random'; const code = '\'#%06x\' % random.randint(0, 2**24 - 1)'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['colour_rgb'] = function(block) { +Python['colour_rgb'] = function(block) { // Compose a colour from RGB components expressed as percentages. - const 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)']); - const r = Blockly.Python.valueToCode(block, 'RED', - Blockly.Python.ORDER_NONE) || 0; - const g = Blockly.Python.valueToCode(block, 'GREEN', - Blockly.Python.ORDER_NONE) || 0; - const b = Blockly.Python.valueToCode(block, 'BLUE', - Blockly.Python.ORDER_NONE) || 0; + const functionName = Python.provideFunction_('colour_rgb', [ + 'def ' + 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)' + ]); + const r = Python.valueToCode(block, 'RED', Python.ORDER_NONE) || 0; + const g = Python.valueToCode(block, 'GREEN', Python.ORDER_NONE) || 0; + const b = Python.valueToCode(block, 'BLUE', Python.ORDER_NONE) || 0; const code = functionName + '(' + r + ', ' + g + ', ' + b + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['colour_blend'] = function(block) { +Python['colour_blend'] = function(block) { // Blend two colours together. - const functionName = 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)']); - const colour1 = Blockly.Python.valueToCode(block, 'COLOUR1', - Blockly.Python.ORDER_NONE) || '\'#000000\''; - const colour2 = Blockly.Python.valueToCode(block, 'COLOUR2', - Blockly.Python.ORDER_NONE) || '\'#000000\''; - const ratio = Blockly.Python.valueToCode(block, 'RATIO', - Blockly.Python.ORDER_NONE) || 0; - const code = functionName + '(' + colour1 + ', ' + colour2 + ', ' + ratio + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + const functionName = Python.provideFunction_('colour_blend', [ + 'def ' + 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)' + ]); + const colour1 = + Python.valueToCode(block, 'COLOUR1', Python.ORDER_NONE) || '\'#000000\''; + const colour2 = + Python.valueToCode(block, 'COLOUR2', Python.ORDER_NONE) || '\'#000000\''; + const ratio = Python.valueToCode(block, 'RATIO', Python.ORDER_NONE) || 0; + const code = + functionName + '(' + colour1 + ', ' + colour2 + ', ' + ratio + ')'; + return [code, Python.ORDER_FUNCTION_CALL]; }; diff --git a/generators/python/lists.js b/generators/python/lists.js index 85365dd393b..607f0671b22 100644 --- a/generators/python/lists.js +++ b/generators/python/lists.js @@ -6,63 +6,58 @@ /** * @fileoverview Generating Python for list blocks. - * @suppress {missingRequire} */ 'use strict'; -goog.provide('Blockly.Python.lists'); +goog.module('Blockly.Python.lists'); -goog.require('Blockly.Python'); -goog.require('Blockly.utils.string'); +const Python = goog.require('Blockly.Python'); +const stringUtils = goog.require('Blockly.utils.string'); +const {NameType} = goog.require('Blockly.Names'); -Blockly.Python['lists_create_empty'] = function(block) { +Python['lists_create_empty'] = function(block) { // Create an empty list. - return ['[]', Blockly.Python.ORDER_ATOMIC]; + return ['[]', Python.ORDER_ATOMIC]; }; -Blockly.Python['lists_create_with'] = function(block) { +Python['lists_create_with'] = function(block) { // Create a list with any number of elements of any type. const elements = new Array(block.itemCount_); for (let i = 0; i < block.itemCount_; i++) { - elements[i] = Blockly.Python.valueToCode(block, 'ADD' + i, - Blockly.Python.ORDER_NONE) || 'None'; + elements[i] = + Python.valueToCode(block, 'ADD' + i, Python.ORDER_NONE) || 'None'; } const code = '[' + elements.join(', ') + ']'; - return [code, Blockly.Python.ORDER_ATOMIC]; + return [code, Python.ORDER_ATOMIC]; }; -Blockly.Python['lists_repeat'] = function(block) { +Python['lists_repeat'] = function(block) { // Create a list with one element repeated. - const item = Blockly.Python.valueToCode(block, 'ITEM', - Blockly.Python.ORDER_NONE) || 'None'; - const times = Blockly.Python.valueToCode(block, 'NUM', - Blockly.Python.ORDER_MULTIPLICATIVE) || '0'; + const item = Python.valueToCode(block, 'ITEM', Python.ORDER_NONE) || 'None'; + const times = + Python.valueToCode(block, 'NUM', Python.ORDER_MULTIPLICATIVE) || '0'; const code = '[' + item + '] * ' + times; - return [code, Blockly.Python.ORDER_MULTIPLICATIVE]; + return [code, Python.ORDER_MULTIPLICATIVE]; }; -Blockly.Python['lists_length'] = function(block) { +Python['lists_length'] = function(block) { // String or array length. - const list = Blockly.Python.valueToCode(block, 'VALUE', - Blockly.Python.ORDER_NONE) || '[]'; - return ['len(' + list + ')', Blockly.Python.ORDER_FUNCTION_CALL]; + const list = Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || '[]'; + return ['len(' + list + ')', Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['lists_isEmpty'] = function(block) { +Python['lists_isEmpty'] = function(block) { // Is the string null or array empty? - const list = Blockly.Python.valueToCode(block, 'VALUE', - Blockly.Python.ORDER_NONE) || '[]'; + const list = Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || '[]'; const code = 'not len(' + list + ')'; - return [code, Blockly.Python.ORDER_LOGICAL_NOT]; + return [code, Python.ORDER_LOGICAL_NOT]; }; -Blockly.Python['lists_indexOf'] = function(block) { +Python['lists_indexOf'] = function(block) { // Find an item in the list. - const item = Blockly.Python.valueToCode(block, 'FIND', - Blockly.Python.ORDER_NONE) || '[]'; - const list = Blockly.Python.valueToCode(block, 'VALUE', - Blockly.Python.ORDER_NONE) || '\'\''; + const item = Python.valueToCode(block, 'FIND', Python.ORDER_NONE) || '[]'; + const list = Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || '\'\''; let errorIndex = ' -1'; let firstIndexAdjustment = ''; let lastIndexAdjustment = ' - 1'; @@ -74,44 +69,41 @@ Blockly.Python['lists_indexOf'] = function(block) { } if (block.getFieldValue('END') === 'FIRST') { - const functionName = Blockly.Python.provideFunction_( - 'first_index', - ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + - '(my_list, elem):', - ' try: index = my_list.index(elem)' + firstIndexAdjustment, - ' except: index =' + errorIndex, - ' return index']); + const functionName = Python.provideFunction_('first_index', [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(my_list, elem):', + ' try: index = my_list.index(elem)' + firstIndexAdjustment, + ' except: index =' + errorIndex, ' return index' + ]); const code = functionName + '(' + list + ', ' + item + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; } - const 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']); + const functionName = Python.provideFunction_('last_index', [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(my_list, elem):', + ' try: index = len(my_list) - my_list[::-1].index(elem)' + + lastIndexAdjustment, + ' except: index =' + errorIndex, ' return index' + ]); const code = functionName + '(' + list + ', ' + item + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['lists_getIndex'] = function(block) { +Python['lists_getIndex'] = function(block) { // Get element at index. // Note: Until January 2013 this block did not have MODE or WHERE inputs. const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; - const listOrder = (where === 'RANDOM') ? Blockly.Python.ORDER_NONE : - Blockly.Python.ORDER_MEMBER; - const list = Blockly.Python.valueToCode(block, 'VALUE', listOrder) || '[]'; + const listOrder = + (where === 'RANDOM') ? Python.ORDER_NONE : Python.ORDER_MEMBER; + const list = Python.valueToCode(block, 'VALUE', listOrder) || '[]'; switch (where) { case 'FIRST': if (mode === 'GET') { const code = list + '[0]'; - return [code, Blockly.Python.ORDER_MEMBER]; + return [code, Python.ORDER_MEMBER]; } else if (mode === 'GET_REMOVE') { const code = list + '.pop(0)'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; } else if (mode === 'REMOVE') { return list + '.pop(0)\n'; } @@ -119,54 +111,55 @@ Blockly.Python['lists_getIndex'] = function(block) { case 'LAST': if (mode === 'GET') { const code = list + '[-1]'; - return [code, Blockly.Python.ORDER_MEMBER]; + return [code, Python.ORDER_MEMBER]; } else if (mode === 'GET_REMOVE') { const code = list + '.pop()'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; } else if (mode === 'REMOVE') { return list + '.pop()\n'; } break; case 'FROM_START': { - const at = Blockly.Python.getAdjustedInt(block, 'AT'); + const at = Python.getAdjustedInt(block, 'AT'); if (mode === 'GET') { const code = list + '[' + at + ']'; - return [code, Blockly.Python.ORDER_MEMBER]; + return [code, Python.ORDER_MEMBER]; } else if (mode === 'GET_REMOVE') { const code = list + '.pop(' + at + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; } else if (mode === 'REMOVE') { return list + '.pop(' + at + ')\n'; } break; } - case'FROM_END': { - const at = Blockly.Python.getAdjustedInt(block, 'AT', 1, true); + case 'FROM_END': { + const at = Python.getAdjustedInt(block, 'AT', 1, true); if (mode === 'GET') { const code = list + '[' + at + ']'; - return [code, Blockly.Python.ORDER_MEMBER]; + return [code, Python.ORDER_MEMBER]; } else if (mode === 'GET_REMOVE') { const code = list + '.pop(' + at + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; } else if (mode === 'REMOVE') { return list + '.pop(' + at + ')\n'; } break; } case 'RANDOM': - Blockly.Python.definitions_['import_random'] = 'import random'; + Python.definitions_['import_random'] = 'import random'; if (mode === 'GET') { const code = 'random.choice(' + list + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; } else { - const functionName = Blockly.Python.provideFunction_( - 'lists_remove_random_item', - ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):', + const functionName = + Python.provideFunction_('lists_remove_random_item', [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):', ' x = int(random.random() * len(myList))', - ' return myList.pop(x)']); + ' return myList.pop(x)' + ]); const code = functionName + '(' + list + ')'; if (mode === 'GET_REMOVE') { - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; } else if (mode === 'REMOVE') { return code + '\n'; } @@ -176,23 +169,21 @@ Blockly.Python['lists_getIndex'] = function(block) { throw Error('Unhandled combination (lists_getIndex).'); }; -Blockly.Python['lists_setIndex'] = function(block) { +Python['lists_setIndex'] = function(block) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. - let list = Blockly.Python.valueToCode(block, 'LIST', - Blockly.Python.ORDER_MEMBER) || '[]'; + let list = Python.valueToCode(block, 'LIST', Python.ORDER_MEMBER) || '[]'; const mode = block.getFieldValue('MODE') || 'GET'; const where = block.getFieldValue('WHERE') || 'FROM_START'; - const value = Blockly.Python.valueToCode(block, 'TO', - Blockly.Python.ORDER_NONE) || 'None'; + const value = Python.valueToCode(block, 'TO', Python.ORDER_NONE) || 'None'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. function cacheList() { if (list.match(/^\w+$/)) { return ''; } - const listVar = Blockly.Python.nameDB_.getDistinctName( - 'tmp_list', Blockly.VARIABLE_CATEGORY_NAME); + const listVar = + Python.nameDB_.getDistinctName('tmp_list', NameType.VARIABLE); const code = listVar + ' = ' + list + '\n'; list = listVar; return code; @@ -207,65 +198,63 @@ Blockly.Python['lists_setIndex'] = function(block) { } break; case 'LAST': - if (mode === 'SET') { - return list + '[-1] = ' + value + '\n'; - } else if (mode === 'INSERT') { - return list + '.append(' + value + ')\n'; - } + if (mode === 'SET') { + return list + '[-1] = ' + value + '\n'; + } else if (mode === 'INSERT') { + return list + '.append(' + value + ')\n'; + } break; case 'FROM_START': { - const at = Blockly.Python.getAdjustedInt(block, 'AT'); - if (mode === 'SET') { - return list + '[' + at + '] = ' + value + '\n'; - } else if (mode === 'INSERT') { - return list + '.insert(' + at + ', ' + value + ')\n'; - } + const at = 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': { - const 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'; - } + const at = 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'; - let code = cacheList(); - const xVar = Blockly.Python.nameDB_.getDistinctName( - 'tmp_x', Blockly.VARIABLE_CATEGORY_NAME); - 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; - } + Python.definitions_['import_random'] = 'import random'; + let code = cacheList(); + const xVar = Python.nameDB_.getDistinctName('tmp_x', NameType.VARIABLE); + 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 Error('Unhandled combination (lists_setIndex).'); }; -Blockly.Python['lists_getSublist'] = function(block) { +Python['lists_getSublist'] = function(block) { // Get sublist. - const list = Blockly.Python.valueToCode(block, 'LIST', - Blockly.Python.ORDER_MEMBER) || '[]'; + const list = Python.valueToCode(block, 'LIST', Python.ORDER_MEMBER) || '[]'; const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); let at1; switch (where1) { case 'FROM_START': - at1 = Blockly.Python.getAdjustedInt(block, 'AT1'); + at1 = Python.getAdjustedInt(block, 'AT1'); if (at1 === 0) { at1 = ''; } break; case 'FROM_END': - at1 = Blockly.Python.getAdjustedInt(block, 'AT1', 1, true); + at1 = Python.getAdjustedInt(block, 'AT1', 1, true); break; case 'FIRST': at1 = ''; @@ -277,14 +266,14 @@ Blockly.Python['lists_getSublist'] = function(block) { let at2; switch (where2) { case 'FROM_START': - at2 = Blockly.Python.getAdjustedInt(block, 'AT2', 1); + at2 = Python.getAdjustedInt(block, 'AT2', 1); break; case 'FROM_END': - at2 = Blockly.Python.getAdjustedInt(block, 'AT2', 0, true); + at2 = 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.utils.string.isNumber(String(at2))) { - Blockly.Python.definitions_['import_sys'] = 'import sys'; + if (!stringUtils.isNumber(String(at2))) { + Python.definitions_['import_sys'] = 'import sys'; at2 += ' or sys.maxsize'; } else if (at2 === 0) { at2 = ''; @@ -297,66 +286,53 @@ Blockly.Python['lists_getSublist'] = function(block) { throw Error('Unhandled option (lists_getSublist)'); } const code = list + '[' + at1 + ' : ' + at2 + ']'; - return [code, Blockly.Python.ORDER_MEMBER]; + return [code, Python.ORDER_MEMBER]; }; -Blockly.Python['lists_sort'] = function(block) { +Python['lists_sort'] = function(block) { // Block for sorting a list. - const list = (Blockly.Python.valueToCode(block, 'LIST', - Blockly.Python.ORDER_NONE) || '[]'); + const list = (Python.valueToCode(block, 'LIST', Python.ORDER_NONE) || '[]'); const type = block.getFieldValue('TYPE'); const reverse = block.getFieldValue('DIRECTION') === '1' ? 'False' : 'True'; - const sortFunctionName = Blockly.Python.provideFunction_('lists_sort', - ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + - '(my_list, type, reverse):', - ' def try_float(s):', - ' try:', - ' return float(s)', - ' except:', - ' return 0', - ' key_funcs = {', - ' "NUMERIC": try_float,', - ' "TEXT": str,', - ' "IGNORE_CASE": lambda s: str(s).lower()', - ' }', + const sortFunctionName = Python.provideFunction_('lists_sort', [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(my_list, type, reverse):', + ' def try_float(s):', ' try:', ' return float(s)', ' except:', + ' return 0', ' key_funcs = {', ' "NUMERIC": try_float,', + ' "TEXT": str,', ' "IGNORE_CASE": lambda s: str(s).lower()', ' }', ' key_func = key_funcs[type]', - ' list_cpy = list(my_list)', // Clone the list. + ' list_cpy = list(my_list)', // Clone the list. ' return sorted(list_cpy, key=key_func, reverse=reverse)' ]); - const code = sortFunctionName + - '(' + list + ', "' + type + '", ' + reverse + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + const code = + sortFunctionName + '(' + list + ', "' + type + '", ' + reverse + ')'; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['lists_split'] = function(block) { +Python['lists_split'] = function(block) { // Block for splitting text into a list, or joining a list into text. const mode = block.getFieldValue('MODE'); let code; if (mode === 'SPLIT') { - const value_input = Blockly.Python.valueToCode(block, 'INPUT', - Blockly.Python.ORDER_MEMBER) || '\'\''; - const value_delim = - Blockly.Python.valueToCode(block, 'DELIM', Blockly.Python.ORDER_NONE); + const value_input = + Python.valueToCode(block, 'INPUT', Python.ORDER_MEMBER) || '\'\''; + const value_delim = Python.valueToCode(block, 'DELIM', Python.ORDER_NONE); code = value_input + '.split(' + value_delim + ')'; } else if (mode === 'JOIN') { const value_input = - Blockly.Python.valueToCode(block, 'INPUT', Blockly.Python.ORDER_NONE) || - '[]'; - const value_delim = Blockly.Python.valueToCode( - block, 'DELIM', Blockly.Python.ORDER_MEMBER) || - '\'\''; + Python.valueToCode(block, 'INPUT', Python.ORDER_NONE) || '[]'; + const value_delim = + Python.valueToCode(block, 'DELIM', Python.ORDER_MEMBER) || '\'\''; code = value_delim + '.join(' + value_input + ')'; } else { throw Error('Unknown mode: ' + mode); } - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['lists_reverse'] = function(block) { +Python['lists_reverse'] = function(block) { // Block for reversing a list. - const list = Blockly.Python.valueToCode(block, 'LIST', - Blockly.Python.ORDER_NONE) || '[]'; + const list = Python.valueToCode(block, 'LIST', Python.ORDER_NONE) || '[]'; const code = 'list(reversed(' + list + '))'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; diff --git a/generators/python/logic.js b/generators/python/logic.js index dfde8856183..18dd9c53e32 100644 --- a/generators/python/logic.js +++ b/generators/python/logic.js @@ -9,73 +9,67 @@ */ 'use strict'; -goog.provide('Blockly.Python.logic'); +goog.module('Blockly.Python.logic'); -goog.require('Blockly.Python'); +const Python = goog.require('Blockly.Python'); -Blockly.Python['controls_if'] = function(block) { +Python['controls_if'] = function(block) { // If/elseif/else condition. let n = 0; let code = '', branchCode, conditionCode; - if (Blockly.Python.STATEMENT_PREFIX) { + if (Python.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. - code += Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, block); + code += Python.injectId(Python.STATEMENT_PREFIX, block); } do { - conditionCode = Blockly.Python.valueToCode(block, 'IF' + n, - Blockly.Python.ORDER_NONE) || 'False'; - branchCode = Blockly.Python.statementToCode(block, 'DO' + n) || - Blockly.Python.PASS; - if (Blockly.Python.STATEMENT_SUFFIX) { - branchCode = Blockly.Python.prefixLines( - Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block), - Blockly.Python.INDENT) + branchCode; + conditionCode = + Python.valueToCode(block, 'IF' + n, Python.ORDER_NONE) || 'False'; + branchCode = Python.statementToCode(block, 'DO' + n) || Python.PASS; + if (Python.STATEMENT_SUFFIX) { + branchCode = + Python.prefixLines( + Python.injectId(Python.STATEMENT_SUFFIX, block), Python.INDENT) + + branchCode; } code += (n === 0 ? 'if ' : 'elif ') + conditionCode + ':\n' + branchCode; n++; } while (block.getInput('IF' + n)); - if (block.getInput('ELSE') || Blockly.Python.STATEMENT_SUFFIX) { - branchCode = Blockly.Python.statementToCode(block, 'ELSE') || - Blockly.Python.PASS; - if (Blockly.Python.STATEMENT_SUFFIX) { - branchCode = Blockly.Python.prefixLines( - Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block), - Blockly.Python.INDENT) + branchCode; + if (block.getInput('ELSE') || Python.STATEMENT_SUFFIX) { + branchCode = Python.statementToCode(block, 'ELSE') || Python.PASS; + if (Python.STATEMENT_SUFFIX) { + branchCode = + Python.prefixLines( + Python.injectId(Python.STATEMENT_SUFFIX, block), Python.INDENT) + + branchCode; } code += 'else:\n' + branchCode; } return code; }; -Blockly.Python['controls_ifelse'] = Blockly.Python['controls_if']; +Python['controls_ifelse'] = Python['controls_if']; -Blockly.Python['logic_compare'] = function(block) { +Python['logic_compare'] = function(block) { // Comparison operator. - const OPERATORS = { - 'EQ': '==', - 'NEQ': '!=', - 'LT': '<', - 'LTE': '<=', - 'GT': '>', - 'GTE': '>=' - }; + const OPERATORS = + {'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>='}; const operator = OPERATORS[block.getFieldValue('OP')]; - const order = Blockly.Python.ORDER_RELATIONAL; - const argument0 = Blockly.Python.valueToCode(block, 'A', order) || '0'; - const argument1 = Blockly.Python.valueToCode(block, 'B', order) || '0'; + const order = Python.ORDER_RELATIONAL; + const argument0 = Python.valueToCode(block, 'A', order) || '0'; + const argument1 = Python.valueToCode(block, 'B', order) || '0'; const code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; }; -Blockly.Python['logic_operation'] = function(block) { +Python['logic_operation'] = function(block) { // Operations 'and', 'or'. const operator = (block.getFieldValue('OP') === 'AND') ? 'and' : 'or'; - const order = (operator === 'and') ? Blockly.Python.ORDER_LOGICAL_AND : - Blockly.Python.ORDER_LOGICAL_OR; - let argument0 = Blockly.Python.valueToCode(block, 'A', order); - let argument1 = Blockly.Python.valueToCode(block, 'B', order); + const order = + (operator === 'and') ? Python.ORDER_LOGICAL_AND : Python.ORDER_LOGICAL_OR; + let argument0 = Python.valueToCode(block, 'A', order); + let argument1 = Python.valueToCode(block, 'B', order); if (!argument0 && !argument1) { // If there are no arguments, then the return value is false. argument0 = 'False'; @@ -94,33 +88,33 @@ Blockly.Python['logic_operation'] = function(block) { return [code, order]; }; -Blockly.Python['logic_negate'] = function(block) { +Python['logic_negate'] = function(block) { // Negation. - const argument0 = Blockly.Python.valueToCode(block, 'BOOL', - Blockly.Python.ORDER_LOGICAL_NOT) || 'True'; + const argument0 = + Python.valueToCode(block, 'BOOL', Python.ORDER_LOGICAL_NOT) || 'True'; const code = 'not ' + argument0; - return [code, Blockly.Python.ORDER_LOGICAL_NOT]; + return [code, Python.ORDER_LOGICAL_NOT]; }; -Blockly.Python['logic_boolean'] = function(block) { +Python['logic_boolean'] = function(block) { // Boolean values true and false. const code = (block.getFieldValue('BOOL') === 'TRUE') ? 'True' : 'False'; - return [code, Blockly.Python.ORDER_ATOMIC]; + return [code, Python.ORDER_ATOMIC]; }; -Blockly.Python['logic_null'] = function(block) { +Python['logic_null'] = function(block) { // Null data type. - return ['None', Blockly.Python.ORDER_ATOMIC]; + return ['None', Python.ORDER_ATOMIC]; }; -Blockly.Python['logic_ternary'] = function(block) { +Python['logic_ternary'] = function(block) { // Ternary operator. - const value_if = Blockly.Python.valueToCode(block, 'IF', - Blockly.Python.ORDER_CONDITIONAL) || 'False'; - const value_then = Blockly.Python.valueToCode(block, 'THEN', - Blockly.Python.ORDER_CONDITIONAL) || 'None'; - const value_else = Blockly.Python.valueToCode(block, 'ELSE', - Blockly.Python.ORDER_CONDITIONAL) || 'None'; + const value_if = + Python.valueToCode(block, 'IF', Python.ORDER_CONDITIONAL) || 'False'; + const value_then = + Python.valueToCode(block, 'THEN', Python.ORDER_CONDITIONAL) || 'None'; + const value_else = + Python.valueToCode(block, 'ELSE', Python.ORDER_CONDITIONAL) || 'None'; const code = value_then + ' if ' + value_if + ' else ' + value_else; - return [code, Blockly.Python.ORDER_CONDITIONAL]; + return [code, Python.ORDER_CONDITIONAL]; }; diff --git a/generators/python/loops.js b/generators/python/loops.js index 85c64b6b93c..aff791d2175 100644 --- a/generators/python/loops.js +++ b/generators/python/loops.js @@ -6,17 +6,17 @@ /** * @fileoverview Generating Python for loop blocks. - * @suppress {missingRequire} */ 'use strict'; -goog.provide('Blockly.Python.loops'); +goog.module('Blockly.Python.loops'); -goog.require('Blockly.Python'); -goog.require('Blockly.utils.string'); +const Python = goog.require('Blockly.Python'); +const stringUtils = goog.require('Blockly.utils.string'); +const {NameType} = goog.require('Blockly.Names'); -Blockly.Python['controls_repeat_ext'] = function(block) { +Python['controls_repeat_ext'] = function(block) { // Repeat n times. let repeats; if (block.getField('TIMES')) { @@ -24,82 +24,72 @@ Blockly.Python['controls_repeat_ext'] = function(block) { repeats = String(parseInt(block.getFieldValue('TIMES'), 10)); } else { // External number. - repeats = Blockly.Python.valueToCode(block, 'TIMES', - Blockly.Python.ORDER_NONE) || '0'; + repeats = Python.valueToCode(block, 'TIMES', Python.ORDER_NONE) || '0'; } - if (Blockly.utils.string.isNumber(repeats)) { + if (stringUtils.isNumber(repeats)) { repeats = parseInt(repeats, 10); } else { repeats = 'int(' + repeats + ')'; } - let branch = Blockly.Python.statementToCode(block, 'DO'); - branch = Blockly.Python.addLoopTrap(branch, block) || Blockly.Python.PASS; - const loopVar = Blockly.Python.nameDB_.getDistinctName( - 'count', Blockly.VARIABLE_CATEGORY_NAME); + let branch = Python.statementToCode(block, 'DO'); + branch = Python.addLoopTrap(branch, block) || Python.PASS; + const loopVar = Python.nameDB_.getDistinctName('count', NameType.VARIABLE); const code = 'for ' + loopVar + ' in range(' + repeats + '):\n' + branch; return code; }; -Blockly.Python['controls_repeat'] = Blockly.Python['controls_repeat_ext']; +Python['controls_repeat'] = Python['controls_repeat_ext']; -Blockly.Python['controls_whileUntil'] = function(block) { +Python['controls_whileUntil'] = function(block) { // Do while/until loop. const until = block.getFieldValue('MODE') === 'UNTIL'; - let argument0 = Blockly.Python.valueToCode(block, 'BOOL', - until ? Blockly.Python.ORDER_LOGICAL_NOT : - Blockly.Python.ORDER_NONE) || 'False'; - let branch = Blockly.Python.statementToCode(block, 'DO'); - branch = Blockly.Python.addLoopTrap(branch, block) || Blockly.Python.PASS; + let argument0 = Python.valueToCode( + block, 'BOOL', + until ? Python.ORDER_LOGICAL_NOT : Python.ORDER_NONE) || + 'False'; + let branch = Python.statementToCode(block, 'DO'); + branch = Python.addLoopTrap(branch, block) || Python.PASS; if (until) { argument0 = 'not ' + argument0; } return 'while ' + argument0 + ':\n' + branch; }; -Blockly.Python['controls_for'] = function(block) { +Python['controls_for'] = function(block) { // For loop. - const variable0 = Blockly.Python.nameDB_.getName( - block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); - let argument0 = Blockly.Python.valueToCode(block, 'FROM', - Blockly.Python.ORDER_NONE) || '0'; - let argument1 = Blockly.Python.valueToCode(block, 'TO', - Blockly.Python.ORDER_NONE) || '0'; - let increment = Blockly.Python.valueToCode(block, 'BY', - Blockly.Python.ORDER_NONE) || '1'; - let branch = Blockly.Python.statementToCode(block, 'DO'); - branch = Blockly.Python.addLoopTrap(branch, block) || Blockly.Python.PASS; + const variable0 = + Python.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE); + let argument0 = Python.valueToCode(block, 'FROM', Python.ORDER_NONE) || '0'; + let argument1 = Python.valueToCode(block, 'TO', Python.ORDER_NONE) || '0'; + let increment = Python.valueToCode(block, 'BY', Python.ORDER_NONE) || '1'; + let branch = Python.statementToCode(block, 'DO'); + branch = Python.addLoopTrap(branch, block) || Python.PASS; let code = ''; let range; // Helper functions. const defineUpRange = function() { - return Blockly.Python.provideFunction_( - 'upRange', - ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + - '(start, stop, step):', - ' while start <= stop:', - ' yield start', - ' start += abs(step)']); + return Python.provideFunction_('upRange', [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(start, stop, step):', + ' while start <= stop:', ' yield start', ' start += abs(step)' + ]); }; const defineDownRange = function() { - return Blockly.Python.provideFunction_( - 'downRange', - ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + - '(start, stop, step):', - ' while start >= stop:', - ' yield start', - ' start -= abs(step)']); + return Python.provideFunction_('downRange', [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(start, stop, step):', + ' while start >= stop:', ' yield start', ' start -= abs(step)' + ]); }; // Arguments are legal Python code (numbers or strings returned by scrub()). const generateUpDownRange = function(start, end, inc) { - return '(' + start + ' <= ' + end + ') and ' + - defineUpRange() + '(' + start + ', ' + end + ', ' + inc + ') or ' + - defineDownRange() + '(' + start + ', ' + end + ', ' + inc + ')'; + return '(' + start + ' <= ' + end + ') and ' + defineUpRange() + '(' + + start + ', ' + end + ', ' + inc + ') or ' + defineDownRange() + '(' + + start + ', ' + end + ', ' + inc + ')'; }; - if (Blockly.utils.string.isNumber(argument0) && Blockly.utils.string.isNumber(argument1) && - Blockly.utils.string.isNumber(increment)) { + if (stringUtils.isNumber(argument0) && stringUtils.isNumber(argument1) && + stringUtils.isNumber(increment)) { // All parameters are simple numbers. argument0 = Number(argument0); argument1 = Number(argument1); @@ -137,7 +127,7 @@ Blockly.Python['controls_for'] = function(block) { } else { // Cache non-trivial values to variables to prevent repeated look-ups. const scrub = function(arg, suffix) { - if (Blockly.utils.string.isNumber(arg)) { + if (stringUtils.isNumber(arg)) { // Simple number. arg = Number(arg); } else if (arg.match(/^\w+$/)) { @@ -145,8 +135,8 @@ Blockly.Python['controls_for'] = function(block) { arg = 'float(' + arg + ')'; } else { // It's complicated. - const varName = Blockly.Python.nameDB_.getDistinctName( - variable0 + suffix, Blockly.VARIABLE_CATEGORY_NAME); + const varName = Python.nameDB_.getDistinctName( + variable0 + suffix, NameType.VARIABLE); code += varName + ' = float(' + arg + ')\n'; arg = varName; } @@ -172,37 +162,37 @@ Blockly.Python['controls_for'] = function(block) { return code; }; -Blockly.Python['controls_forEach'] = function(block) { +Python['controls_forEach'] = function(block) { // For each loop. - const variable0 = Blockly.Python.nameDB_.getName( - block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); - const argument0 = Blockly.Python.valueToCode(block, 'LIST', - Blockly.Python.ORDER_RELATIONAL) || '[]'; - let branch = Blockly.Python.statementToCode(block, 'DO'); - branch = Blockly.Python.addLoopTrap(branch, block) || Blockly.Python.PASS; + const variable0 = + Python.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE); + const argument0 = + Python.valueToCode(block, 'LIST', Python.ORDER_RELATIONAL) || '[]'; + let branch = Python.statementToCode(block, 'DO'); + branch = Python.addLoopTrap(branch, block) || Python.PASS; const code = 'for ' + variable0 + ' in ' + argument0 + ':\n' + branch; return code; }; -Blockly.Python['controls_flow_statements'] = function(block) { +Python['controls_flow_statements'] = function(block) { // Flow statements: continue, break. let xfix = ''; - if (Blockly.Python.STATEMENT_PREFIX) { + if (Python.STATEMENT_PREFIX) { // Automatic prefix insertion is switched off for this block. Add manually. - xfix += Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, block); + xfix += Python.injectId(Python.STATEMENT_PREFIX, block); } - if (Blockly.Python.STATEMENT_SUFFIX) { + if (Python.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the break/continue is triggered. - xfix += Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block); + xfix += Python.injectId(Python.STATEMENT_SUFFIX, block); } - if (Blockly.Python.STATEMENT_PREFIX) { + if (Python.STATEMENT_PREFIX) { const loop = block.getSurroundLoop(); if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. // In the case of 'break', a prefix is needed due to the loop's suffix. - xfix += Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, loop); + xfix += Python.injectId(Python.STATEMENT_PREFIX, loop); } } switch (block.getFieldValue('FLOW')) { diff --git a/generators/python/math.js b/generators/python/math.js index 162318d9b21..9f4fdc983f0 100644 --- a/generators/python/math.js +++ b/generators/python/math.js @@ -6,49 +6,48 @@ /** * @fileoverview Generating Python for math blocks. - * @suppress {missingRequire} */ 'use strict'; -goog.provide('Blockly.Python.math'); +goog.module('Blockly.Python.math'); -goog.require('Blockly.Python'); +const Python = goog.require('Blockly.Python'); +const {NameType} = goog.require('Blockly.Names'); // If any new block imports any library, add that library name here. -Blockly.Python.addReservedWords('math,random,Number'); +Python.addReservedWords('math,random,Number'); -Blockly.Python['math_number'] = function(block) { +Python['math_number'] = function(block) { // Numeric value. let code = Number(block.getFieldValue('NUM')); let order; if (code === Infinity) { code = 'float("inf")'; - order = Blockly.Python.ORDER_FUNCTION_CALL; + order = Python.ORDER_FUNCTION_CALL; } else if (code === -Infinity) { code = '-float("inf")'; - order = Blockly.Python.ORDER_UNARY_SIGN; + order = Python.ORDER_UNARY_SIGN; } else { - order = code < 0 ? Blockly.Python.ORDER_UNARY_SIGN : - Blockly.Python.ORDER_ATOMIC; + order = code < 0 ? Python.ORDER_UNARY_SIGN : Python.ORDER_ATOMIC; } return [code, order]; }; -Blockly.Python['math_arithmetic'] = function(block) { +Python['math_arithmetic'] = function(block) { // Basic arithmetic operators, and power. const OPERATORS = { - '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] + 'ADD': [' + ', Python.ORDER_ADDITIVE], + 'MINUS': [' - ', Python.ORDER_ADDITIVE], + 'MULTIPLY': [' * ', Python.ORDER_MULTIPLICATIVE], + 'DIVIDE': [' / ', Python.ORDER_MULTIPLICATIVE], + 'POWER': [' ** ', Python.ORDER_EXPONENTIATION] }; const tuple = OPERATORS[block.getFieldValue('OP')]; const operator = tuple[0]; const order = tuple[1]; - const argument0 = Blockly.Python.valueToCode(block, 'A', order) || '0'; - const argument1 = Blockly.Python.valueToCode(block, 'B', order) || '0'; + const argument0 = Python.valueToCode(block, 'A', order) || '0'; + const argument1 = Python.valueToCode(block, 'B', order) || '0'; const code = argument0 + operator + argument1; return [code, order]; // In case of 'DIVIDE', division between integers returns different results @@ -58,24 +57,21 @@ Blockly.Python['math_arithmetic'] = function(block) { // legibility of the generated code. }; -Blockly.Python['math_single'] = function(block) { +Python['math_single'] = function(block) { // Math operators with single operand. const operator = block.getFieldValue('OP'); let code; let arg; if (operator === 'NEG') { // Negation is a special case given its different operator precedence. - code = Blockly.Python.valueToCode(block, 'NUM', - Blockly.Python.ORDER_UNARY_SIGN) || '0'; - return ['-' + code, Blockly.Python.ORDER_UNARY_SIGN]; + code = Python.valueToCode(block, 'NUM', Python.ORDER_UNARY_SIGN) || '0'; + return ['-' + code, Python.ORDER_UNARY_SIGN]; } - Blockly.Python.definitions_['import_math'] = 'import math'; + Python.definitions_['import_math'] = 'import math'; if (operator === 'SIN' || operator === 'COS' || operator === 'TAN') { - arg = Blockly.Python.valueToCode(block, 'NUM', - Blockly.Python.ORDER_MULTIPLICATIVE) || '0'; + arg = Python.valueToCode(block, 'NUM', Python.ORDER_MULTIPLICATIVE) || '0'; } else { - arg = Blockly.Python.valueToCode(block, 'NUM', - Blockly.Python.ORDER_NONE) || '0'; + arg = Python.valueToCode(block, 'NUM', Python.ORDER_NONE) || '0'; } // First, handle cases which generate values that don't need parentheses // wrapping the code. @@ -118,7 +114,7 @@ Blockly.Python['math_single'] = function(block) { break; } if (code) { - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; } // Second, handle cases which generate values that may need parentheses // wrapping the code. @@ -135,61 +131,57 @@ Blockly.Python['math_single'] = function(block) { default: throw Error('Unknown math operator: ' + operator); } - return [code, Blockly.Python.ORDER_MULTIPLICATIVE]; + return [code, Python.ORDER_MULTIPLICATIVE]; }; -Blockly.Python['math_constant'] = function(block) { +Python['math_constant'] = function(block) { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. const CONSTANTS = { - 'PI': ['math.pi', Blockly.Python.ORDER_MEMBER], - 'E': ['math.e', Blockly.Python.ORDER_MEMBER], - 'GOLDEN_RATIO': ['(1 + math.sqrt(5)) / 2', - Blockly.Python.ORDER_MULTIPLICATIVE], - 'SQRT2': ['math.sqrt(2)', Blockly.Python.ORDER_MEMBER], - 'SQRT1_2': ['math.sqrt(1.0 / 2)', Blockly.Python.ORDER_MEMBER], - 'INFINITY': ['float(\'inf\')', Blockly.Python.ORDER_ATOMIC] + 'PI': ['math.pi', Python.ORDER_MEMBER], + 'E': ['math.e', Python.ORDER_MEMBER], + 'GOLDEN_RATIO': ['(1 + math.sqrt(5)) / 2', Python.ORDER_MULTIPLICATIVE], + 'SQRT2': ['math.sqrt(2)', Python.ORDER_MEMBER], + 'SQRT1_2': ['math.sqrt(1.0 / 2)', Python.ORDER_MEMBER], + 'INFINITY': ['float(\'inf\')', Python.ORDER_ATOMIC] }; const constant = block.getFieldValue('CONSTANT'); if (constant !== 'INFINITY') { - Blockly.Python.definitions_['import_math'] = 'import math'; + Python.definitions_['import_math'] = 'import math'; } return CONSTANTS[constant]; }; -Blockly.Python['math_number_property'] = function(block) { +Python['math_number_property'] = function(block) { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. - const number_to_check = Blockly.Python.valueToCode(block, 'NUMBER_TO_CHECK', - Blockly.Python.ORDER_MULTIPLICATIVE) || '0'; + const number_to_check = + Python.valueToCode( + block, 'NUMBER_TO_CHECK', Python.ORDER_MULTIPLICATIVE) || + '0'; const dropdown_property = block.getFieldValue('PROPERTY'); let code; if (dropdown_property === 'PRIME') { - Blockly.Python.definitions_['import_math'] = 'import math'; - Blockly.Python.definitions_['from_numbers_import_Number'] = + Python.definitions_['import_math'] = 'import math'; + Python.definitions_['from_numbers_import_Number'] = 'from numbers import Number'; - const functionName = Blockly.Python.provideFunction_( - 'math_isPrime', - ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(n):', - ' # https://en.wikipedia.org/wiki/Primality_test#Naive_methods', - ' # If n is not a number but a string, try parsing it.', - ' if not isinstance(n, Number):', - ' try:', - ' n = float(n)', - ' except:', - ' return False', - ' if n == 2 or n == 3:', - ' return True', - ' # False if n is negative, is 1, or not whole,' + - ' or if n is divisible by 2 or 3.', - ' if n <= 1 or n % 1 != 0 or n % 2 == 0 or n % 3 == 0:', - ' return False', - ' # Check all the numbers of form 6k +/- 1, up to sqrt(n).', - ' for x in range(6, int(math.sqrt(n)) + 2, 6):', - ' if n % (x - 1) == 0 or n % (x + 1) == 0:', - ' return False', - ' return True']); + const functionName = Python.provideFunction_('math_isPrime', [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(n):', + ' # https://en.wikipedia.org/wiki/Primality_test#Naive_methods', + ' # If n is not a number but a string, try parsing it.', + ' if not isinstance(n, Number):', ' try:', ' n = float(n)', + ' except:', ' return False', + ' if n == 2 or n == 3:', ' return True', + ' # False if n is negative, is 1, or not whole,' + + ' or if n is divisible by 2 or 3.', + ' if n <= 1 or n % 1 != 0 or n % 2 == 0 or n % 3 == 0:', + ' return False', + ' # Check all the numbers of form 6k +/- 1, up to sqrt(n).', + ' for x in range(6, int(math.sqrt(n)) + 2, 6):', + ' if n % (x - 1) == 0 or n % (x + 1) == 0:', ' return False', + ' return True' + ]); code = functionName + '(' + number_to_check + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; } switch (dropdown_property) { case 'EVEN': @@ -208,41 +200,40 @@ Blockly.Python['math_number_property'] = function(block) { code = number_to_check + ' < 0'; break; case 'DIVISIBLE_BY': { - const divisor = Blockly.Python.valueToCode(block, 'DIVISOR', - Blockly.Python.ORDER_MULTIPLICATIVE); + const divisor = + Python.valueToCode(block, 'DIVISOR', Python.ORDER_MULTIPLICATIVE); // If 'divisor' is some code that evals to 0, Python will raise an error. if (!divisor || divisor === '0') { - return ['False', Blockly.Python.ORDER_ATOMIC]; + return ['False', Python.ORDER_ATOMIC]; } code = number_to_check + ' % ' + divisor + ' == 0'; break; } } - return [code, Blockly.Python.ORDER_RELATIONAL]; + return [code, Python.ORDER_RELATIONAL]; }; -Blockly.Python['math_change'] = function(block) { +Python['math_change'] = function(block) { // Add to a variable in place. - Blockly.Python.definitions_['from_numbers_import_Number'] = + Python.definitions_['from_numbers_import_Number'] = 'from numbers import Number'; - const argument0 = Blockly.Python.valueToCode(block, 'DELTA', - Blockly.Python.ORDER_ADDITIVE) || '0'; - const varName = Blockly.Python.nameDB_.getName(block.getFieldValue('VAR'), - Blockly.VARIABLE_CATEGORY_NAME); + const argument0 = + Python.valueToCode(block, 'DELTA', Python.ORDER_ADDITIVE) || '0'; + const varName = + Python.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE); return varName + ' = (' + varName + ' if isinstance(' + varName + ', Number) else 0) + ' + argument0 + '\n'; }; // Rounding functions have a single operand. -Blockly.Python['math_round'] = Blockly.Python['math_single']; +Python['math_round'] = Python['math_single']; // Trigonometry functions have a single operand. -Blockly.Python['math_trig'] = Blockly.Python['math_single']; +Python['math_trig'] = Python['math_single']; -Blockly.Python['math_on_list'] = function(block) { +Python['math_on_list'] = function(block) { // Math functions for lists. const func = block.getFieldValue('OP'); - const list = Blockly.Python.valueToCode(block, 'LIST', - Blockly.Python.ORDER_NONE) || '[]'; + const list = Python.valueToCode(block, 'LIST', Python.ORDER_NONE) || '[]'; let code; switch (func) { case 'SUM': @@ -255,136 +246,130 @@ Blockly.Python['math_on_list'] = function(block) { code = 'max(' + list + ')'; break; case 'AVERAGE': { - Blockly.Python.definitions_['from_numbers_import_Number'] = + Python.definitions_['from_numbers_import_Number'] = 'from numbers import Number'; - const functionName = Blockly.Python.provideFunction_( + const functionName = Python.provideFunction_( 'math_mean', // This operation excludes null and values that aren't int or float: // math_mean([null, null, "aString", 1, 9]) -> 5.0 - ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):', - ' localList = [e for e in myList if isinstance(e, Number)]', - ' if not localList: return', - ' return float(sum(localList)) / len(localList)']); + [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):', + ' localList = [e for e in myList if isinstance(e, Number)]', + ' if not localList: return', + ' return float(sum(localList)) / len(localList)' + ]); code = functionName + '(' + list + ')'; break; } case 'MEDIAN': { - Blockly.Python.definitions_['from_numbers_import_Number'] = + Python.definitions_['from_numbers_import_Number'] = 'from numbers import Number'; - const functionName = Blockly.Python.provideFunction_( + const functionName = Python.provideFunction_( 'math_median', // This operation excludes null values: // math_median([null, null, 1, 3]) -> 2.0 - ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):', - ' localList = sorted([e for e in myList if isinstance(e, Number)])', - ' if not localList: return', - ' if len(localList) % 2 == 0:', - ' return (localList[len(localList) // 2 - 1] + ' + - 'localList[len(localList) // 2]) / 2.0', - ' else:', - ' return localList[(len(localList) - 1) // 2]']); + [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):', + ' localList = sorted([e for e in myList if isinstance(e, Number)])', + ' if not localList: return', ' if len(localList) % 2 == 0:', + ' return (localList[len(localList) // 2 - 1] + ' + + 'localList[len(localList) // 2]) / 2.0', + ' else:', ' return localList[(len(localList) - 1) // 2]' + ]); code = functionName + '(' + list + ')'; break; } case 'MODE': { - const functionName = Blockly.Python.provideFunction_( + const functionName = Python.provideFunction_( 'math_modes', // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1] - ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(some_list):', - ' modes = []', - ' # Using a lists of [item, count] to keep count rather than dict', - ' # to avoid "unhashable" errors when the counted item is ' + - 'itself a list or dict.', - ' counts = []', - ' maxCount = 1', - ' for item in some_list:', - ' found = False', - ' for count in counts:', - ' if count[0] == item:', - ' count[1] += 1', - ' maxCount = max(maxCount, count[1])', - ' found = True', - ' if not found:', - ' counts.append([item, 1])', - ' for counted_item, item_count in counts:', - ' if item_count == maxCount:', - ' modes.append(counted_item)', - ' return modes']); + [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(some_list):', + ' modes = []', + ' # Using a lists of [item, count] to keep count rather than dict', + ' # to avoid "unhashable" errors when the counted item is ' + + 'itself a list or dict.', + ' counts = []', ' maxCount = 1', ' for item in some_list:', + ' found = False', ' for count in counts:', + ' if count[0] == item:', ' count[1] += 1', + ' maxCount = max(maxCount, count[1])', + ' found = True', + ' if not found:', ' counts.append([item, 1])', + ' for counted_item, item_count in counts:', + ' if item_count == maxCount:', + ' modes.append(counted_item)', ' return modes' + ]); code = functionName + '(' + list + ')'; break; } case 'STD_DEV': { - Blockly.Python.definitions_['import_math'] = 'import math'; - const functionName = Blockly.Python.provideFunction_( - 'math_standard_deviation', - ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(numbers):', - ' n = len(numbers)', - ' if n == 0: return', - ' mean = float(sum(numbers)) / n', - ' variance = sum((x - mean) ** 2 for x in numbers) / n', - ' return math.sqrt(variance)']); + Python.definitions_['import_math'] = 'import math'; + const functionName = Python.provideFunction_('math_standard_deviation', [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(numbers):', + ' n = len(numbers)', ' if n == 0: return', + ' mean = float(sum(numbers)) / n', + ' variance = sum((x - mean) ** 2 for x in numbers) / n', + ' return math.sqrt(variance)' + ]); code = functionName + '(' + list + ')'; break; } case 'RANDOM': - Blockly.Python.definitions_['import_random'] = 'import random'; + Python.definitions_['import_random'] = 'import random'; code = 'random.choice(' + list + ')'; break; default: throw Error('Unknown operator: ' + func); } - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['math_modulo'] = function(block) { +Python['math_modulo'] = function(block) { // Remainder computation. - const argument0 = Blockly.Python.valueToCode(block, 'DIVIDEND', - Blockly.Python.ORDER_MULTIPLICATIVE) || '0'; - const argument1 = Blockly.Python.valueToCode(block, 'DIVISOR', - Blockly.Python.ORDER_MULTIPLICATIVE) || '0'; + const argument0 = + Python.valueToCode(block, 'DIVIDEND', Python.ORDER_MULTIPLICATIVE) || '0'; + const argument1 = + Python.valueToCode(block, 'DIVISOR', Python.ORDER_MULTIPLICATIVE) || '0'; const code = argument0 + ' % ' + argument1; - return [code, Blockly.Python.ORDER_MULTIPLICATIVE]; + return [code, Python.ORDER_MULTIPLICATIVE]; }; -Blockly.Python['math_constrain'] = function(block) { +Python['math_constrain'] = function(block) { // Constrain a number between two limits. - const argument0 = Blockly.Python.valueToCode(block, 'VALUE', - Blockly.Python.ORDER_NONE) || '0'; - const argument1 = Blockly.Python.valueToCode(block, 'LOW', - Blockly.Python.ORDER_NONE) || '0'; - const argument2 = Blockly.Python.valueToCode(block, 'HIGH', - Blockly.Python.ORDER_NONE) || 'float(\'inf\')'; - const code = 'min(max(' + argument0 + ', ' + argument1 + '), ' + - argument2 + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + const argument0 = + Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || '0'; + const argument1 = Python.valueToCode(block, 'LOW', Python.ORDER_NONE) || '0'; + const argument2 = + Python.valueToCode(block, 'HIGH', Python.ORDER_NONE) || 'float(\'inf\')'; + const code = + 'min(max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['math_random_int'] = function(block) { +Python['math_random_int'] = function(block) { // Random integer between [X] and [Y]. - Blockly.Python.definitions_['import_random'] = 'import random'; - const argument0 = Blockly.Python.valueToCode(block, 'FROM', - Blockly.Python.ORDER_NONE) || '0'; - const argument1 = Blockly.Python.valueToCode(block, 'TO', - Blockly.Python.ORDER_NONE) || '0'; + Python.definitions_['import_random'] = 'import random'; + const argument0 = Python.valueToCode(block, 'FROM', Python.ORDER_NONE) || '0'; + const argument1 = Python.valueToCode(block, 'TO', Python.ORDER_NONE) || '0'; const code = 'random.randint(' + argument0 + ', ' + argument1 + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['math_random_float'] = function(block) { +Python['math_random_float'] = function(block) { // Random fraction between 0 and 1. - Blockly.Python.definitions_['import_random'] = 'import random'; - return ['random.random()', Blockly.Python.ORDER_FUNCTION_CALL]; + Python.definitions_['import_random'] = 'import random'; + return ['random.random()', Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['math_atan2'] = function(block) { +Python['math_atan2'] = function(block) { // Arctangent of point (X, Y) in degrees from -180 to 180. - Blockly.Python.definitions_['import_math'] = 'import math'; - const argument0 = Blockly.Python.valueToCode(block, 'X', - Blockly.Python.ORDER_NONE) || '0'; - const argument1 = Blockly.Python.valueToCode(block, 'Y', - Blockly.Python.ORDER_NONE) || '0'; - return ['math.atan2(' + argument1 + ', ' + argument0 + ') / math.pi * 180', - Blockly.Python.ORDER_MULTIPLICATIVE]; + Python.definitions_['import_math'] = 'import math'; + const argument0 = Python.valueToCode(block, 'X', Python.ORDER_NONE) || '0'; + const argument1 = Python.valueToCode(block, 'Y', Python.ORDER_NONE) || '0'; + return [ + 'math.atan2(' + argument1 + ', ' + argument0 + ') / math.pi * 180', + Python.ORDER_MULTIPLICATIVE + ]; }; diff --git a/generators/python/procedures.js b/generators/python/procedures.js index ae8f0b7c6eb..b95becd3d27 100644 --- a/generators/python/procedures.js +++ b/generators/python/procedures.js @@ -6,129 +6,124 @@ /** * @fileoverview Generating Python for procedure blocks. - * @suppress {missingRequire} */ 'use strict'; -goog.provide('Blockly.Python.procedures'); +goog.module('Blockly.Python.procedures'); -goog.require('Blockly.Python'); -goog.require('Blockly.Variables'); +const Python = goog.require('Blockly.Python'); +const Variables = goog.require('Blockly.Variables'); +const {NameType} = goog.require('Blockly.Names'); -Blockly.Python['procedures_defreturn'] = function(block) { +Python['procedures_defreturn'] = function(block) { // Define a procedure with a return value. // First, add a 'global' statement for every variable that is not shadowed by // a local parameter. const globals = []; const workspace = block.workspace; - const usedVariables = Blockly.Variables.allUsedVarModels(workspace) || []; + const usedVariables = Variables.allUsedVarModels(workspace) || []; for (let i = 0, variable; (variable = usedVariables[i]); i++) { const varName = variable.name; if (block.getVars().indexOf(varName) === -1) { - globals.push(Blockly.Python.nameDB_.getName(varName, - Blockly.VARIABLE_CATEGORY_NAME)); + globals.push(Python.nameDB_.getName(varName, NameType.VARIABLE)); } } // Add developer variables. - const devVarList = Blockly.Variables.allDeveloperVariables(workspace); + const devVarList = Variables.allDeveloperVariables(workspace); for (let i = 0; i < devVarList.length; i++) { - globals.push(Blockly.Python.nameDB_.getName(devVarList[i], - Blockly.Names.DEVELOPER_VARIABLE_TYPE)); + globals.push( + Python.nameDB_.getName(devVarList[i], NameType.DEVELOPER_VARIABLE)); } const globalString = globals.length ? - Blockly.Python.INDENT + 'global ' + globals.join(', ') + '\n' : ''; - const funcName = Blockly.Python.nameDB_.getName( - block.getFieldValue('NAME'), Blockly.PROCEDURE_CATEGORY_NAME); + Python.INDENT + 'global ' + globals.join(', ') + '\n' : + ''; + const funcName = + Python.nameDB_.getName(block.getFieldValue('NAME'), NameType.PROCEDURE); let xfix1 = ''; - if (Blockly.Python.STATEMENT_PREFIX) { - xfix1 += Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, block); + if (Python.STATEMENT_PREFIX) { + xfix1 += Python.injectId(Python.STATEMENT_PREFIX, block); } - if (Blockly.Python.STATEMENT_SUFFIX) { - xfix1 += Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block); + if (Python.STATEMENT_SUFFIX) { + xfix1 += Python.injectId(Python.STATEMENT_SUFFIX, block); } if (xfix1) { - xfix1 = Blockly.Python.prefixLines(xfix1, Blockly.Python.INDENT); + xfix1 = Python.prefixLines(xfix1, Python.INDENT); } let loopTrap = ''; - if (Blockly.Python.INFINITE_LOOP_TRAP) { - loopTrap = Blockly.Python.prefixLines( - Blockly.Python.injectId(Blockly.Python.INFINITE_LOOP_TRAP, block), - Blockly.Python.INDENT); + if (Python.INFINITE_LOOP_TRAP) { + loopTrap = Python.prefixLines( + Python.injectId(Python.INFINITE_LOOP_TRAP, block), Python.INDENT); } - let branch = Blockly.Python.statementToCode(block, 'STACK'); - let returnValue = Blockly.Python.valueToCode(block, 'RETURN', - Blockly.Python.ORDER_NONE) || ''; + let branch = Python.statementToCode(block, 'STACK'); + let returnValue = + Python.valueToCode(block, 'RETURN', Python.ORDER_NONE) || ''; let xfix2 = ''; if (branch && returnValue) { // After executing the function body, revisit this block for the return. xfix2 = xfix1; } if (returnValue) { - returnValue = Blockly.Python.INDENT + 'return ' + returnValue + '\n'; + returnValue = Python.INDENT + 'return ' + returnValue + '\n'; } else if (!branch) { - branch = Blockly.Python.PASS; + branch = Python.PASS; } const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = Blockly.Python.nameDB_.getName(variables[i], - Blockly.VARIABLE_CATEGORY_NAME); + args[i] = Python.nameDB_.getName(variables[i], NameType.VARIABLE); } let code = 'def ' + funcName + '(' + args.join(', ') + '):\n' + globalString + xfix1 + loopTrap + branch + xfix2 + returnValue; - code = Blockly.Python.scrub_(block, code); + code = Python.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. - Blockly.Python.definitions_['%' + funcName] = code; + Python.definitions_['%' + funcName] = code; return null; }; // Defining a procedure without a return value uses the same generator as // a procedure with a return value. -Blockly.Python['procedures_defnoreturn'] = - Blockly.Python['procedures_defreturn']; +Python['procedures_defnoreturn'] = Python['procedures_defreturn']; -Blockly.Python['procedures_callreturn'] = function(block) { +Python['procedures_callreturn'] = function(block) { // Call a procedure with a return value. - const funcName = Blockly.Python.nameDB_.getName(block.getFieldValue('NAME'), - Blockly.PROCEDURE_CATEGORY_NAME); + const funcName = + Python.nameDB_.getName(block.getFieldValue('NAME'), NameType.PROCEDURE); const args = []; const variables = block.getVars(); for (let i = 0; i < variables.length; i++) { - args[i] = Blockly.Python.valueToCode(block, 'ARG' + i, - Blockly.Python.ORDER_NONE) || 'None'; + args[i] = Python.valueToCode(block, 'ARG' + i, Python.ORDER_NONE) || 'None'; } const code = funcName + '(' + args.join(', ') + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['procedures_callnoreturn'] = function(block) { +Python['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. - const tuple = Blockly.Python['procedures_callreturn'](block); + const tuple = Python['procedures_callreturn'](block); return tuple[0] + '\n'; }; -Blockly.Python['procedures_ifreturn'] = function(block) { +Python['procedures_ifreturn'] = function(block) { // Conditionally return value from a procedure. - const condition = Blockly.Python.valueToCode(block, 'CONDITION', - Blockly.Python.ORDER_NONE) || 'False'; + const condition = + Python.valueToCode(block, 'CONDITION', Python.ORDER_NONE) || 'False'; let code = 'if ' + condition + ':\n'; - if (Blockly.Python.STATEMENT_SUFFIX) { + if (Python.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. - code += Blockly.Python.prefixLines( - Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block), - Blockly.Python.INDENT); + code += Python.prefixLines( + Python.injectId(Python.STATEMENT_SUFFIX, block), Python.INDENT); } if (block.hasReturnValue_) { - const value = Blockly.Python.valueToCode(block, 'VALUE', - Blockly.Python.ORDER_NONE) || 'None'; - code += Blockly.Python.INDENT + 'return ' + value + '\n'; + const value = + Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || 'None'; + code += Python.INDENT + 'return ' + value + '\n'; } else { - code += Blockly.Python.INDENT + 'return\n'; + code += Python.INDENT + 'return\n'; } return code; }; diff --git a/generators/python/text.js b/generators/python/text.js index 3164c5e58b1..4edb5d3b2d6 100644 --- a/generators/python/text.js +++ b/generators/python/text.js @@ -6,184 +6,175 @@ /** * @fileoverview Generating Python for text blocks. - * @suppress {missingRequire} */ 'use strict'; -goog.provide('Blockly.Python.texts'); +goog.module('Blockly.Python.texts'); -goog.require('Blockly.Python'); -goog.require('Blockly.utils.string'); +const Python = goog.require('Blockly.Python'); +const stringUtils = goog.require('Blockly.utils.string'); +const {NameType} = goog.require('Blockly.Names'); -Blockly.Python['text'] = function(block) { +Python['text'] = function(block) { // Text value. - const code = Blockly.Python.quote_(block.getFieldValue('TEXT')); - return [code, Blockly.Python.ORDER_ATOMIC]; + const code = Python.quote_(block.getFieldValue('TEXT')); + return [code, Python.ORDER_ATOMIC]; }; -Blockly.Python['text_multiline'] = function(block) { +Python['text_multiline'] = function(block) { // Text value. - const code = Blockly.Python.multiline_quote_(block.getFieldValue('TEXT')); - const order = code.indexOf('+') !== -1 ? Blockly.Python.ORDER_ADDITIVE : - Blockly.Python.ORDER_ATOMIC; + const code = Python.multiline_quote_(block.getFieldValue('TEXT')); + const order = + code.indexOf('+') !== -1 ? Python.ORDER_ADDITIVE : Python.ORDER_ATOMIC; return [code, order]; }; +/** + * Regular expression to detect a single-quoted string literal. + */ +const strRegExp = /^\s*'([^']|\\')*'\s*$/; + /** * Enclose the provided value in 'str(...)' function. * Leave string literals alone. * @param {string} value Code evaluating to a value. - * @return {Array} Array containing code evaluating to a string and + * @return {Array} Array containing code evaluating to a string + * and * the order of the returned code.[string, number] - * @private */ -Blockly.Python.text.forceString_ = function(value) { - if (Blockly.Python.text.forceString_.strRegExp.test(value)) { - return [value, Blockly.Python.ORDER_ATOMIC]; +const forceString = function(value) { + if (strRegExp.test(value)) { + return [value, Python.ORDER_ATOMIC]; } - return ['str(' + value + ')', Blockly.Python.ORDER_FUNCTION_CALL]; + return ['str(' + value + ')', Python.ORDER_FUNCTION_CALL]; }; -/** - * Regular expression to detect a single-quoted string literal. - */ -Blockly.Python.text.forceString_.strRegExp = /^\s*'([^']|\\')*'\s*$/; - -Blockly.Python['text_join'] = function(block) { +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? + // Should we allow joining by '-' or ',' or any other characters? switch (block.itemCount_) { case 0: - return ['\'\'', Blockly.Python.ORDER_ATOMIC]; + return ['\'\'', Python.ORDER_ATOMIC]; case 1: { - const element = Blockly.Python.valueToCode(block, 'ADD0', - Blockly.Python.ORDER_NONE) || '\'\''; - const codeAndOrder = Blockly.Python.text.forceString_(element); + const element = + Python.valueToCode(block, 'ADD0', Python.ORDER_NONE) || '\'\''; + const codeAndOrder = forceString(element); return codeAndOrder; } case 2: { - const element0 = Blockly.Python.valueToCode( - block, 'ADD0', Blockly.Python.ORDER_NONE) || - '\'\''; - const element1 = Blockly.Python.valueToCode( - block, 'ADD1', Blockly.Python.ORDER_NONE) || - '\'\''; - const code = Blockly.Python.text.forceString_(element0)[0] + ' + ' + - Blockly.Python.text.forceString_(element1)[0]; - return [code, Blockly.Python.ORDER_ADDITIVE]; + const element0 = + Python.valueToCode(block, 'ADD0', Python.ORDER_NONE) || '\'\''; + const element1 = + Python.valueToCode(block, 'ADD1', Python.ORDER_NONE) || '\'\''; + const code = forceString(element0)[0] + ' + ' + forceString(element1)[0]; + return [code, Python.ORDER_ADDITIVE]; } default: { const elements = []; for (let i = 0; i < block.itemCount_; i++) { - elements[i] = Blockly.Python.valueToCode(block, 'ADD' + i, - Blockly.Python.ORDER_NONE) || '\'\''; + elements[i] = + Python.valueToCode(block, 'ADD' + i, Python.ORDER_NONE) || '\'\''; } - const tempVar = Blockly.Python.nameDB_.getDistinctName( - 'x', Blockly.VARIABLE_CATEGORY_NAME); + const tempVar = Python.nameDB_.getDistinctName('x', NameType.VARIABLE); const code = '\'\'.join([str(' + tempVar + ') for ' + tempVar + ' in [' + elements.join(', ') + ']])'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; } } }; -Blockly.Python['text_append'] = function(block) { +Python['text_append'] = function(block) { // Append to a variable in place. - const varName = Blockly.Python.nameDB_.getName(block.getFieldValue('VAR'), - Blockly.VARIABLE_CATEGORY_NAME); - const value = Blockly.Python.valueToCode(block, 'TEXT', - Blockly.Python.ORDER_NONE) || '\'\''; - return varName + ' = str(' + varName + ') + ' + - Blockly.Python.text.forceString_(value)[0] + '\n'; + const varName = + Python.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE); + const value = Python.valueToCode(block, 'TEXT', Python.ORDER_NONE) || '\'\''; + return varName + ' = str(' + varName + ') + ' + forceString(value)[0] + '\n'; }; -Blockly.Python['text_length'] = function(block) { +Python['text_length'] = function(block) { // Is the string null or array empty? - const text = Blockly.Python.valueToCode(block, 'VALUE', - Blockly.Python.ORDER_NONE) || '\'\''; - return ['len(' + text + ')', Blockly.Python.ORDER_FUNCTION_CALL]; + const text = Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || '\'\''; + return ['len(' + text + ')', Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['text_isEmpty'] = function(block) { +Python['text_isEmpty'] = function(block) { // Is the string null or array empty? - const text = Blockly.Python.valueToCode(block, 'VALUE', - Blockly.Python.ORDER_NONE) || '\'\''; + const text = Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || '\'\''; const code = 'not len(' + text + ')'; - return [code, Blockly.Python.ORDER_LOGICAL_NOT]; + return [code, Python.ORDER_LOGICAL_NOT]; }; -Blockly.Python['text_indexOf'] = function(block) { +Python['text_indexOf'] = function(block) { // Search the text for a substring. // Should we allow for non-case sensitive??? const operator = block.getFieldValue('END') === 'FIRST' ? 'find' : 'rfind'; - const substring = Blockly.Python.valueToCode(block, 'FIND', - Blockly.Python.ORDER_NONE) || '\'\''; - const text = Blockly.Python.valueToCode(block, 'VALUE', - Blockly.Python.ORDER_MEMBER) || '\'\''; + const substring = + Python.valueToCode(block, 'FIND', Python.ORDER_NONE) || '\'\''; + const text = + Python.valueToCode(block, 'VALUE', Python.ORDER_MEMBER) || '\'\''; const code = text + '.' + operator + '(' + substring + ')'; if (block.workspace.options.oneBasedIndex) { - return [code + ' + 1', Blockly.Python.ORDER_ADDITIVE]; + return [code + ' + 1', Python.ORDER_ADDITIVE]; } - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['text_charAt'] = function(block) { +Python['text_charAt'] = function(block) { // Get letter at index. // Note: Until January 2013 this block did not have the WHERE input. const where = block.getFieldValue('WHERE') || 'FROM_START'; - const textOrder = (where === 'RANDOM') ? Blockly.Python.ORDER_NONE : - Blockly.Python.ORDER_MEMBER; - const text = Blockly.Python.valueToCode(block, 'VALUE', textOrder) || '\'\''; + const textOrder = + (where === 'RANDOM') ? Python.ORDER_NONE : Python.ORDER_MEMBER; + const text = Python.valueToCode(block, 'VALUE', textOrder) || '\'\''; switch (where) { case 'FIRST': { const code = text + '[0]'; - return [code, Blockly.Python.ORDER_MEMBER]; + return [code, Python.ORDER_MEMBER]; } case 'LAST': { const code = text + '[-1]'; - return [code, Blockly.Python.ORDER_MEMBER]; + return [code, Python.ORDER_MEMBER]; } case 'FROM_START': { - const at = Blockly.Python.getAdjustedInt(block, 'AT'); + const at = Python.getAdjustedInt(block, 'AT'); const code = text + '[' + at + ']'; - return [code, Blockly.Python.ORDER_MEMBER]; + return [code, Python.ORDER_MEMBER]; } case 'FROM_END': { - const at = Blockly.Python.getAdjustedInt(block, 'AT', 1, true); + const at = Python.getAdjustedInt(block, 'AT', 1, true); const code = text + '[' + at + ']'; - return [code, Blockly.Python.ORDER_MEMBER]; + return [code, Python.ORDER_MEMBER]; } case 'RANDOM': { - Blockly.Python.definitions_['import_random'] = 'import random'; - const functionName = - Blockly.Python.provideFunction_('text_random_letter', [ - 'def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(text):', - ' x = int(random.random() * len(text))', ' return text[x];' - ]); + Python.definitions_['import_random'] = 'import random'; + const functionName = Python.provideFunction_('text_random_letter', [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(text):', + ' x = int(random.random() * len(text))', ' return text[x];' + ]); const code = functionName + '(' + text + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; } } throw Error('Unhandled option (text_charAt).'); }; -Blockly.Python['text_getSubstring'] = function(block) { +Python['text_getSubstring'] = function(block) { // Get substring. const where1 = block.getFieldValue('WHERE1'); const where2 = block.getFieldValue('WHERE2'); - const text = Blockly.Python.valueToCode(block, 'STRING', - Blockly.Python.ORDER_MEMBER) || '\'\''; + const text = + Python.valueToCode(block, 'STRING', Python.ORDER_MEMBER) || '\'\''; let at1; switch (where1) { case 'FROM_START': - at1 = Blockly.Python.getAdjustedInt(block, 'AT1'); + at1 = Python.getAdjustedInt(block, 'AT1'); if (at1 === 0) { at1 = ''; } break; case 'FROM_END': - at1 = Blockly.Python.getAdjustedInt(block, 'AT1', 1, true); + at1 = Python.getAdjustedInt(block, 'AT1', 1, true); break; case 'FIRST': at1 = ''; @@ -195,14 +186,14 @@ Blockly.Python['text_getSubstring'] = function(block) { let at2; switch (where2) { case 'FROM_START': - at2 = Blockly.Python.getAdjustedInt(block, 'AT2', 1); + at2 = Python.getAdjustedInt(block, 'AT2', 1); break; case 'FROM_END': - at2 = Blockly.Python.getAdjustedInt(block, 'AT2', 0, true); + at2 = 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.utils.string.isNumber(String(at2))) { - Blockly.Python.definitions_['import_sys'] = 'import sys'; + if (!stringUtils.isNumber(String(at2))) { + Python.definitions_['import_sys'] = 'import sys'; at2 += ' or sys.maxsize'; } else if (at2 === 0) { at2 = ''; @@ -215,10 +206,10 @@ Blockly.Python['text_getSubstring'] = function(block) { throw Error('Unhandled option (text_getSubstring)'); } const code = text + '[' + at1 + ' : ' + at2 + ']'; - return [code, Blockly.Python.ORDER_MEMBER]; + return [code, Python.ORDER_MEMBER]; }; -Blockly.Python['text_changeCase'] = function(block) { +Python['text_changeCase'] = function(block) { // Change capitalization. const OPERATORS = { 'UPPERCASE': '.upper()', @@ -226,13 +217,12 @@ Blockly.Python['text_changeCase'] = function(block) { 'TITLECASE': '.title()' }; const operator = OPERATORS[block.getFieldValue('CASE')]; - const text = Blockly.Python.valueToCode(block, 'TEXT', - Blockly.Python.ORDER_MEMBER) || '\'\''; + const text = Python.valueToCode(block, 'TEXT', Python.ORDER_MEMBER) || '\'\''; const code = text + operator; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['text_trim'] = function(block) { +Python['text_trim'] = function(block) { // Trim spaces. const OPERATORS = { 'LEFT': '.lstrip()', @@ -240,70 +230,58 @@ Blockly.Python['text_trim'] = function(block) { 'BOTH': '.strip()' }; const operator = OPERATORS[block.getFieldValue('MODE')]; - const text = Blockly.Python.valueToCode(block, 'TEXT', - Blockly.Python.ORDER_MEMBER) || '\'\''; + const text = Python.valueToCode(block, 'TEXT', Python.ORDER_MEMBER) || '\'\''; const code = text + operator; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['text_print'] = function(block) { +Python['text_print'] = function(block) { // Print statement. - const msg = Blockly.Python.valueToCode(block, 'TEXT', - Blockly.Python.ORDER_NONE) || '\'\''; + const msg = Python.valueToCode(block, 'TEXT', Python.ORDER_NONE) || '\'\''; return 'print(' + msg + ')\n'; }; -Blockly.Python['text_prompt_ext'] = function(block) { +Python['text_prompt_ext'] = function(block) { // Prompt function. - const functionName = Blockly.Python.provideFunction_( - 'text_prompt', - ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(msg):', - ' try:', - ' return raw_input(msg)', - ' except NameError:', - ' return input(msg)']); + const functionName = Python.provideFunction_('text_prompt', [ + 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(msg):', ' try:', + ' return raw_input(msg)', ' except NameError:', ' return input(msg)' + ]); let msg; if (block.getField('TEXT')) { // Internal message. - msg = Blockly.Python.quote_(block.getFieldValue('TEXT')); + msg = Python.quote_(block.getFieldValue('TEXT')); } else { // External message. - msg = Blockly.Python.valueToCode(block, 'TEXT', - Blockly.Python.ORDER_NONE) || '\'\''; + msg = Python.valueToCode(block, 'TEXT', Python.ORDER_NONE) || '\'\''; } let code = functionName + '(' + msg + ')'; const toNumber = block.getFieldValue('TYPE') === 'NUMBER'; if (toNumber) { code = 'float(' + code + ')'; } - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['text_prompt'] = Blockly.Python['text_prompt_ext']; +Python['text_prompt'] = Python['text_prompt_ext']; -Blockly.Python['text_count'] = function(block) { - const text = Blockly.Python.valueToCode(block, 'TEXT', - Blockly.Python.ORDER_MEMBER) || '\'\''; - const sub = Blockly.Python.valueToCode(block, 'SUB', - Blockly.Python.ORDER_NONE) || '\'\''; +Python['text_count'] = function(block) { + const text = Python.valueToCode(block, 'TEXT', Python.ORDER_MEMBER) || '\'\''; + const sub = Python.valueToCode(block, 'SUB', Python.ORDER_NONE) || '\'\''; const code = text + '.count(' + sub + ')'; - return [code, Blockly.Python.ORDER_FUNCTION_CALL]; + return [code, Python.ORDER_FUNCTION_CALL]; }; -Blockly.Python['text_replace'] = function(block) { - const text = Blockly.Python.valueToCode(block, 'TEXT', - Blockly.Python.ORDER_MEMBER) || '\'\''; - const from = Blockly.Python.valueToCode(block, 'FROM', - Blockly.Python.ORDER_NONE) || '\'\''; - const to = Blockly.Python.valueToCode(block, 'TO', - Blockly.Python.ORDER_NONE) || '\'\''; +Python['text_replace'] = function(block) { + const text = Python.valueToCode(block, 'TEXT', Python.ORDER_MEMBER) || '\'\''; + const from = Python.valueToCode(block, 'FROM', Python.ORDER_NONE) || '\'\''; + const to = Python.valueToCode(block, 'TO', Python.ORDER_NONE) || '\'\''; const code = text + '.replace(' + from + ', ' + to + ')'; - return [code, Blockly.Python.ORDER_MEMBER]; + return [code, Python.ORDER_MEMBER]; }; -Blockly.Python['text_reverse'] = function(block) { - const text = Blockly.Python.valueToCode(block, 'TEXT', - Blockly.Python.ORDER_MEMBER) || '\'\''; +Python['text_reverse'] = function(block) { + const text = Python.valueToCode(block, 'TEXT', Python.ORDER_MEMBER) || '\'\''; const code = text + '[::-1]'; - return [code, Blockly.Python.ORDER_MEMBER]; + return [code, Python.ORDER_MEMBER]; }; diff --git a/generators/python/variables.js b/generators/python/variables.js index 58266da1da8..107beda0d1f 100644 --- a/generators/python/variables.js +++ b/generators/python/variables.js @@ -6,28 +6,27 @@ /** * @fileoverview Generating Python for variable blocks. - * @suppress {missingRequire} */ 'use strict'; -goog.provide('Blockly.Python.variables'); +goog.module('Blockly.Python.variables'); -goog.require('Blockly.Python'); +const Python = goog.require('Blockly.Python'); +const {NameType} = goog.require('Blockly.Names'); -Blockly.Python['variables_get'] = function(block) { +Python['variables_get'] = function(block) { // Variable getter. - const code = Blockly.Python.nameDB_.getName(block.getFieldValue('VAR'), - Blockly.VARIABLE_CATEGORY_NAME); - return [code, Blockly.Python.ORDER_ATOMIC]; + const code = + Python.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE); + return [code, Python.ORDER_ATOMIC]; }; -Blockly.Python['variables_set'] = function(block) { +Python['variables_set'] = function(block) { // Variable setter. const argument0 = - Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_NONE) || - '0'; - const varName = Blockly.Python.nameDB_.getName( - block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); + Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || '0'; + const varName = + Python.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE); return varName + ' = ' + argument0 + '\n'; }; diff --git a/generators/python/variables_dynamic.js b/generators/python/variables_dynamic.js index 9b662b93bb9..738b383fe0e 100644 --- a/generators/python/variables_dynamic.js +++ b/generators/python/variables_dynamic.js @@ -6,16 +6,16 @@ /** * @fileoverview Generating Python for dynamic variable blocks. - * @suppress {extraRequire} */ 'use strict'; -goog.provide('Blockly.Python.variablesDynamic'); +goog.module('Blockly.Python.variablesDynamic'); -goog.require('Blockly.Python'); +const Python = goog.require('Blockly.Python'); +/** @suppress {extraRequire} */ goog.require('Blockly.Python.variables'); // Python is dynamically typed. -Blockly.Python['variables_get_dynamic'] = Blockly.Python['variables_get']; -Blockly.Python['variables_set_dynamic'] = Blockly.Python['variables_set']; +Python['variables_get_dynamic'] = Python['variables_get']; +Python['variables_set_dynamic'] = Python['variables_set']; diff --git a/scripts/gulpfiles/chunks.json b/scripts/gulpfiles/chunks.json index 31733f7396c..2233b278d95 100644 --- a/scripts/gulpfiles/chunks.json +++ b/scripts/gulpfiles/chunks.json @@ -183,6 +183,10 @@ "./core/renderers/common/debug.js", "./core/renderers/common/block_rendering.js", "./core/variables_dynamic.js", + "./core/events/events_var_rename.js", + "./core/events/events_var_delete.js", + "./core/variable_map.js", + "./core/names.js", "./core/events/events_block_base.js", "./core/events/events_block_change.js", "./core/events/events_ui_base.js", @@ -232,6 +236,7 @@ "./core/utils/deprecation.js", "./core/css.js", "./core/toolbox/category.js", + "./core/input_types.js", "./core/utils/size.js", "./core/serialization/exceptions.js", "./core/interfaces/i_serializer.js", @@ -247,17 +252,12 @@ "./core/extensions.js", "./core/block.js", "./core/utils/string.js", - "./core/input_types.js", "./core/dialog.js", "./core/utils/xml.js", "./core/events/events_var_base.js", "./core/events/events_var_create.js", "./core/variable_model.js", "./core/variables.js", - "./core/events/events_var_rename.js", - "./core/events/events_var_delete.js", - "./core/variable_map.js", - "./core/names.js", "./core/events/events_abstract.js", "./core/events/utils.js", "./core/xml.js", diff --git a/tests/deps.js b/tests/deps.js index 98f5b25c6cc..e73e51f1f0d 100644 --- a/tests/deps.js +++ b/tests/deps.js @@ -309,17 +309,17 @@ goog.addDependency('../../generators/php/procedures.js', ['Blockly.PHP.procedure goog.addDependency('../../generators/php/text.js', ['Blockly.PHP.texts'], ['Blockly.Names', 'Blockly.PHP'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../generators/php/variables.js', ['Blockly.PHP.variables'], ['Blockly.Names', 'Blockly.PHP'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../generators/php/variables_dynamic.js', ['Blockly.PHP.variablesDynamic'], ['Blockly.PHP', 'Blockly.PHP.variables'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../generators/python.js', ['Blockly.Python'], ['Blockly.Generator', 'Blockly.Names', 'Blockly.Variables', 'Blockly.inputTypes', 'Blockly.utils.string'], {'lang': 'es6'}); +goog.addDependency('../../generators/python.js', ['Blockly.Python'], ['Blockly.Generator', 'Blockly.Names', 'Blockly.Variables', 'Blockly.inputTypes', 'Blockly.utils.string'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../generators/python/all.js', ['Blockly.Python.all'], ['Blockly.Python.colour', 'Blockly.Python.lists', 'Blockly.Python.logic', 'Blockly.Python.loops', 'Blockly.Python.math', 'Blockly.Python.procedures', 'Blockly.Python.texts', 'Blockly.Python.variables', 'Blockly.Python.variablesDynamic'], {'module': 'goog'}); -goog.addDependency('../../generators/python/colour.js', ['Blockly.Python.colour'], ['Blockly.Python'], {'lang': 'es6'}); -goog.addDependency('../../generators/python/lists.js', ['Blockly.Python.lists'], ['Blockly.Python', 'Blockly.utils.string'], {'lang': 'es6'}); -goog.addDependency('../../generators/python/logic.js', ['Blockly.Python.logic'], ['Blockly.Python'], {'lang': 'es6'}); -goog.addDependency('../../generators/python/loops.js', ['Blockly.Python.loops'], ['Blockly.Python', 'Blockly.utils.string'], {'lang': 'es6'}); -goog.addDependency('../../generators/python/math.js', ['Blockly.Python.math'], ['Blockly.Python'], {'lang': 'es6'}); -goog.addDependency('../../generators/python/procedures.js', ['Blockly.Python.procedures'], ['Blockly.Python', 'Blockly.Variables'], {'lang': 'es6'}); -goog.addDependency('../../generators/python/text.js', ['Blockly.Python.texts'], ['Blockly.Python', 'Blockly.utils.string'], {'lang': 'es6'}); -goog.addDependency('../../generators/python/variables.js', ['Blockly.Python.variables'], ['Blockly.Python'], {'lang': 'es6'}); -goog.addDependency('../../generators/python/variables_dynamic.js', ['Blockly.Python.variablesDynamic'], ['Blockly.Python', 'Blockly.Python.variables']); +goog.addDependency('../../generators/python/colour.js', ['Blockly.Python.colour'], ['Blockly.Python'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../generators/python/lists.js', ['Blockly.Python.lists'], ['Blockly.Names', 'Blockly.Python', 'Blockly.utils.string'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../generators/python/logic.js', ['Blockly.Python.logic'], ['Blockly.Python'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../generators/python/loops.js', ['Blockly.Python.loops'], ['Blockly.Names', 'Blockly.Python', 'Blockly.utils.string'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../generators/python/math.js', ['Blockly.Python.math'], ['Blockly.Names', 'Blockly.Python'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../generators/python/procedures.js', ['Blockly.Python.procedures'], ['Blockly.Names', 'Blockly.Python', 'Blockly.Variables'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../generators/python/text.js', ['Blockly.Python.texts'], ['Blockly.Names', 'Blockly.Python', 'Blockly.utils.string'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../generators/python/variables.js', ['Blockly.Python.variables'], ['Blockly.Names', 'Blockly.Python'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../generators/python/variables_dynamic.js', ['Blockly.Python.variablesDynamic'], ['Blockly.Python', 'Blockly.Python.variables'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('base.js', [], []); goog.addDependency('base_minimal.js', [], []);