python_to_blockly.js.html 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JSDoc: Source: python_to_blockly.js</title>
  6. <script src="scripts/prettify/prettify.js"> </script>
  7. <script src="scripts/prettify/lang-css.js"> </script>
  8. <!--[if lt IE 9]>
  9. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  10. <![endif]-->
  11. <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
  12. <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
  13. </head>
  14. <body>
  15. <div id="main">
  16. <h1 class="page-title">Source: python_to_blockly.js</h1>
  17. <section>
  18. <article>
  19. <pre class="prettyprint source linenums"><code>/**
  20. * An object for converting Python source code to the
  21. * Blockly XML representation.
  22. *
  23. * @constructor
  24. * @this {PythonToBlocks}
  25. */
  26. function PythonToBlocks() {
  27. }
  28. function xmlToString(xml) {
  29. return new XMLSerializer().serializeToString(xml);
  30. }
  31. PythonToBlocks.prototype.convertSourceToCodeBlock = function(python_source) {
  32. var xml = document.createElement("xml");
  33. xml.appendChild(raw_block(python_source));
  34. return xmlToString(xml);
  35. }
  36. /**
  37. * The main function for converting a string representation of Python
  38. * code to the Blockly XML representation.
  39. *
  40. * @param {string} python_source - The string representation of Python
  41. * code (e.g., "a = 0").
  42. * @returns {Object} An object which will either have the converted
  43. * source code or an error message and the code as a code-block.
  44. */
  45. PythonToBlocks.prototype.convertSource = function(python_source) {
  46. var xml = document.createElement("xml");
  47. if (python_source.trim() === "") {
  48. return {"xml": xmlToString(xml), "error": null};
  49. }
  50. this.source = python_source.split("\n");
  51. var filename = 'user_code.py';
  52. // Attempt parsing - might fail!
  53. var parse, ast, symbol_table, error;
  54. try {
  55. parse = Sk.parse(filename, python_source);
  56. ast = Sk.astFromParse(parse.cst, filename, parse.flags);
  57. //symbol_table = Sk.symboltable(ast, filename, python_source, filename, parse.flags);
  58. } catch (e) {
  59. error = e;
  60. xml.appendChild(raw_block(python_source))
  61. return {"xml": xmlToString(xml), "error": error};
  62. }
  63. this.comments = {};
  64. for (var commentLocation in parse.comments) {
  65. var lineColumn = commentLocation.split(",");
  66. var yLocation = parseInt(lineColumn[0], 10);
  67. this.comments[yLocation] = parse.comments[commentLocation];
  68. }
  69. this.highestLineSeen = 0;
  70. this.levelIndex = 0;
  71. this.nextExpectedLine = 0;
  72. this.measureNode(ast);
  73. var converted = this.convert(ast);
  74. if (converted !== null) {
  75. for (var block = 0; block &lt; converted.length; block+= 1) {
  76. xml.appendChild(converted[block]);
  77. }
  78. }
  79. return {"xml": xmlToString(xml), "error": null, "lineMap": this.lineMap, 'comment': this.comments};
  80. }
  81. PythonToBlocks.prototype.identifier = function(node) {
  82. return Sk.ffi.remapToJs(node);
  83. }
  84. PythonToBlocks.prototype.recursiveMeasure = function(node, nextBlockLine) {
  85. if (node === undefined) {
  86. return;
  87. }
  88. var myNext = nextBlockLine;
  89. if ("orelse" in node &amp;&amp; node.orelse.length > 0) {
  90. if (node.orelse.length == 1 &amp;&amp; node.orelse[0]._astname == "If") {
  91. myNext = node.orelse[0].lineno-1;
  92. } else {
  93. myNext = node.orelse[0].lineno-1-1;
  94. }
  95. }
  96. this.heights.push(nextBlockLine);
  97. if ("body" in node) {
  98. for (var i = 0; i &lt; node.body.length; i++) {
  99. var next;
  100. if (i+1 == node.body.length) {
  101. next = myNext;
  102. } else {
  103. next = node.body[i+1].lineno-1;
  104. }
  105. this.recursiveMeasure(node.body[i], next);
  106. }
  107. }
  108. if ("orelse" in node) {
  109. for (var i = 0; i &lt; node.orelse.length; i++) {
  110. var next;
  111. if (i == node.orelse.length) {
  112. next = nextBlockLine;
  113. } else {
  114. next = 1+(node.orelse[i].lineno-1);
  115. }
  116. this.recursiveMeasure(node.orelse[i], next);
  117. }
  118. }
  119. }
  120. PythonToBlocks.prototype.measureNode = function(node) {
  121. this.heights = [];
  122. this.recursiveMeasure(node, this.source.length-1);
  123. this.heights.shift();
  124. }
  125. PythonToBlocks.prototype.getSourceCode = function(frm, to) {
  126. var lines = this.source.slice(frm-1, to);
  127. // Strip out any starting indentation.
  128. if (lines.length > 0) {
  129. var indentation = lines[0].search(/\S/);
  130. for (var i = 0; i &lt; lines.length; i++) {
  131. lines[i] = lines[i].substring(indentation);
  132. }
  133. }
  134. return lines.join("\n");
  135. }
  136. PythonToBlocks.prototype.convertBody = function(node, is_top_level) {
  137. this.levelIndex += 1;
  138. // Empty body, return nothing
  139. if (node.length == 0) {
  140. return null;
  141. }
  142. // Final result list
  143. var children = [], // The complete set of peers
  144. root = null, // The top of the current peer
  145. current = null,
  146. levelIndex = this.levelIndex; // The bottom of the current peer
  147. function addPeer(peer) {
  148. if (root == null) {
  149. children.push(peer);
  150. } else {
  151. children.push(root);
  152. }
  153. root = peer;
  154. current = peer;
  155. }
  156. function finalizePeers() {
  157. if (root != null) {
  158. children.push(root);
  159. }
  160. }
  161. function nestChild(child) {
  162. if (root == null) {
  163. root = child;
  164. current = child;
  165. } else if (current == null) {
  166. root = current;
  167. } else {
  168. var nextElement = document.createElement("next");
  169. nextElement.appendChild(child);
  170. current.appendChild(nextElement);
  171. current = child;
  172. }
  173. }
  174. var lineNumberInBody = 0,
  175. lineNumberInProgram,
  176. previousLineInProgram=null,
  177. distance,
  178. skipped_line,
  179. commentCount,
  180. previousHeight = null,
  181. visitedFirstLine = false;
  182. // Iterate through each node
  183. for (var i = 0; i &lt; node.length; i++) {
  184. lineNumberInBody += 1;
  185. lineNumberInProgram = node[i].lineno;
  186. distance = 0, wasFirstLine = true;
  187. if (previousLineInProgram != null) {
  188. distance = lineNumberInProgram - previousLineInProgram-1;
  189. wasFirstLine = false;
  190. }
  191. lineNumberInBody += distance;
  192. // Handle earlier comments
  193. commentCount = 0;
  194. for (var commentLineInProgram in this.comments) {
  195. if (commentLineInProgram &lt; lineNumberInProgram) {
  196. commentChild = this.Comment(this.comments[commentLineInProgram], commentLineInProgram);
  197. if (previousLineInProgram == null) {
  198. nestChild(commentChild);
  199. } else {
  200. skipped_previous_line = Math.abs(previousLineInProgram-commentLineInProgram) > 1;
  201. if (is_top_level &amp;&amp; skipped_previous_line) {
  202. addPeer(commentChild);
  203. } else {
  204. nestChild(commentChild);
  205. }
  206. }
  207. previousLineInProgram = commentLineInProgram;
  208. this.highestLineSeen = Math.max(this.highestLineSeen, parseInt(commentLineInProgram, 10));
  209. distance = lineNumberInProgram - previousLineInProgram;
  210. delete this.comments[commentLineInProgram];
  211. commentCount += 1;
  212. }
  213. }
  214. distance = lineNumberInProgram - this.highestLineSeen;
  215. this.highestLineSeen = Math.max(lineNumberInProgram, this.highestLineSeen);
  216. // Now convert the actual node
  217. var height = this.heights.shift();
  218. var originalSourceCode = this.getSourceCode(lineNumberInProgram, height);
  219. var newChild = this.convertStatement(node[i], originalSourceCode, is_top_level);
  220. // Skip null blocks (e.g., imports)
  221. if (newChild == null) {
  222. continue;
  223. }
  224. skipped_line = distance > 1;
  225. previousLineInProgram = lineNumberInProgram;
  226. previousHeight = height;
  227. // Handle top-level expression blocks
  228. if (is_top_level &amp;&amp; newChild.constructor == Array) {
  229. addPeer(newChild[0]);
  230. // Handle skipped line
  231. } else if (is_top_level &amp;&amp; skipped_line &amp;&amp; visitedFirstLine) {
  232. addPeer(newChild);
  233. // Otherwise, always embed it in there.
  234. } else {
  235. nestChild(newChild);
  236. }
  237. visitedFirstLine = true;
  238. }
  239. // Handle comments that are on the very last line
  240. var lastLineNumber = lineNumberInProgram+1
  241. if (lastLineNumber in this.comments) {
  242. commentChild = this.Comment(this.comments[lastLineNumber], lastLineNumber);
  243. nestChild(commentChild);
  244. delete this.comments[lastLineNumber];
  245. }
  246. // Handle any extra comments that stuck around
  247. if (is_top_level) {
  248. for (var commentLineInProgram in this.comments) {
  249. commentChild = this.Comment(this.comments[commentLineInProgram], commentLineInProgram);
  250. distance = commentLineInProgram - previousLineInProgram;
  251. if (previousLineInProgram == null) {
  252. addPeer(commentChild);
  253. } else if (distance > 1) {
  254. addPeer(commentChild);
  255. } else {
  256. nestChild(commentChild);
  257. }
  258. previousLineInProgram = commentLineInProgram;
  259. delete this.comments[lastLineNumber];
  260. }
  261. }
  262. finalizePeers();
  263. this.levelIndex -= 1;
  264. return children;
  265. }
  266. function block(type, lineNumber, fields, values, settings, mutations, statements) {
  267. var newBlock = document.createElement("block");
  268. // Settings
  269. newBlock.setAttribute("type", type);
  270. newBlock.setAttribute("line_number", lineNumber);
  271. for (var setting in settings) {
  272. var settingValue = settings[setting];
  273. newBlock.setAttribute(setting, settingValue);
  274. }
  275. // Mutations
  276. if (mutations !== undefined &amp;&amp; Object.keys(mutations).length > 0) {
  277. var newMutation = document.createElement("mutation");
  278. for (var mutation in mutations) {
  279. var mutationValue = mutations[mutation];
  280. if (mutation.charAt(0) == '@') {
  281. newMutation.setAttribute(mutation.substr(1), mutationValue);
  282. } else if (mutationValue.constructor === Array) {
  283. for (var i = 0; i &lt; mutationValue.length; i++) {
  284. var mutationNode = document.createElement(mutation);
  285. mutationNode.setAttribute("name", mutationValue[i]);
  286. newMutation.appendChild(mutationNode);
  287. }
  288. } else {
  289. var mutationNode = document.createElement("arg");
  290. mutationNode.setAttribute("name", mutation);
  291. mutationNode.appendChild(mutationValue);
  292. newMutation.appendChild(mutationNode);
  293. }
  294. }
  295. newBlock.appendChild(newMutation);
  296. }
  297. // Fields
  298. for (var field in fields) {
  299. var fieldValue = fields[field];
  300. var newField = document.createElement("field");
  301. newField.setAttribute("name", field);
  302. newField.appendChild(document.createTextNode(fieldValue));
  303. newBlock.appendChild(newField);
  304. }
  305. // Values
  306. for (var value in values) {
  307. var valueValue = values[value];
  308. var newValue = document.createElement("value");
  309. if (valueValue !== null) {
  310. newValue.setAttribute("name", value);
  311. newValue.appendChild(valueValue);
  312. newBlock.appendChild(newValue);
  313. }
  314. }
  315. // Statements
  316. if (statements !== undefined &amp;&amp; Object.keys(statements).length > 0) {
  317. for (var statement in statements) {
  318. var statementValue = statements[statement];
  319. if (statementValue == null) {
  320. continue;
  321. } else {
  322. for (var i = 0; i &lt; statementValue.length; i += 1) {
  323. // In most cases, you really shouldn't ever have more than
  324. // one statement in this list. I'm not sure Blockly likes
  325. // that.
  326. var newStatement = document.createElement("statement");
  327. newStatement.setAttribute("name", statement);
  328. newStatement.appendChild(statementValue[i]);
  329. newBlock.appendChild(newStatement);
  330. }
  331. }
  332. }
  333. }
  334. return newBlock;
  335. }
  336. raw_block = function(txt) {
  337. // TODO: lineno as second parameter!
  338. return block("raw_block", 0, { "TEXT": txt });
  339. }
  340. raw_expression = function(txt, lineno) {
  341. return block("raw_expression", lineno, {"TEXT": txt});
  342. }
  343. PythonToBlocks.prototype.convert = function(node, is_top_level) {
  344. return this[node._astname](node, is_top_level);
  345. }
  346. function arrayMax(array) {
  347. return array.reduce(function(a, b) {
  348. return Math.max(a, b);
  349. });
  350. }
  351. function arrayMin(array) {
  352. return array.reduce(function(a, b) {
  353. return Math.min(a, b);
  354. });
  355. }
  356. PythonToBlocks.prototype.convertStatement = function(node, full_source, is_top_level) {
  357. try {
  358. return this.convert(node, is_top_level);
  359. } catch (e) {
  360. heights = this.getChunkHeights(node);
  361. extractedSource = this.getSourceCode(arrayMin(heights), arrayMax(heights));
  362. console.error(e);
  363. return raw_block(extractedSource);
  364. }
  365. }
  366. PythonToBlocks.prototype.getChunkHeights = function(node) {
  367. var lineNumbers = [];
  368. if (node.hasOwnProperty("lineno")) {
  369. lineNumbers.push(node.lineno);
  370. }
  371. if (node.hasOwnProperty("body")) {
  372. for (var i = 0; i &lt; node.body.length; i += 1) {
  373. var subnode = node.body[i];
  374. lineNumbers = lineNumbers.concat(this.getChunkHeights(subnode));
  375. }
  376. }
  377. if (node.hasOwnProperty("orelse")) {
  378. for (var i = 0; i &lt; node.orelse.length; i += 1) {
  379. var subnode = node.orelse[i];
  380. lineNumbers = lineNumbers.concat(this.getChunkHeights(subnode));
  381. }
  382. }
  383. return lineNumbers;
  384. }
  385. /* ----- Nodes ---- */
  386. /*
  387. * NO LINE OR COLUMN NUMBERS
  388. * Module
  389. * body: asdl_seq
  390. */
  391. PythonToBlocks.prototype.Module = function(node)
  392. {
  393. return this.convertBody(node.body, true);
  394. }
  395. PythonToBlocks.prototype.Comment = function(txt, lineno) {
  396. return block("comment_single", lineno, {
  397. "BODY": txt.slice(1)
  398. }, {}, {}, {}, {})
  399. }
  400. /*
  401. * NO LINE OR COLUMN NUMBERS
  402. * Interactive
  403. * body: asdl_seq
  404. */
  405. PythonToBlocks.prototype.Interactive = function(body)
  406. {
  407. return this.convertBody(node.body);
  408. }
  409. /*
  410. * NO LINE OR COLUMN NUMBERS
  411. * TODO
  412. * body: expr_ty
  413. */
  414. PythonToBlocks.prototype.Expression = function(body)
  415. {
  416. this.body = body;
  417. }
  418. /*
  419. * NO LINE OR COLUMN NUMBERS
  420. *
  421. * body: asdl_seq
  422. */
  423. PythonToBlocks.prototype.Suite = function(body)
  424. {
  425. this.asdl_seq(node.body);
  426. }
  427. /*
  428. *
  429. * name: identifier
  430. * args: arguments__ty
  431. * body: asdl_seq
  432. * decorator_list: asdl_seq
  433. */
  434. PythonToBlocks.prototype.FunctionDef = function(node)
  435. {
  436. var name = node.name;
  437. var args = node.args;
  438. var body = node.body;
  439. var decorator_list = node.decorator_list;
  440. if (decorator_list.length > 0) {
  441. throw new Error("Decorators are not implemented.");
  442. }
  443. return block("procedures_defnoreturn", node.lineno, {
  444. "NAME": this.identifier(name)
  445. }, {
  446. }, {
  447. "inline": "false"
  448. }, {
  449. "arg": this.arguments_(args)
  450. }, {
  451. "STACK": this.convertBody(body)
  452. });
  453. }
  454. /*
  455. * name: identifier
  456. * args: arguments__ty
  457. * bases: asdl_seq
  458. * body: asdl_seq
  459. * decorator_list: asdl_seq
  460. */
  461. PythonToBlocks.prototype.ClassDef = function(node)
  462. {
  463. var name = node.name;
  464. var bases = node.bases;
  465. var body = node.body;
  466. var decorator_list = node.decorator_list;
  467. if (decorator_list.length > 0) {
  468. throw new Error("Decorators are not implemented.");
  469. }
  470. return block("class_creation", node.lineno, {
  471. "CLASS": this.identifier(name)
  472. }, {
  473. }, {
  474. "inline": "false"
  475. }, {
  476. //"arg": this.arguments_(args)
  477. }, {
  478. "BODY": this.convertBody(body)
  479. });
  480. }
  481. /*
  482. * value: expr_ty
  483. *
  484. */
  485. PythonToBlocks.prototype.Return = function(node)
  486. {
  487. var value = node.value;
  488. // No field, one title, one setting
  489. return block("procedures_return", node.lineno, {}, {
  490. "VALUE": this.convert(value)
  491. }, {
  492. "inline": "false"
  493. });
  494. }
  495. /*
  496. * targets: asdl_seq
  497. *
  498. */
  499. PythonToBlocks.prototype.Delete = function(/* {asdl_seq *} */ targets)
  500. {
  501. this.targets = targets;
  502. // TODO
  503. throw new Error("Delete is not implemented");
  504. }
  505. /*
  506. * targets: asdl_seq
  507. * value: expr_ty
  508. */
  509. PythonToBlocks.prototype.Assign = function(node)
  510. {
  511. var targets = node.targets;
  512. var value = node.value;
  513. if (targets.length == 0) {
  514. throw new Error("Nothing to assign to!");
  515. } else if (targets.length == 1) {
  516. return block("variables_set", node.lineno, {
  517. "VAR": this.Name_str(targets[0]) //targets
  518. }, {
  519. "VALUE": this.convert(value)
  520. });
  521. } else {
  522. //TODO
  523. throw new Error("Multiple Assigment Targets Not implemented");
  524. }
  525. }
  526. /*
  527. * target: expr_ty
  528. * op: operator_ty
  529. * value: expr_ty
  530. */
  531. PythonToBlocks.prototype.AugAssign = function(node)
  532. {
  533. var target = node.target;
  534. var op = node.op;
  535. var value = node.value;
  536. if (op.name != "Add") {
  537. //TODO
  538. throw new Error("Only addition is currently supported for augmented assignment!");
  539. } else {
  540. return block("math_change", node.lineno, {
  541. "VAR": this.Name_str(target)
  542. }, {
  543. "DELTA": this.convert(value)
  544. });
  545. }
  546. }
  547. /*
  548. * dest: expr_ty
  549. * values: asdl_seq
  550. * nl: bool
  551. *
  552. */
  553. PythonToBlocks.prototype.Print = function(node)
  554. {
  555. var dest = node.dest;
  556. var values = node.values;
  557. var nl = node.nl;
  558. if (values.length == 1) {
  559. return block("text_print", node.lineno, {}, {
  560. "TEXT": this.convert(values[0])
  561. });
  562. } else {
  563. return block("text_print_multiple", node.lineno, {},
  564. this.convertElements("PRINT", values),
  565. {
  566. "inline": "true"
  567. }, {
  568. "@items": values.length
  569. });
  570. }
  571. }
  572. /*
  573. * target: expr_ty
  574. * iter: expr_ty
  575. * body: asdl_seq
  576. * orelse: asdl_seq
  577. *
  578. */
  579. PythonToBlocks.prototype.For = function(node) {
  580. var target = node.target;
  581. var iter = node.iter;
  582. var body = node.body;
  583. var orelse = node.orelse;
  584. if (orelse.length > 0) {
  585. // TODO
  586. throw new Error("Or-else block of For is not implemented.");
  587. }
  588. return block("controls_forEach", node.lineno, {
  589. }, {
  590. "LIST": this.convert(iter),
  591. "VAR": this.convert(target)
  592. }, {
  593. "inline": "true"
  594. }, {}, {
  595. "DO": this.convertBody(body)
  596. });
  597. }
  598. /*
  599. * test: expr_ty
  600. * body: asdl_seq
  601. * orelse: asdl_seq
  602. */
  603. PythonToBlocks.prototype.While = function(node) {
  604. var test = node.test;
  605. var body = node.body;
  606. var orelse = node.orelse;
  607. if (orelse.length > 0) {
  608. // TODO
  609. throw new Error("Or-else block of While is not implemented.");
  610. }
  611. return block("controls_while", node.lineno, {}, {
  612. "BOOL": this.convert(test)
  613. }, {}, {}, {
  614. "DO": this.convertBody(body)
  615. });
  616. }
  617. /*
  618. * test: expr_ty
  619. * body: asdl_seq
  620. * orelse: asdl_seq
  621. *
  622. */
  623. PythonToBlocks.prototype.If = function(node)
  624. {
  625. var test = node.test;
  626. var body = node.body;
  627. var orelse = node.orelse;
  628. var IF_values = {"IF0": this.convert(test)};
  629. var DO_values = {"DO0": this.convertBody(body)};
  630. var elseifCount = 0;
  631. var elseCount = 0;
  632. var potentialElseBody = null;
  633. // Handle weird orelse stuff
  634. if (orelse !== undefined) {
  635. if (orelse.length == 1 &amp;&amp; orelse[0]._astname == "If") {
  636. // This is an 'ELIF'
  637. while (orelse.length == 1 &amp;&amp; orelse[0]._astname == "If") {
  638. this.heights.shift();
  639. elseifCount += 1;
  640. body = orelse[0].body;
  641. test = orelse[0].test;
  642. orelse = orelse[0].orelse;
  643. DO_values["DO"+elseifCount] = this.convertBody(body, false);
  644. if (test !== undefined) {
  645. IF_values["IF"+elseifCount] = this.convert(test);
  646. }
  647. }
  648. }
  649. if (orelse !== undefined &amp;&amp; orelse.length > 0) {
  650. // Or just the body of an Else statement
  651. elseCount += 1;
  652. DO_values["ELSE"] = this.convertBody(orelse);
  653. }
  654. }
  655. return block("controls_if", node.lineno, {
  656. }, IF_values, {
  657. "inline": "false"
  658. }, {
  659. "@elseif": elseifCount,
  660. "@else": elseCount
  661. }, DO_values);
  662. }
  663. /*
  664. * context_expr: expr_ty
  665. * optional_vars: expr_ty
  666. * body: asdl_seq
  667. */
  668. PythonToBlocks.prototype.With = function(node)
  669. {
  670. var context_expr = node.context_expr;
  671. var optional_vars = node.optional_vars;
  672. var body = node.body;
  673. throw new Error("With_ not implemented");
  674. }
  675. /*
  676. * type: expr_ty
  677. * inst: expr_ty
  678. * tback: expr_ty
  679. */
  680. PythonToBlocks.prototype.Raise = function(node)
  681. {
  682. var type = node.type;
  683. var inst = node.inst;
  684. var tback = node.tback;
  685. throw new Error("Raise not implemented");
  686. }
  687. /*
  688. * body: asdl_seq
  689. * handlers: asdl_seq
  690. * orelse: asdl_seq
  691. *
  692. */
  693. PythonToBlocks.prototype.TryExcept = function(node)
  694. {
  695. var body = node.body;
  696. var handlers = node.handlers;
  697. var orelse = node.orelse;
  698. throw new Error("TryExcept not implemented");
  699. }
  700. /*
  701. * body: asdl_seq
  702. * finalbody: asdl_seq
  703. *
  704. */
  705. PythonToBlocks.prototype.TryFinally = function(node)
  706. {
  707. var body = node.body;
  708. var finalbody = node.finalbody;
  709. throw new Error("TryExcept not implemented");
  710. }
  711. /*
  712. * test: expr_ty
  713. * msg: expr_ty
  714. */
  715. PythonToBlocks.prototype.Assert = function(node)
  716. {
  717. var test = node.test;
  718. var msg = node.msg;
  719. throw new Error("Assert not implemented");
  720. }
  721. /*
  722. * names: asdl_seq
  723. *
  724. */
  725. PythonToBlocks.prototype.Import = function(node)
  726. {
  727. var names = node.names;
  728. // The import statement isn't used in blockly because it happens implicitly
  729. return null;
  730. }
  731. /*
  732. * module: identifier
  733. * names: asdl_seq
  734. * level: int
  735. *
  736. */
  737. PythonToBlocks.prototype.ImportFrom = function(node)
  738. {
  739. var module = node.module;
  740. var names = node.names;
  741. var level = node.level;
  742. // The import statement isn't used in blockly because it happens implicitly
  743. return null;
  744. }
  745. /*
  746. * body: expr_ty
  747. * globals: expr_ty
  748. * locals: expr_ty
  749. *
  750. */
  751. PythonToBlocks.prototype.Exec = function(node) {
  752. var body = node.body;
  753. var globals = node.globals;
  754. var locals = node.locals;
  755. throw new Error("Exec not implemented");
  756. }
  757. /*
  758. * names: asdl_seq
  759. *
  760. */
  761. PythonToBlocks.prototype.Global = function(node)
  762. {
  763. var names = node.names;
  764. throw new Error("Globals not implemented");
  765. }
  766. /*
  767. * value: expr_ty
  768. *
  769. */
  770. PythonToBlocks.prototype.Expr = function(node, is_top_level) {
  771. var value = node.value;
  772. var converted = this.convert(value);
  773. if (converted.constructor == Array) {
  774. return converted[0];
  775. } else if (is_top_level === true) {
  776. return [this.convert(value)];
  777. } else {
  778. return block("raw_empty", node.lineno, {}, {
  779. "VALUE": this.convert(value)
  780. });
  781. }
  782. }
  783. /*
  784. *
  785. *
  786. */
  787. PythonToBlocks.prototype.Pass = function() {
  788. return null; //block("controls_pass");
  789. }
  790. /*
  791. *
  792. *
  793. */
  794. PythonToBlocks.prototype.Break = function(node) {
  795. return block("controls_flow_statements", node.lineno, {
  796. "FLOW": "BREAK"
  797. });
  798. }
  799. /*
  800. *
  801. *
  802. */
  803. PythonToBlocks.prototype.Continue = function(node) {
  804. return block("controls_flow_statements", node.lineno, {
  805. "FLOW": "CONTINUE"
  806. });
  807. }
  808. /*
  809. * TODO: what does this do?
  810. *
  811. */
  812. PythonToBlocks.prototype.Debugger = function() {
  813. return null;
  814. }
  815. PythonToBlocks.prototype.booleanOperator = function(op) {
  816. switch (op.name) {
  817. case "And": return "AND";
  818. case "Or": return "OR";
  819. default: throw new Error("Operator not supported:"+op.name);
  820. }
  821. }
  822. /*
  823. * op: boolop_ty
  824. * values: asdl_seq
  825. */
  826. PythonToBlocks.prototype.BoolOp = function(node) {
  827. var op = node.op;
  828. var values = node.values;
  829. // TODO: is there ever a case where it's &lt; 1 values?
  830. var result_block = this.convert(values[0]);
  831. for (var i = 1; i &lt; values.length; i+= 1) {
  832. result_block = block("logic_operation", node.lineno, {
  833. "OP": this.booleanOperator(op)
  834. }, {
  835. "A": result_block,
  836. "B": this.convert(values[i])
  837. }, {
  838. "inline": "true"
  839. });
  840. }
  841. return result_block;
  842. }
  843. PythonToBlocks.prototype.binaryOperator = function(op) {
  844. switch (op.name) {
  845. case "Add": return "ADD";
  846. case "Sub": return "MINUS";
  847. case "Div": case "FloorDiv": return "DIVIDE";
  848. case "Mult": return "MULTIPLY";
  849. case "Pow": return "POWER";
  850. case "Mod": return "MODULO";
  851. default: throw new Error("Operator not supported:"+op.name);
  852. }
  853. }
  854. /*
  855. * left: expr_ty
  856. * op: operator_ty
  857. * right: expr_ty
  858. */
  859. PythonToBlocks.prototype.BinOp = function(node)
  860. {
  861. var left = node.left;
  862. var op = node.op;
  863. var right = node.right;
  864. return block("math_arithmetic", node.lineno, {
  865. "OP": this.binaryOperator(op) // TODO
  866. }, {
  867. "A": this.convert(left),
  868. "B": this.convert(right)
  869. }, {
  870. "inline": true
  871. });
  872. }
  873. /*
  874. * op: unaryop_ty
  875. * operand: expr_ty
  876. */
  877. PythonToBlocks.prototype.UnaryOp = function(node)
  878. {
  879. var op = node.op;
  880. var operand = node.operand;
  881. if (op.name == "Not") {
  882. return block("logic_negate", node.lineno, {}, {
  883. "BOOL": this.convert(operand)
  884. }, {
  885. "inline": "false"
  886. });
  887. } else {
  888. throw new Error("Other unary operators are not implemented yet.");
  889. }
  890. }
  891. /*
  892. * args: arguments__ty
  893. * body: expr_ty
  894. */
  895. PythonToBlocks.prototype.Lambda = function(node) {
  896. var args = node.args;
  897. var body = node.body;
  898. throw new Error("Lambda functions are not implemented yet.");
  899. }
  900. /*
  901. * test: expr_ty
  902. * body: expr_ty
  903. * orelse: expr_ty
  904. */
  905. PythonToBlocks.prototype.IfExp = function(node)
  906. {
  907. var test = node.test;
  908. var body = node.body;
  909. var orelse = node.orelse;
  910. throw new Error("Inline IF expressions are not implemented yet.");
  911. }
  912. /*
  913. * keys: asdl_seq
  914. * values: asdl_seq
  915. */
  916. PythonToBlocks.prototype.Dict = function(node) {
  917. var keys = node.keys;
  918. var values = node.values;
  919. var keyList = [];
  920. var valueList = [];
  921. for (var i = 0; i &lt; keys.length; i+= 1) {
  922. if (keys[i]._astname != "Str") {
  923. throw new Error("Dictionary Keys should be Strings.");
  924. }
  925. keyList["KEY"+i] = this.Str_value(keys[i]);
  926. valueList["VALUE"+i] = this.convert(values[i]);
  927. }
  928. return block("dicts_create_with", node.lineno, keyList, valueList, {
  929. "inline": "false"
  930. }, {
  931. "@items": keys.length
  932. });
  933. }
  934. /*
  935. * elts: asdl_seq
  936. *
  937. */
  938. PythonToBlocks.prototype.Set = function(node)
  939. {
  940. var elts = node.elts;
  941. throw new Error("Sets are not implemented");
  942. }
  943. /*
  944. * elt: expr_ty
  945. * generators: asdl_seq
  946. */
  947. PythonToBlocks.prototype.ListComp = function(node)
  948. {
  949. var elt = node.elt;
  950. var generators = node.generators;
  951. // TODO
  952. }
  953. /*
  954. * elt: expr_ty
  955. * generators: asdl_seq
  956. */
  957. PythonToBlocks.prototype.SetComp = function(node)
  958. {
  959. var elt = node.elt;
  960. var generators = node.generators;
  961. throw new Error("Set Comprehensions are not implemented");
  962. }
  963. /*
  964. * key: expr_ty
  965. * value: expr_ty
  966. * generators: asdl_seq
  967. */
  968. PythonToBlocks.prototype.DictComp = function(node)
  969. {
  970. var key = node.key;
  971. var value = node.value;
  972. var generators = node.generators;
  973. throw new Error("Dictionary Comprehensions are not implemented");
  974. }
  975. /*
  976. * elt: expr_ty
  977. * generators: asdl_seq
  978. */
  979. PythonToBlocks.prototype.GeneratorExp = function(node) {
  980. var elt = node.elt;
  981. var generators = node.generators;
  982. throw new Error("Generator Expresions are not implemented");
  983. }
  984. /*
  985. * value: expr_ty
  986. *
  987. */
  988. PythonToBlocks.prototype.Yield = function(node)
  989. {
  990. var value = value;
  991. throw new Error("Yield expression is not implemented");
  992. }
  993. PythonToBlocks.prototype.compareOperator = function(op) {
  994. switch (op.name) {
  995. case "Eq": return "EQ";
  996. case "NotEq": return "NEQ";
  997. case "Lt": return "LT";
  998. case "Gt": return "GT";
  999. case "LtE": return "LTE";
  1000. case "GtE": return "GTE";
  1001. case "In_": return "IN";
  1002. case "NotIn": return "NOTIN";
  1003. // Is, IsNot, In, NotIn
  1004. default: throw new Error("Operator not supported:"+op.name);
  1005. }
  1006. }
  1007. /*
  1008. * left: expr_ty
  1009. * ops: asdl_int_seq
  1010. * asdl_seq: comparators
  1011. */
  1012. PythonToBlocks.prototype.Compare = function(node)
  1013. {
  1014. var left = node.left;
  1015. var ops = node.ops;
  1016. var comparators = node.comparators;
  1017. if (ops.length != 1) {
  1018. throw new Error("Only one comparison operator is supported");
  1019. } else if (ops[0].name == "In_" || ops[0].name == "NotIn") {
  1020. return block("logic_isIn", node.lineno, {
  1021. "OP": this.compareOperator(ops[0])
  1022. }, {
  1023. "ITEM": this.convert(left),
  1024. "LIST": this.convert(comparators[0])
  1025. }, {
  1026. "inline": "true"
  1027. });
  1028. } else {
  1029. return block("logic_compare", node.lineno, {
  1030. "OP": this.compareOperator(ops[0])
  1031. }, {
  1032. "A": this.convert(left),
  1033. "B": this.convert(comparators[0])
  1034. }, {
  1035. "inline": "true"
  1036. });
  1037. }
  1038. }
  1039. convertStockSymbols = function(symbol) {
  1040. switch (symbol) {
  1041. case 'FB': case "Facebook":
  1042. return "Facebook";
  1043. case "AAPL": case "Apple":
  1044. return "Apple";
  1045. case "MSFT": case "Microsoft":
  1046. return "Microsoft";
  1047. case "GOOG": case "Google":
  1048. return "Google";
  1049. default:
  1050. throw new Error("Unknown Stock Symbol.");
  1051. }
  1052. }
  1053. toTitleCase = function(str) {
  1054. return str.replace(/\w\S*/g, function(txt){
  1055. return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
  1056. });
  1057. }
  1058. PythonToBlocks.KNOWN_MODULES = {
  1059. "weather": {
  1060. "get_temperature": ["weather_temperature", "CITY"],
  1061. "get_report": ["weather_report", "CITY"],
  1062. "get_forecasts": ["weather_forecasts", "CITY"],
  1063. "get_highs_lows": ["weather_highs_lows", "CITY"],
  1064. "get_all_forecasted_temperatures": ["weather_all_forecasts"],
  1065. "get_forecasted_reports": ["weather_report_forecasts", "CITY"]
  1066. },
  1067. "earthquakes": {
  1068. "get": ["earthquake_get", "PROPERTY"],
  1069. "get_both": ["earthquake_both"],
  1070. "get_all": ["earthquake_all"]
  1071. },
  1072. "stocks": {
  1073. "get_current": ["stocks_current", ["TICKER", convertStockSymbols]],
  1074. "get_past": ["stocks_past", ["TICKER", convertStockSymbols]]
  1075. },
  1076. "crime": {
  1077. // STATE = toTitleCase
  1078. "get_property_crimes": ["crime_state", ["STATE", toTitleCase],
  1079. ["TYPE", "property"]],
  1080. "get_violent_crimes": ["crime_state", ["STATE", toTitleCase],
  1081. ["TYPE", "violent"]],
  1082. "get_by_year": ["crime_year", "YEAR"],
  1083. "get_all": ["crime_all"]
  1084. },
  1085. "books": {
  1086. "get_all": ["books_get"]
  1087. },
  1088. "plt": {
  1089. "title": ["*plot_title", "TEXT"],
  1090. "xlabel": ["*plot_xlabel", "TEXT"],
  1091. "ylabel": ["*plot_ylabel", "TEXT"],
  1092. "hist": ["*plot_hist", {"type": "variable", "mode": "value", "name": "values"}],
  1093. "scatter": ["*plot_scatter", {"type": "variable", "mode": "value", "name": "x_values"},
  1094. {"type": "variable", "mode": "value", "name": "y_values"}],
  1095. "show": ["*plot_show"]
  1096. }
  1097. };
  1098. PythonToBlocks.prototype.KNOWN_FUNCTIONS = ["append", "strip", "rstrip", "lstrip"];
  1099. PythonToBlocks.KNOWN_ATTR_FUNCTIONS = {};
  1100. PythonToBlocks.prototype.CallAttribute = function(func, args, keywords, starargs, kwargs, node) {
  1101. var name = this.identifier(func.attr);
  1102. if (func.value._astname == "Name") {
  1103. var module = this.identifier(func.value.id);
  1104. if (module == "plt" &amp;&amp; name == "plot") {
  1105. if (args.length == 1) {
  1106. return [block("plot_line", func.lineno, {}, {
  1107. "y_values": this.convert(args[0])
  1108. }, {"inline": "false"})];
  1109. } else if (args.length == 2) {
  1110. return [block("plot_lineXY", func.lineno, {}, {
  1111. "x_values": this.convert(args[0]),
  1112. "y_values": this.convert(args[1])
  1113. }, {"inline": "false"})];
  1114. } else {
  1115. throw new Error("Incorrect number of arguments to plt.plot");
  1116. }
  1117. } else if (module in PythonToBlocks.KNOWN_MODULES &amp;&amp; name in PythonToBlocks.KNOWN_MODULES[module]) {
  1118. var definition = PythonToBlocks.KNOWN_MODULES[module][name];
  1119. var blockName = definition[0];
  1120. var isExpression = true;
  1121. if (blockName.charAt(0) == "*") {
  1122. blockName = blockName.slice(1);
  1123. isExpression = false;
  1124. }
  1125. var fields = {};
  1126. var mutations = {};
  1127. var values = {};
  1128. for (var i = 0; i &lt; args.length; i++) {
  1129. var argument = definition[1+i];
  1130. var destination = fields;
  1131. if (typeof argument == "string") {
  1132. fields[argument] = this.Str_value(args[i]);
  1133. } else if (typeof argument == "object") {
  1134. if (argument.mode == "value") {
  1135. destination = values;
  1136. }
  1137. if (argument.add_mutation !== undefined) {
  1138. mutations[argument.add_mutation.name] = argument.add_mutation.value;
  1139. }
  1140. if (argument.type == 'mutation') {
  1141. if (argument.index == undefined) {
  1142. mutations[argument.name] = this.Str_value(args[i]);
  1143. } else {
  1144. mutations[argument.name] = this.Str_value(args[argument.index+1]);
  1145. }
  1146. } else if (argument.type == "integer") {
  1147. destination[argument.name] = this.Num_value(args[i]);
  1148. } else if (argument.type == 'variable') {
  1149. destination[argument.name] = this.convert(args[i]);
  1150. } else if (argument.type == "integer_mapper") {
  1151. // Okay we jumped the shark here
  1152. var argumentName = argument.name;
  1153. var argumentMapper = argument.method;
  1154. destination[argumentName] = argumentMapper(this.Num_value(args[i]));
  1155. } else if (argument.type == 'mapper') {
  1156. var argumentName = argument.name;
  1157. var argumentMapper = argument.method;
  1158. destination[argumentName] = argumentMapper(this.Str_value(args[i]));
  1159. }
  1160. } else {
  1161. var argumentName = argument[0];
  1162. var argumentMapper = argument[1];
  1163. fields[argumentName] = argumentMapper(this.Str_value(args[i]));
  1164. }
  1165. }
  1166. for (var i = 1+args.length; i &lt; definition.length; i++) {
  1167. var first = definition[i][0];
  1168. var second = definition[i][1];
  1169. fields[first] = second;
  1170. }
  1171. if (isExpression) {
  1172. var k = block(blockName, func.lineno, fields, values, [], mutations);
  1173. return k;
  1174. } else {
  1175. return [block(blockName, func.lineno, fields, values, [], mutations)];
  1176. }
  1177. }
  1178. }
  1179. if (this.KNOWN_FUNCTIONS.indexOf(name) > -1) {
  1180. switch (name) {
  1181. case "append":
  1182. if (args.length !== 1) {
  1183. throw new Error("Incorrect number of arguments to .append");
  1184. }
  1185. // Return as statement
  1186. return [block("lists_append", func.lineno, {}, {
  1187. "ITEM": this.convert(args[0]),
  1188. "LIST": this.convert(func.value)
  1189. }, {
  1190. "inline": "true"
  1191. })];
  1192. case "strip":
  1193. return block("text_trim", func.lineno, { "MODE": "BOTH" },
  1194. { "TEXT": this.convert(func.value) });
  1195. case "lstrip":
  1196. return block("text_trim", func.lineno, { "MODE": "LEFT" },
  1197. { "TEXT": this.convert(func.value) });
  1198. case "rstrip":
  1199. return block("text_trim", func.lineno, { "MODE": "RIGHT" },
  1200. { "TEXT": this.convert(func.value) });
  1201. default: throw new Error("Unknown function call!");
  1202. }
  1203. } else if (name in PythonToBlocks.KNOWN_ATTR_FUNCTIONS) {
  1204. return PythonToBlocks.KNOWN_ATTR_FUNCTIONS[name].bind(this)(func, args, keywords, starargs, kwargs, node)
  1205. } else {
  1206. console.log(func, args, keywords, starargs, kwargs);
  1207. heights = this.getChunkHeights(node);
  1208. extractedSource = this.getSourceCode(arrayMin(heights), arrayMax(heights));
  1209. var col_endoffset = node.col_endoffset;
  1210. if (args.length > 0) {
  1211. for (var i = 0; i &lt; args.length; i+= 1) {
  1212. col_endoffset = args[i].col_endoffset;
  1213. }
  1214. } else {
  1215. col_endoffset += 2;
  1216. expressionCall += "()";
  1217. }
  1218. var expressionCall = extractedSource.slice(node.col_offset, 1+col_endoffset);
  1219. //console.log(node, extractedSource, node.col_offset, node.col_endoffset);
  1220. var lineno = node.lineno;
  1221. //console.error(e);
  1222. //return raw_expression(expressionCall, lineno);
  1223. var argumentsNormal = {};
  1224. var argumentsMutation = {"@name": name};
  1225. for (var i = 0; i &lt; args.length; i+= 1) {
  1226. argumentsNormal["ARG"+i] = this.convert(args[i]);
  1227. argumentsMutation[i] = this.convert(args[i]);
  1228. }
  1229. var methodCall = block("procedures_callreturn", node.lineno, {
  1230. }, argumentsNormal, {
  1231. "inline": "false"
  1232. }, argumentsMutation);
  1233. return block("attribute_access", node.lineno, {}, {
  1234. "MODULE": this.convert(func.value),
  1235. "NAME": methodCall
  1236. }, { "inline": "true"}, {});
  1237. }
  1238. }
  1239. /*
  1240. * func: expr_ty
  1241. * args: asdl_seq
  1242. * keywords: asdl_seq
  1243. * starargs: expr_ty
  1244. * kwargs: expr_ty
  1245. *
  1246. */
  1247. PythonToBlocks.prototype.Call = function(node) {
  1248. var func = node.func;
  1249. var args = node.args;
  1250. var keywords = node.keywords;
  1251. var starargs = node.starargs;
  1252. var kwargs = node.kwargs;
  1253. switch (func._astname) {
  1254. case "Name":
  1255. switch (this.identifier(func.id)) {
  1256. case "print":
  1257. if (args.length == 1) {
  1258. return [block("text_print", node.lineno, {}, {
  1259. "TEXT": this.convert(args[0])})];
  1260. } else {
  1261. return [block("text_print_multiple", node.lineno, {},
  1262. this.convertElements("PRINT", args),
  1263. {"inline": "true"
  1264. }, { "@items": args.length})];
  1265. }
  1266. case "abs":
  1267. return block("math_single", node.lineno, {"OP": "ABS"}, {"NUM": this.convert(args[0])})
  1268. case "round":
  1269. return block("math_round", node.lineno, {"OP": "ROUND"}, {"NUM": this.convert(args[0])})
  1270. case "sum":
  1271. return block("math_on_list", node.lineno, {"OP": "SUM"}, {"LIST": this.convert(args[0])})
  1272. case "min":
  1273. return block("math_on_list", node.lineno, {"OP": "MIN"}, {"LIST": this.convert(args[0])})
  1274. case "max":
  1275. return block("math_on_list", node.lineno, {"OP": "MAX"}, {"LIST": this.convert(args[0])})
  1276. case "len":
  1277. return block("lists_length", node.lineno, {}, {"VALUE": this.convert(args[0])})
  1278. case "xrange":
  1279. return block("procedures_callreturn", node.lineno, {},
  1280. {"ARG0": this.convert(args[0])},
  1281. {"inline": "true"},
  1282. {"@name": "xrange",
  1283. "": this.convert(args[0])})
  1284. default:
  1285. if (starargs !== null &amp;&amp; starargs.length > 0) {
  1286. throw new Error("*args (variable arguments) are not implemented yet.");
  1287. } else if (kwargs !== null &amp;&amp; kwargs.length > 0) {
  1288. throw new Error("**args (keyword arguments) are not implemented yet.");
  1289. }
  1290. var argumentsNormal = {};
  1291. var argumentsMutation = {"@name": this.identifier(func.id)};
  1292. for (var i = 0; i &lt; args.length; i+= 1) {
  1293. argumentsNormal["ARG"+i] = this.convert(args[i]);
  1294. argumentsMutation[i] = this.convert(args[i]);
  1295. }
  1296. return block("procedures_callreturn", node.lineno, {}, argumentsNormal, {
  1297. "inline": "false"
  1298. }, argumentsMutation);
  1299. }
  1300. // Direct function call
  1301. case "Attribute":
  1302. // Module function call
  1303. return this.CallAttribute(func, args, keywords, starargs, kwargs, node);
  1304. }
  1305. }
  1306. /*
  1307. * value: expr_ty
  1308. *
  1309. */
  1310. PythonToBlocks.prototype.Repr = function(node)
  1311. {
  1312. var value = node.value;
  1313. throw new Error("Repr is not yet implemented");
  1314. }
  1315. /*
  1316. * n: object
  1317. *
  1318. */
  1319. PythonToBlocks.prototype.Num = function(node)
  1320. {
  1321. var n = node.n;
  1322. return block("math_number", node.lineno, {"NUM": Sk.ffi.remapToJs(n)});
  1323. }
  1324. PythonToBlocks.prototype.Num_value = function(node)
  1325. {
  1326. var n = node.n;
  1327. return Sk.ffi.remapToJs(n);
  1328. }
  1329. /*
  1330. * s: string
  1331. *
  1332. */
  1333. PythonToBlocks.prototype.Str = function(node)
  1334. {
  1335. var s = node.s;
  1336. var strValue = Sk.ffi.remapToJs(s);
  1337. if (strValue.split("\n").length > 1) {
  1338. return block("string_multiline", node.lineno, {"TEXT": strValue});
  1339. } else {
  1340. return block("text", node.lineno, {"TEXT": strValue});
  1341. }
  1342. }
  1343. PythonToBlocks.prototype.Str_value = function(node) {
  1344. var s = node.s;
  1345. return Sk.ffi.remapToJs(s);
  1346. }
  1347. /*
  1348. * value: expr_ty
  1349. * attr: identifier
  1350. * ctx: expr_context_ty
  1351. *
  1352. */
  1353. PythonToBlocks.prototype.Attribute = function(node)
  1354. {
  1355. var value = node.value;
  1356. var attr = node.attr;
  1357. var ctx = node.ctx;
  1358. console.log(node);
  1359. return block("attribute_access", node.lineno, {
  1360. "MODULE": this.convert(value),
  1361. "NAME": this.convert(attr)
  1362. });
  1363. //throw new Error("Attribute access not implemented");
  1364. }
  1365. /*
  1366. * value: expr_ty
  1367. * slice: slice_ty
  1368. * ctx: expr_context_ty
  1369. *
  1370. */
  1371. PythonToBlocks.prototype.Subscript = function(node)
  1372. {
  1373. var value = node.value;
  1374. var slice = node.slice;
  1375. var ctx = node.ctx;
  1376. if (slice.value._astname == "Str") {
  1377. return block("dict_get_literal", node.lineno, {
  1378. "ITEM": this.Str_value(slice.value)
  1379. }, {
  1380. "DICT": this.convert(value)
  1381. });
  1382. } else if (slice.value._astname == "Num") {
  1383. return block("lists_index", node.lineno, {}, {
  1384. "ITEM": this.convert(slice.value),
  1385. "LIST": this.convert(value),
  1386. });
  1387. }
  1388. throw new Error("This kind of subscript is not supported.");
  1389. }
  1390. /*
  1391. * id: identifier
  1392. * ctx: expr_context_ty
  1393. */
  1394. PythonToBlocks.prototype.Name = function(node)
  1395. {
  1396. var id = node.id;
  1397. var ctx = node.ctx;
  1398. switch (this.Name_str(node)) {
  1399. case "True":
  1400. return block("logic_boolean", node.lineno, {"BOOL": "TRUE"});
  1401. case "False":
  1402. return block("logic_boolean", node.lineno, {"BOOL": "FALSE"});
  1403. case "None":
  1404. return block("logic_null", node.lineno);
  1405. case "___":
  1406. return null;
  1407. default:
  1408. return block('variables_get', node.lineno, {
  1409. "VAR": this.identifier(id)
  1410. });
  1411. }
  1412. }
  1413. /*
  1414. * id: identifier
  1415. * ctx: expr_context_ty
  1416. */
  1417. PythonToBlocks.prototype.Name_str = function(node)
  1418. {
  1419. var id = node.id;
  1420. var ctx = node.ctx;
  1421. return this.identifier(id);
  1422. }
  1423. PythonToBlocks.prototype.convertElements = function(key, values) {
  1424. var output = {};
  1425. for (var i = 0; i &lt; values.length; i++) {
  1426. output[key+i] = this.convert(values[i]);
  1427. }
  1428. return output;
  1429. }
  1430. /*
  1431. * elts: asdl_seq
  1432. * ctx: expr_context_ty
  1433. *
  1434. */
  1435. PythonToBlocks.prototype.List = function(node) {
  1436. var elts = node.elts;
  1437. var ctx = node.ctx;
  1438. return block("lists_create_with", node.lineno, {},
  1439. this.convertElements("ADD", elts)
  1440. , {
  1441. "inline": elts.length > 3 ? "false" : "true",
  1442. }, {
  1443. "@items": elts.length
  1444. });
  1445. }
  1446. /*
  1447. * elts: asdl_seq
  1448. * ctx: expr_context_ty
  1449. */
  1450. PythonToBlocks.prototype.Tuple = function(node)
  1451. {
  1452. var elts = node.elts;
  1453. var ctx = node.ctx;
  1454. throw new Error("Tuples not implemented");
  1455. }
  1456. /*
  1457. *
  1458. *
  1459. */
  1460. PythonToBlocks.prototype.Ellipsis = function() {
  1461. throw new Error("Ellipsis not implemented");
  1462. }
  1463. /*
  1464. * lower: expr_ty
  1465. * upper: expr_ty
  1466. * step: expr_ty
  1467. *
  1468. */
  1469. PythonToBlocks.prototype.Slice = function(node)
  1470. {
  1471. var lower = node.lower;
  1472. var upper = node.upper;
  1473. var step = node.step;
  1474. throw new Error("Slices not implemented");
  1475. }
  1476. /*
  1477. * dims: asdl_seq
  1478. *
  1479. */
  1480. PythonToBlocks.prototype.ExtSlice = function(node)
  1481. {
  1482. var dims = node.dims;
  1483. throw new Error("ExtSlice is not implemented.");
  1484. }
  1485. /*
  1486. * value: expr_ty
  1487. *
  1488. */
  1489. PythonToBlocks.prototype.Index = function(value)
  1490. {
  1491. var value = node.value;
  1492. throw new Error("Index is not implemented");
  1493. }
  1494. /*
  1495. * target: expr_ty
  1496. * iter: expr_ty
  1497. * ifs: asdl_seq
  1498. *
  1499. */
  1500. PythonToBlocks.prototype.comprehension = function(node)
  1501. {
  1502. var target = node.target;
  1503. var iter = node.iter;
  1504. var ifs = node.ifs;
  1505. throw new Error("Comprehensions not implemented.");
  1506. }
  1507. /*
  1508. * type: expr_ty
  1509. * name: expr_ty
  1510. * body: asdl_seq
  1511. *
  1512. */
  1513. PythonToBlocks.prototype.ExceptHandler = function(node)
  1514. {
  1515. var type = node.type;
  1516. var name = node.name;
  1517. var body = node.boy;
  1518. throw new Error("Except handlers are not implemented");
  1519. }
  1520. PythonToBlocks.prototype.argument_ = function(node) {
  1521. var id = node.id;
  1522. return this.identifier(id);
  1523. }
  1524. /*
  1525. * args: asdl_seq
  1526. * vararg: identifier
  1527. * kwarg: identifier
  1528. * defaults: asdl_seq
  1529. *
  1530. */
  1531. PythonToBlocks.prototype.arguments_ = function(node)
  1532. {
  1533. var args = node.args;
  1534. var vararg = node.vararg;
  1535. var kwarg = node.kwarg;
  1536. var defaults = node.defaults;
  1537. var allArgs = [];
  1538. for (var i = 0; i &lt; args.length; i++) {
  1539. var arg = args[i];
  1540. allArgs.push(this.argument_(arg));
  1541. }
  1542. return allArgs;
  1543. }
  1544. /*
  1545. * arg: identifier
  1546. * value: expr_ty
  1547. *
  1548. */
  1549. PythonToBlocks.prototype.keyword = function(node)
  1550. {
  1551. var arg = node.arg;
  1552. var value = node.value;
  1553. throw new Error("Keywords are not implemented");
  1554. }
  1555. /*
  1556. * name: identifier
  1557. * asname: identifier
  1558. *
  1559. */
  1560. PythonToBlocks.prototype.alias = function(node)
  1561. {
  1562. var name = node.name;
  1563. var asname = node.asname;
  1564. throw new Error("Aliases are not implemented");
  1565. }
  1566. /* ----- expr_context ----- */
  1567. /*
  1568. Load
  1569. Store
  1570. Del
  1571. AugLoad
  1572. AugStore
  1573. Param
  1574. */
  1575. /* ----- operator ----- */
  1576. /*
  1577. Add
  1578. Sub
  1579. Mult
  1580. Div
  1581. Mod
  1582. Pow
  1583. LShift
  1584. RShift
  1585. BitOr
  1586. BitXor
  1587. BitAnd
  1588. FloorDiv
  1589. */
  1590. /* ----- unaryop ----- */
  1591. /*
  1592. Invert
  1593. Not
  1594. UAdd
  1595. USub
  1596. */</code></pre>
  1597. </article>
  1598. </section>
  1599. </div>
  1600. <nav>
  1601. <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="BlockPy.html">BlockPy</a></li><li><a href="BlockPyCorgis.html">BlockPyCorgis</a></li><li><a href="BlockPyDialog.html">BlockPyDialog</a></li><li><a href="BlockPyEditor.html">BlockPyEditor</a></li><li><a href="BlockPyEngine.html">BlockPyEngine</a></li><li><a href="BlockPyEnglish.html">BlockPyEnglish</a></li><li><a href="BlockPyFeedback.html">BlockPyFeedback</a></li><li><a href="BlockPyHistory.html">BlockPyHistory</a></li><li><a href="BlockPyPresentation.html">BlockPyPresentation</a></li><li><a href="BlockPyPrinter.html">BlockPyPrinter</a></li><li><a href="BlockPyServer.html">BlockPyServer</a></li><li><a href="BlockPyToolbar.html">BlockPyToolbar</a></li><li><a href="LocalStorageWrapper.html">LocalStorageWrapper</a></li><li><a href="PythonToBlocks.html">PythonToBlocks</a></li></ul><h3>Global</h3><ul><li><a href="global.html#BlockPyInterface">BlockPyInterface</a></li><li><a href="global.html#cloneNode">cloneNode</a></li><li><a href="global.html#encodeHTML">encodeHTML</a></li><li><a href="global.html#expandArray">expandArray</a></li><li><a href="global.html#EXTENDED_ERROR_EXPLANATION">EXTENDED_ERROR_EXPLANATION</a></li><li><a href="global.html#indent">indent</a></li><li><a href="global.html#instructor_module">instructor_module</a></li><li><a href="global.html#prettyPrintDateTime">prettyPrintDateTime</a></li><li><a href="global.html#randomInteger">randomInteger</a></li><li><a href="global.html#set_button_loaded">set_button_loaded</a></li><li><a href="global.html#timerGuard">timerGuard</a></li></ul>
  1602. </nav>
  1603. <br class="clear">
  1604. <footer>
  1605. Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a> on Sun Mar 26 2017 09:45:03 GMT-0400 (Eastern Daylight Time)
  1606. </footer>
  1607. <script> prettyPrint(); </script>
  1608. <script src="scripts/linenumber.js"> </script>
  1609. </body>
  1610. </html>