text.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /**
  2. * @license
  3. * Visual Blocks Language
  4. *
  5. * Copyright 2016 Google Inc.
  6. * https://developers.google.com/blockly/
  7. *
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. */
  20. /**
  21. * @fileoverview Generating Lua for text blocks.
  22. * @author rodrigoq@google.com (Rodrigo Queiro)
  23. */
  24. 'use strict';
  25. goog.provide('Blockly.Lua.texts');
  26. goog.require('Blockly.Lua');
  27. Blockly.Lua['text'] = function(block) {
  28. // Text value.
  29. var code = Blockly.Lua.quote_(block.getFieldValue('TEXT'));
  30. return [code, Blockly.Lua.ORDER_ATOMIC];
  31. };
  32. Blockly.Lua['text_join'] = function(block) {
  33. // Create a string made up of any number of elements of any type.
  34. if (block.itemCount_ == 0) {
  35. return ['\'\'', Blockly.Lua.ORDER_ATOMIC];
  36. } else if (block.itemCount_ == 1) {
  37. var argument0 = Blockly.Lua.valueToCode(block, 'ADD0',
  38. Blockly.Lua.ORDER_NONE) || '\'\'';
  39. var code = argument0;
  40. return [code, Blockly.Lua.ORDER_HIGH];
  41. } else if (block.itemCount_ == 2) {
  42. var argument0 = Blockly.Lua.valueToCode(block, 'ADD0',
  43. Blockly.Lua.ORDER_NONE) || '\'\'';
  44. var argument1 = Blockly.Lua.valueToCode(block, 'ADD1',
  45. Blockly.Lua.ORDER_NONE) || '\'\'';
  46. var code = argument0 + ' .. ' + argument1;
  47. return [code, Blockly.Lua.ORDER_UNARY];
  48. } else {
  49. var code = [];
  50. for (var n = 0; n < block.itemCount_; n++) {
  51. code[n] = Blockly.Lua.valueToCode(block, 'ADD' + n,
  52. Blockly.Lua.ORDER_NONE) || '\'\'';
  53. }
  54. code = 'table.concat({' + code.join(', ') + '})';
  55. return [code, Blockly.Lua.ORDER_HIGH];
  56. }
  57. };
  58. Blockly.Lua['text_append'] = function(block) {
  59. // Append to a variable in place.
  60. var varName = Blockly.Lua.variableDB_.getName(
  61. block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE);
  62. var argument0 = Blockly.Lua.valueToCode(block, 'TEXT',
  63. Blockly.Lua.ORDER_NONE) || '\'\'';
  64. return varName + ' = ' + varName + ' .. ' + argument0 + '\n';
  65. };
  66. Blockly.Lua['text_length'] = function(block) {
  67. // String or array length.
  68. var argument0 = Blockly.Lua.valueToCode(block, 'VALUE',
  69. Blockly.Lua.ORDER_HIGH) || '\'\'';
  70. return ['#' + argument0, Blockly.Lua.ORDER_HIGH];
  71. };
  72. Blockly.Lua['text_isEmpty'] = function(block) {
  73. // Is the string null or array empty?
  74. var argument0 = Blockly.Lua.valueToCode(block, 'VALUE',
  75. Blockly.Lua.ORDER_HIGH) || '\'\'';
  76. return ['#' + argument0 + ' == 0', Blockly.Lua.ORDER_RELATIONAL];
  77. };
  78. Blockly.Lua['text_indexOf'] = function(block) {
  79. // Search the text for a substring.
  80. var operator = block.getFieldValue('END') == 'FIRST' ?
  81. 'indexOf' : 'lastIndexOf';
  82. var substr = Blockly.Lua.valueToCode(block, 'FIND',
  83. Blockly.Lua.ORDER_NONE) || '\'\'';
  84. var str = Blockly.Lua.valueToCode(block, 'VALUE',
  85. Blockly.Lua.ORDER_NONE) || '\'\'';
  86. if (block.getFieldValue('END') == 'FIRST') {
  87. var functionName = Blockly.Lua.provideFunction_(
  88. 'firstIndexOf',
  89. ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ +
  90. '(str, substr) ',
  91. ' local i = string.find(str, substr, 1, true)',
  92. ' if i == nil then',
  93. ' return 0',
  94. ' else',
  95. ' return i',
  96. ' end',
  97. 'end']);
  98. } else {
  99. var functionName = Blockly.Lua.provideFunction_(
  100. 'lastIndexOf',
  101. ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ +
  102. '(str, substr)',
  103. ' local i = string.find(string.reverse(str), ' +
  104. 'string.reverse(substr), 1, true)',
  105. ' if i then',
  106. ' return #str + 2 - i - #substr',
  107. ' end',
  108. ' return 0',
  109. 'end']);
  110. }
  111. var code = functionName + '(' + str + ', ' + substr + ')';
  112. return [code, Blockly.Lua.ORDER_HIGH];
  113. };
  114. Blockly.Lua['text_charAt'] = function(block) {
  115. // Get letter at index.
  116. // Note: Until January 2013 this block did not have the WHERE input.
  117. var where = block.getFieldValue('WHERE') || 'FROM_START';
  118. var at = Blockly.Lua.valueToCode(block, 'AT',
  119. Blockly.Lua.ORDER_UNARY) || '1';
  120. var text = Blockly.Lua.valueToCode(block, 'VALUE',
  121. Blockly.Lua.ORDER_NONE) || '\'\'';
  122. var code;
  123. if (where == 'RANDOM') {
  124. var functionName = Blockly.Lua.provideFunction_(
  125. 'text_random_letter',
  126. ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(str)',
  127. ' local index = math.random(string.len(str))',
  128. ' return string.sub(str, index, index)',
  129. 'end']);
  130. code = functionName + '(' + text + ')';
  131. } else {
  132. if (where == 'FIRST') {
  133. var start = '1';
  134. } else if (where == 'LAST') {
  135. var start = '-1';
  136. } else {
  137. if (where == 'FROM_START') {
  138. var start = at;
  139. } else if (where == 'FROM_END') {
  140. var start = '-' + at;
  141. } else {
  142. throw 'Unhandled option (text_charAt).';
  143. }
  144. }
  145. if (start.match(/^-?\w*$/)) {
  146. code = 'string.sub(' + text + ', ' + start + ', ' + start + ')';
  147. } else {
  148. // use function to avoid reevaluation
  149. var functionName = Blockly.Lua.provideFunction_(
  150. 'text_char_at',
  151. ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ +
  152. '(str, index)',
  153. ' return string.sub(str, index, index)',
  154. 'end']);
  155. code = functionName + '(' + text + ', ' + start + ')';
  156. }
  157. }
  158. return [code, Blockly.Lua.ORDER_HIGH];
  159. };
  160. Blockly.Lua['text_getSubstring'] = function(block) {
  161. // Get substring.
  162. var text = Blockly.Lua.valueToCode(block, 'STRING',
  163. Blockly.Lua.ORDER_NONE) || '\'\'';
  164. // Get start index.
  165. var where1 = block.getFieldValue('WHERE1');
  166. var at1 = Blockly.Lua.valueToCode(block, 'AT1',
  167. Blockly.Lua.ORDER_UNARY) || '1';
  168. if (where1 == 'FIRST') {
  169. var start = 1;
  170. } else if (where1 == 'FROM_START') {
  171. var start = at1;
  172. } else if (where1 == 'FROM_END') {
  173. var start = '-' + at1;
  174. } else {
  175. throw 'Unhandled option (text_getSubstring)';
  176. }
  177. // Get end index.
  178. var where2 = block.getFieldValue('WHERE2');
  179. var at2 = Blockly.Lua.valueToCode(block, 'AT2',
  180. Blockly.Lua.ORDER_UNARY) || '1';
  181. if (where2 == 'LAST') {
  182. var end = -1;
  183. } else if (where2 == 'FROM_START') {
  184. var end = at2;
  185. } else if (where2 == 'FROM_END') {
  186. var end = '-' + at2;
  187. } else {
  188. throw 'Unhandled option (text_getSubstring)';
  189. }
  190. var code = 'string.sub(' + text + ', ' + start + ', ' + end + ')';
  191. return [code, Blockly.Lua.ORDER_HIGH];
  192. };
  193. Blockly.Lua['text_changeCase'] = function(block) {
  194. // Change capitalization.
  195. var operator = block.getFieldValue('CASE');
  196. var argument0 = Blockly.Lua.valueToCode(block, 'TEXT',
  197. Blockly.Lua.ORDER_NONE) || '\'\'';
  198. if (operator == 'UPPERCASE') {
  199. var functionName = 'string.upper';
  200. } else if (operator == 'LOWERCASE') {
  201. var functionName = 'string.lower';
  202. } else if (operator == 'TITLECASE') {
  203. var functionName = Blockly.Lua.provideFunction_(
  204. 'text_titlecase',
  205. // There are shorter versions at
  206. // http://lua-users.org/wiki/SciteTitleCase
  207. // that do not preserve whitespace.
  208. ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(str)',
  209. ' local buf = {}',
  210. ' local inWord = false',
  211. ' for i = 1, #str do',
  212. ' local c = string.sub(str, i, i)',
  213. ' if inWord then',
  214. ' table.insert(buf, string.lower(c))',
  215. ' if string.find(c, "%s") then',
  216. ' inWord = false',
  217. ' end',
  218. ' else',
  219. ' table.insert(buf, string.upper(c))',
  220. ' inWord = true',
  221. ' end',
  222. ' end',
  223. ' return table.concat(buf)',
  224. 'end']);
  225. }
  226. var code = functionName + '(' + argument0 + ')';
  227. return [code, Blockly.Lua.ORDER_HIGH];
  228. };
  229. Blockly.Lua['text_trim'] = function(block) {
  230. // Trim spaces.
  231. var OPERATORS = {
  232. LEFT: '^%s*(,-)',
  233. RIGHT: '(.-)%s*$',
  234. BOTH: '^%s*(.-)%s*$'
  235. };
  236. var operator = OPERATORS[block.getFieldValue('MODE')];
  237. var text = Blockly.Lua.valueToCode(block, 'TEXT',
  238. Blockly.Lua.ORDER_NONE) || '\'\'';
  239. var code = 'string.gsub(' + text + ', "' + operator + '", "%1")';
  240. return [code, Blockly.Lua.ORDER_HIGH];
  241. };
  242. Blockly.Lua['text_print'] = function(block) {
  243. // Print statement.
  244. var argument0 = Blockly.Lua.valueToCode(block, 'TEXT',
  245. Blockly.Lua.ORDER_NONE) || '\'\'';
  246. return 'print(' + argument0 + ')\n';
  247. };
  248. Blockly.Lua['text_prompt_ext'] = function(block) {
  249. // Prompt function.
  250. if (block.getField('TEXT')) {
  251. // Internal message.
  252. var msg = Blockly.Lua.quote_(block.getFieldValue('TEXT'));
  253. } else {
  254. // External message.
  255. var msg = Blockly.Lua.valueToCode(block, 'TEXT',
  256. Blockly.Lua.ORDER_NONE) || '\'\'';
  257. }
  258. var functionName = Blockly.Lua.provideFunction_(
  259. 'text_prompt',
  260. ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(msg)',
  261. ' io.write(msg)',
  262. ' io.flush()',
  263. ' return io.read()',
  264. 'end']);
  265. var code = functionName + '(' + msg + ')';
  266. var toNumber = block.getFieldValue('TYPE') == 'NUMBER';
  267. if (toNumber) {
  268. code = 'tonumber(' + code + ', 10)';
  269. }
  270. return [code, Blockly.Lua.ORDER_HIGH];
  271. };
  272. Blockly.Lua['text_prompt'] = Blockly.Lua['text_prompt_ext'];