Skip to content

Commit

Permalink
refactor: convert python block generators to goog.module (#5771)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
rachel-fenichel authored Dec 2, 2021
1 parent c0517ea commit 9314992
Show file tree
Hide file tree
Showing 16 changed files with 675 additions and 764 deletions.
1 change: 0 additions & 1 deletion generators/dart.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion generators/javascript.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion generators/lua.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion generators/php.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
140 changes: 71 additions & 69 deletions generators/python.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<!Array<number>>}
*/
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);

Expand All @@ -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();
}
Expand All @@ -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');
Expand All @@ -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 = [];
Expand All @@ -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';
};

Expand All @@ -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 = '\'';
Expand All @@ -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' +
Expand All @@ -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);
Expand All @@ -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--;
Expand All @@ -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) {
Expand All @@ -330,3 +330,5 @@ Blockly.Python.getAdjustedInt = function(block, atId, opt_delta, opt_negate) {
}
return at;
};

exports = Python;
Loading

0 comments on commit 9314992

Please sign in to comment.