From ba18ae2159186f6b3aa8adb2bcbc655c1586bbe2 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 10 May 2019 23:19:35 -0700 Subject: [PATCH] Add STATEMENT_SUFFIX Also remove need to manually indent INFINITE_LOOP_TRAP. This is a breaking change for Python users of this property. However, very few users of this property exist, given that the existing code breaks if the block ID has a $ in it (also fixed in this PR). --- core/generator.js | 25 ++++++++++++++++++++++--- demos/code/code.js | 2 +- generators/dart/procedures.js | 18 ++++++++++++------ generators/javascript/procedures.js | 18 ++++++++++++------ generators/lua/procedures.js | 18 ++++++++++++------ generators/php/procedures.js | 18 ++++++++++++------ generators/python/procedures.js | 18 ++++++++++++------ 7 files changed, 83 insertions(+), 34 deletions(-) diff --git a/core/generator.js b/core/generator.js index 13cfc3358..adacfbd08 100644 --- a/core/generator.js +++ b/core/generator.js @@ -62,6 +62,14 @@ Blockly.Generator.prototype.INFINITE_LOOP_TRAP = null; */ Blockly.Generator.prototype.STATEMENT_PREFIX = null; +/** + * Arbitrary code to inject after every statement. + * Any instances of '%1' will be replaced by the block ID of the statement. + * E.g. 'highlight(%1);\n' + * @type {?string} + */ +Blockly.Generator.prototype.STATEMENT_SUFFIX = null; + /** * The method of indenting. Defaults to two spaces, but language generators * may override this to increase indent or change to tabs. @@ -126,6 +134,7 @@ Blockly.Generator.prototype.workspaceToCode = function(workspace) { /** * Prepend a common prefix onto each line of code. + * Intended for indenting code or adding comment markers. * @param {string} text The lines of code. * @param {string} prefix The common prefix. * @return {string} The prefixed lines of code. @@ -193,6 +202,9 @@ Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) { if (this.STATEMENT_PREFIX) { code = this.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\'') + code; } + if (this.STATEMENT_SUFFIX) { + code = code + this.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''); + } return this.scrub_(block, code, opt_thisOnly); } else if (code === null) { // Block has handled code generation itself. @@ -299,7 +311,9 @@ Blockly.Generator.prototype.statementToCode = function(block, name) { /** * Add an infinite loop trap to the contents of a loop. - * If loop is empty, add a statment prefix for the loop block. + * Add statement suffix at the start of the loop block (right after the loop + * statement executes), and a statement prefix to the end of the loop block + * (right before the loop statement executes). * @param {string} branch Code for loop contents. * @param {string} id ID of enclosing block. * @return {string} Loop contents, with infinite loop trap added. @@ -307,10 +321,15 @@ Blockly.Generator.prototype.statementToCode = function(block, name) { Blockly.Generator.prototype.addLoopTrap = function(branch, id) { id = id.replace(/\$/g, '$$$$'); // Issue 251. if (this.INFINITE_LOOP_TRAP) { - branch = this.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\'') + branch; + branch = this.prefixLines(this.INFINITE_LOOP_TRAP.replace(/%1/g, + '\'' + id + '\''), this.INDENT) + branch; + } + if (this.STATEMENT_SUFFIX) { + branch = this.prefixLines(this.STATEMENT_SUFFIX.replace(/%1/g, + '\'' + id + '\''), this.INDENT) + branch; } if (this.STATEMENT_PREFIX) { - branch += this.prefixLines(this.STATEMENT_PREFIX.replace(/%1/g, + branch = branch + this.prefixLines(this.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), this.INDENT); } return branch; diff --git a/demos/code/code.js b/demos/code/code.js index 7ffed86bd..7128adfc7 100644 --- a/demos/code/code.js +++ b/demos/code/code.js @@ -516,7 +516,7 @@ Code.initLanguage = function() { * Just a quick and dirty eval. Catch infinite loops. */ Code.runJS = function() { - Blockly.JavaScript.INFINITE_LOOP_TRAP = ' checkTimeout();\n'; + Blockly.JavaScript.INFINITE_LOOP_TRAP = 'checkTimeout();\n'; var timeouts = 0; var checkTimeout = function() { if (timeouts++ > 1000000) { diff --git a/generators/dart/procedures.js b/generators/dart/procedures.js index 7e61ab56c..b9daf055a 100644 --- a/generators/dart/procedures.js +++ b/generators/dart/procedures.js @@ -34,15 +34,21 @@ Blockly.Dart['procedures_defreturn'] = function(block) { var funcName = Blockly.Dart.variableDB_.getName(block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.Dart.statementToCode(block, 'STACK'); - if (Blockly.Dart.STATEMENT_PREFIX) { - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + if (Blockly.Dart.STATEMENT_SUFFIX) { branch = Blockly.Dart.prefixLines( - Blockly.Dart.STATEMENT_PREFIX.replace(/%1/g, - '\'' + id + '\''), Blockly.Dart.INDENT) + branch; + Blockly.Dart.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.Dart.INDENT) + branch; } if (Blockly.Dart.INFINITE_LOOP_TRAP) { - branch = Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g, - '\'' + block.id + '\'') + branch; + branch = Blockly.Dart.prefixLines( + Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.Dart.INDENT) + branch; + } + if (Blockly.Dart.STATEMENT_PREFIX) { + branch = Blockly.Dart.prefixLines( + Blockly.Dart.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.Dart.INDENT) + branch; } var returnValue = Blockly.Dart.valueToCode(block, 'RETURN', Blockly.Dart.ORDER_NONE) || ''; diff --git a/generators/javascript/procedures.js b/generators/javascript/procedures.js index 7ed4da794..a3f9c88d6 100644 --- a/generators/javascript/procedures.js +++ b/generators/javascript/procedures.js @@ -34,15 +34,21 @@ Blockly.JavaScript['procedures_defreturn'] = function(block) { var funcName = Blockly.JavaScript.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.JavaScript.statementToCode(block, 'STACK'); - if (Blockly.JavaScript.STATEMENT_PREFIX) { - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + if (Blockly.JavaScript.STATEMENT_SUFFIX) { branch = Blockly.JavaScript.prefixLines( - Blockly.JavaScript.STATEMENT_PREFIX.replace(/%1/g, - '\'' + id + '\''), Blockly.JavaScript.INDENT) + branch; + Blockly.JavaScript.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.JavaScript.INDENT) + branch; } if (Blockly.JavaScript.INFINITE_LOOP_TRAP) { - branch = Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, - '\'' + block.id + '\'') + branch; + branch = Blockly.JavaScript.prefixLines( + Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.JavaScript.INDENT) + branch; + } + if (Blockly.JavaScript.STATEMENT_PREFIX) { + branch = Blockly.JavaScript.prefixLines( + Blockly.JavaScript.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.JavaScript.INDENT) + branch; } var returnValue = Blockly.JavaScript.valueToCode(block, 'RETURN', Blockly.JavaScript.ORDER_NONE) || ''; diff --git a/generators/lua/procedures.js b/generators/lua/procedures.js index 07626b65a..58c32baba 100644 --- a/generators/lua/procedures.js +++ b/generators/lua/procedures.js @@ -34,15 +34,21 @@ Blockly.Lua['procedures_defreturn'] = function(block) { var funcName = Blockly.Lua.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.Lua.statementToCode(block, 'STACK'); - if (Blockly.Lua.STATEMENT_PREFIX) { - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + if (Blockly.Lua.STATEMENT_SUFFIX) { branch = Blockly.Lua.prefixLines( - Blockly.Lua.STATEMENT_PREFIX.replace(/%1/g, - '\'' + id + '\''), Blockly.Lua.INDENT) + branch; + Blockly.Lua.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.Lua.INDENT) + branch; } if (Blockly.Lua.INFINITE_LOOP_TRAP) { - branch = Blockly.Lua.INFINITE_LOOP_TRAP.replace(/%1/g, - '\'' + block.id + '\'') + branch; + branch = Blockly.Lua.prefixLines( + Blockly.Lua.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.Lua.INDENT) + branch; + } + if (Blockly.Lua.STATEMENT_PREFIX) { + branch = Blockly.Lua.prefixLines( + Blockly.Lua.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.Lua.INDENT) + branch; } var returnValue = Blockly.Lua.valueToCode(block, 'RETURN', Blockly.Lua.ORDER_NONE) || ''; diff --git a/generators/php/procedures.js b/generators/php/procedures.js index c81eab344..d93d7cb63 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.js @@ -55,15 +55,21 @@ Blockly.PHP['procedures_defreturn'] = function(block) { var funcName = Blockly.PHP.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.PHP.statementToCode(block, 'STACK'); - if (Blockly.PHP.STATEMENT_PREFIX) { - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + if (Blockly.PHP.STATEMENT_SUFFIX) { branch = Blockly.PHP.prefixLines( - Blockly.PHP.STATEMENT_PREFIX.replace( - /%1/g, '\'' + id + '\''), Blockly.PHP.INDENT) + branch; + Blockly.PHP.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.PHP.INDENT) + branch; } if (Blockly.PHP.INFINITE_LOOP_TRAP) { - branch = Blockly.PHP.INFINITE_LOOP_TRAP.replace(/%1/g, - '\'' + block.id + '\'') + branch; + branch = Blockly.PHP.prefixLines( + Blockly.PHP.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.PHP.INDENT) + branch; + } + if (Blockly.PHP.STATEMENT_PREFIX) { + branch = Blockly.PHP.prefixLines( + Blockly.PHP.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.PHP.INDENT) + branch; } var returnValue = Blockly.PHP.valueToCode(block, 'RETURN', Blockly.PHP.ORDER_NONE) || ''; diff --git a/generators/python/procedures.js b/generators/python/procedures.js index 520b3f589..c95c279f1 100644 --- a/generators/python/procedures.js +++ b/generators/python/procedures.js @@ -56,15 +56,21 @@ Blockly.Python['procedures_defreturn'] = function(block) { var funcName = Blockly.Python.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.Python.statementToCode(block, 'STACK'); - if (Blockly.Python.STATEMENT_PREFIX) { - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + if (Blockly.Python.STATEMENT_SUFFIX) { branch = Blockly.Python.prefixLines( - Blockly.Python.STATEMENT_PREFIX.replace( - /%1/g, '\'' + id + '\''), Blockly.Python.INDENT) + branch; + Blockly.Python.STATEMENT_SUFFIX.replace( /%1/g, '\'' + id + '\''), + Blockly.Python.INDENT) + branch; } if (Blockly.Python.INFINITE_LOOP_TRAP) { - branch = Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g, - '"' + block.id + '"') + branch; + branch = Blockly.Python.prefixLines( + Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.Python.INDENT) + branch; + } + if (Blockly.Python.STATEMENT_PREFIX) { + branch = Blockly.Python.prefixLines( + Blockly.Python.STATEMENT_PREFIX.replace( /%1/g, '\'' + id + '\''), + Blockly.Python.INDENT) + branch; } var returnValue = Blockly.Python.valueToCode(block, 'RETURN', Blockly.Python.ORDER_NONE) || '';