parseFromVisual.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. // iVProg - www.usp.br/line/ivprog
  2. // LInE - Free Education, Private Data
  3. // This is used when is loaded "ivph" file (under the button "upload" or GET)
  4. import { IVProgParser } from "../ast/ivprogParser";
  5. import * as Expressions from "../ast/expressions";
  6. import { Types } from "../typeSystem/types";
  7. import { convertBoolToString } from "../typeSystem/parsers";
  8. import * as Commands from "../ast/commands";
  9. import { ArrayType } from "../typeSystem/array_type";
  10. import { Literal } from "../ast/expressions/literal";
  11. const TYPES = {
  12. VARIABLE: "var",
  13. CONST: "const",
  14. FUNCTION: "function",
  15. RELATIONAL: "relational",
  16. LOGIC: "logic",
  17. ARITHMETIC: "arithmetic",
  18. };
  19. function translateOp (type, op) {
  20. switch (type) {
  21. case TYPES.ARITHMETIC:
  22. return op.value;
  23. case TYPES.RELATIONAL:
  24. return op.value;
  25. case TYPES.LOGIC: {
  26. if (op.ord === 11) {
  27. return "and";
  28. } else if (op.ord === 12) {
  29. return "or";
  30. } else {
  31. return "not";
  32. }
  33. }
  34. }
  35. }
  36. function getOpType (op) {
  37. switch (op.ord) {
  38. case 0:
  39. case 1:
  40. case 2:
  41. case 3:
  42. case 4:
  43. return TYPES.ARITHMETIC;
  44. case 5:
  45. case 6:
  46. case 7:
  47. case 8:
  48. case 9:
  49. case 10:
  50. return TYPES.RELATIONAL;
  51. default:
  52. return TYPES.LOGIC;
  53. }
  54. }
  55. /**
  56. * @param {Commands.Case} switchCase
  57. * */
  58. function switchCaseWalker (switchCase) {
  59. const commands = switchCase.commands.map(commandWalker);
  60. const expression = switchCase.isDefault ? null : expressionWalker(switchCase.expression);
  61. return {
  62. type: "switchcase",
  63. line: switchCase.sourceInfo.line,
  64. expression,
  65. commands,
  66. };
  67. }
  68. /**
  69. * @param {Commands.Switch} switchCommand
  70. * */
  71. function switchWalker (switchCommand) {
  72. const expression = expressionWalker(switchCommand.expression);
  73. const cases = switchCommand.cases.map(switchCaseWalker);
  74. return {
  75. type: "switch",
  76. expression,
  77. cases,
  78. };
  79. }
  80. /**
  81. * @param {Commands.Return} returnCommand
  82. * */
  83. function returnWalker (returnCommand) {
  84. let expression = null;
  85. if (returnCommand.expression !== null) {
  86. expression = expressionWalker(returnCommand.expression);
  87. }
  88. return {
  89. type: "return",
  90. expression,
  91. };
  92. }
  93. function breakWalker (_) {
  94. return { type: "break" };
  95. }
  96. /**
  97. * @param {Commands.For} forLoop
  98. * */
  99. function forWalker (forLoop) {
  100. const var_attribution = expressionWalker(forLoop.for_id);
  101. const var_initial = expressionWalker(forLoop.for_from);
  102. const condition = expressionWalker(forLoop.for_to);
  103. const step_expression = forLoop.for_pass ? expressionWalker(forLoop.for_pass) : [];
  104. const commands = forLoop.commands.map(commandWalker);
  105. return {
  106. type: "repeatNtimes",
  107. var_attribution,
  108. var_initial,
  109. condition,
  110. step_expression,
  111. commands,
  112. };
  113. }
  114. /**
  115. * @param {Commands.While} whileLoop
  116. * */
  117. function whileWalker (whileLoop) {
  118. const expression = expressionWalker(whileLoop.expression);
  119. const commands = whileLoop.commands.map(commandWalker);
  120. let type = whileLoop.testFirst ? "whiletrue" : "dowhiletrue";
  121. return {
  122. type,
  123. expression,
  124. commands,
  125. };
  126. }
  127. /**
  128. * @param {Commands.IfThenElse} ifthenelse
  129. * */
  130. function ifThenElseWalker (ifthenelse) {
  131. //ifthenelse.
  132. const expression = expressionWalker(ifthenelse.condition);
  133. const ifTrue = ifthenelse.ifTrue.commands.map(commandWalker);
  134. let ifFalse = [];
  135. if (ifthenelse.ifFalse) {
  136. if (ifthenelse.ifFalse instanceof Commands.CommandBlock) {
  137. ifFalse = ifthenelse.ifFalse.commands.map(commandWalker);
  138. } else {
  139. ifFalse = [ifThenElseWalker(ifthenelse.ifFalse)];
  140. }
  141. }
  142. return {
  143. type: "iftrue",
  144. expression,
  145. ifTrue,
  146. ifFalse,
  147. };
  148. }
  149. /**
  150. * @param {Commands.Assign} assingment
  151. * */
  152. function assignmentWalker (assingment) {
  153. let variable = null;
  154. if (assingment instanceof Commands.ArrayIndexAssign) {
  155. const line = expressionWalker(assingment.line);
  156. let arrayClass = "vector";
  157. let column = null;
  158. if (assingment.column) {
  159. arrayClass = "matrix";
  160. column = expressionWalker(assingment.column);
  161. }
  162. variable = [ {
  163. instance: "expression",
  164. type: TYPES.VARIABLE,
  165. class: arrayClass,
  166. column: column,
  167. line: line,
  168. value: assingment.id,
  169. },
  170. ];
  171. } else {
  172. variable = [ { instance: "expression", type: TYPES.VARIABLE, value: assingment.id }, ];
  173. }
  174. const expression = expressionWalker(assingment.expression);
  175. return {
  176. type: "attribution",
  177. variable,
  178. expression,
  179. };
  180. }
  181. /**
  182. * @param {Command} command
  183. * */
  184. function commandWalker (command) {
  185. let parsedCommand = null;
  186. if (command instanceof Commands.FunctionCall) {
  187. parsedCommand = functionCallWalker(command);
  188. } else if (command instanceof Commands.Assign) {
  189. parsedCommand = assignmentWalker(command);
  190. } else if (command instanceof Commands.IfThenElse) {
  191. parsedCommand = ifThenElseWalker(command);
  192. } else if (command instanceof Commands.While) {
  193. parsedCommand = whileWalker(command);
  194. } else if (command instanceof Commands.Break) {
  195. parsedCommand = breakWalker(command);
  196. } else if (command instanceof Commands.Return) {
  197. parsedCommand = returnWalker(command);
  198. } else if (command instanceof Commands.Switch) {
  199. parsedCommand = switchWalker(command);
  200. } else if (command instanceof Commands.For) {
  201. parsedCommand = forWalker(command);
  202. } else {
  203. throw new Error("not implemented");
  204. }
  205. parsedCommand.line = command.sourceInfo.line;
  206. return parsedCommand;
  207. }
  208. /**
  209. * @param {Commands.FunctionCall} functionCall
  210. * */
  211. function functionCallWalker (functionCall) {
  212. let name = functionCall.id;
  213. if (name.indexOf(".") !== -1) {
  214. name = name.split(".")[1];
  215. }
  216. const parameters = functionCall.actualParameters.map(expressionWalker);
  217. if (name === "$write") {
  218. const lastInput = parameters[parameters.length - 1][0];
  219. // if lastInput is an object with value === '\n', newLine is true
  220. const newLine = lastInput.value && lastInput.value.match(/^\n$/) !== null;
  221. const content = newLine ? parameters.slice(0, parameters.length - 1) : parameters;
  222. return {
  223. type: "writer",
  224. newLine,
  225. content,
  226. };
  227. }
  228. if (name === "$read") {
  229. return {
  230. type: "reader",
  231. variable: parameters[0],
  232. };
  233. }
  234. return {
  235. type: "functioncall",
  236. parameters_list: parameters,
  237. name: functionCall.id,
  238. };
  239. }
  240. /**
  241. * @param {Commands.Function} func
  242. * */
  243. function functionWalker (func) {
  244. const funcDeclaration = {
  245. name: func.name,
  246. line: func.sourceInfo.line,
  247. return_type: "",
  248. return_dimensions: 0,
  249. parameters_list: [],
  250. variables_list: [],
  251. commands: [],
  252. };
  253. if (func.returnType instanceof ArrayType) {
  254. funcDeclaration.return_type = func.returnType.innerType.value;
  255. funcDeclaration.return_dimensions = func.returnType.dimensions;
  256. } else {
  257. funcDeclaration.return_type = func.returnType.value;
  258. }
  259. funcDeclaration.parameters_list = func.formalParameters.map(functionParameterWalker);
  260. funcDeclaration.variables_list = func.variablesDeclarations.map(variableDeclarationWalker);
  261. funcDeclaration.commands = func.commands.map(commandWalker);
  262. return funcDeclaration;
  263. }
  264. /**
  265. * @param {Commands.FormalParameter} formalParameter
  266. * */
  267. function functionParameterWalker (formalParameter) {
  268. const variable = {
  269. name: formalParameter.id,
  270. line: formalParameter.sourceInfo.line,
  271. type: "",
  272. rows: 0,
  273. columns: 0,
  274. dimension: 0,
  275. value: 0,
  276. is_const: false,
  277. reference: formalParameter.byRef,
  278. };
  279. if (formalParameter.type instanceof ArrayType) {
  280. variable.type = formalParameter.type.innerType.value;
  281. variable.dimension = formalParameter.type.dimensions;
  282. } else {
  283. variable.type = formalParameter.type.value;
  284. }
  285. return variable;
  286. }
  287. /**
  288. * @param {Commands.Declaration} command
  289. * @param {boolean} global
  290. * */
  291. function variableDeclarationWalker (command, global = false) {
  292. const variable = {
  293. name: command.id,
  294. line: command.sourceInfo.line,
  295. type: "",
  296. rows: 0,
  297. columns: 0,
  298. dimension: 0,
  299. value: 0,
  300. is_const: false,
  301. };
  302. variable.is_const = global && command.isConst;
  303. if (command instanceof Commands.ArrayDeclaration) {
  304. // array
  305. const lines = expressionWalker(command.lines).pop();
  306. variable.type = command.type.innerType.value;
  307. if (command.isVector) {
  308. variable.columns = lines.value;
  309. variable.dimension = 1;
  310. const values = command.initial.value.map((exp) => variableInitialWalker(exp));
  311. variable.value = values;
  312. } else {
  313. const columns = expressionWalker(command.columns).pop();
  314. variable.dimension = 2;
  315. variable.rows = lines.value;
  316. variable.columns = columns.value;
  317. const values = command.initial.value.map((rows) => rows.value.map((exp) => variableInitialWalker(exp)));
  318. variable.value = values;
  319. }
  320. } else {
  321. // atomic
  322. variable.type = command.type.value;
  323. variable.value = variableInitialWalker(command.initial);
  324. }
  325. return variable;
  326. }
  327. /// @param {any} expression
  328. function variableInitialWalker (expression) {
  329. if (expression instanceof Expressions.UnaryApp) {
  330. const left = variableInitialWalker(expression.left);
  331. const opType = getOpType(expression.op);
  332. if (opType !== TYPES.ARITHMETIC) {
  333. throw new Error("invalid variable initial value: " + expression.toString());
  334. }
  335. return `${expression.op.value}${left}`;
  336. } else if (expression instanceof Expressions.BoolLiteral) {
  337. const value = expression.value;
  338. return convertBoolToString(value);
  339. } else if (expression instanceof Literal) {
  340. let value = expression.value;
  341. if (expression.value.toNumber) {
  342. if (Types.REAL.isCompatible(expression.type) && expression.value.decimalPlaces() == 0) {
  343. value = Number(expression.value.toFixed(2));
  344. } else {
  345. value = expression.value.toNumber();
  346. }
  347. }
  348. return value;
  349. }
  350. throw new Error("invalid variable initial value: " + expression.toString());
  351. }
  352. /// @return {[]}
  353. function expressionWalker (expression) {
  354. let result;
  355. if (expression instanceof Expressions.VariableLiteral) {
  356. result = [ { instance: "expression", type: TYPES.VARIABLE, value: expression.id }, ];
  357. } else if (expression instanceof Expressions.FunctionCall) {
  358. const funcObj = {
  359. instance: "expression",
  360. type: TYPES.FUNCTION,
  361. value: expression.id,
  362. };
  363. const paramsList = expression.actualParameters.map((e) => expressionWalker(e));
  364. funcObj.params = paramsList;
  365. result = [funcObj];
  366. } else if (expression instanceof Expressions.UnaryApp) {
  367. const left = expressionWalker(expression.left);
  368. const opType = getOpType(expression.op);
  369. const opValue = translateOp(opType, expression.op);
  370. result = [{ instance: "operator", type: opType, value: opValue }, ...left];
  371. } else if (expression instanceof Expressions.InfixApp) {
  372. const left = expressionWalker(expression.left);
  373. const right = expressionWalker(expression.right);
  374. const opType = getOpType(expression.op);
  375. const opValue = translateOp(opType, expression.op);
  376. result = [
  377. ...left,
  378. { instance: "operator", type: opType, value: opValue },
  379. ...right,
  380. ];
  381. } else if (expression instanceof Expressions.ArrayAccess) {
  382. const line = expressionWalker(expression.line);
  383. let arrayClass = "vector";
  384. let column = null;
  385. if (expression.column) {
  386. arrayClass = "matrix";
  387. column = expressionWalker(expression.column);
  388. }
  389. result = [ {
  390. instance: "expression",
  391. type: TYPES.VARIABLE,
  392. class: arrayClass,
  393. column: column,
  394. line: line,
  395. value: expression.id,
  396. },
  397. ];
  398. } else if (expression instanceof Expressions.BoolLiteral) {
  399. const value = expression.value;
  400. result = [ {
  401. instance: "expression",
  402. class: "simple",
  403. type: TYPES.CONST,
  404. value: convertBoolToString(value),
  405. },
  406. ];
  407. } else {
  408. let value = expression.value;
  409. //x if (expression.value.toNumber)
  410. if (value !== null && value !== undefined && typeof value.toNumber === "function") {
  411. //x if (Types.REAL.isCompatible(expression.type) && expression.value.decimalPlaces() == 0)
  412. if (Types.REAL.isCompatible(expression.type) && value.decimalPlaces() == 0) {
  413. //x value = Number(expression.value.toFixed(2));
  414. value = Number(value.toFixed(2));
  415. } else {
  416. //x value = expression.value.toNumber();
  417. value = value.toNumber();
  418. }
  419. }
  420. result = [ { instance: "expression", class: "simple", type: TYPES.CONST, value: value, }, ];
  421. }
  422. if (expression.parenthesis) return ["(", ...result, ")"];
  423. else return result;
  424. }
  425. export function parseExpression (text) {
  426. const parser = IVProgParser.createParser(text);
  427. const expressionAST = parser.parseExpressionOR();
  428. return expressionWalker(expressionAST);
  429. }
  430. /// @param {string} text
  431. /// @calledby js/util/iassignHelpers.js!setPreviousAlgorithm(code)
  432. export function parseCode (text) {
  433. console.log("js/util/parseFromVisual.js!parseCode(text): can this function be removed? If is it appearing in log, then no...");
  434. //D console.trace();
  435. return parserCodeVisual(text);
  436. }
  437. /// @param {string} text
  438. /// @calledby js/util/iassignHelpers.js!setPreviousAlgorithm(code)
  439. export function parserCodeVisual (text) { // Gleyce; Edilson
  440. console.log("js/util/parseFromVisual.js!parserCodeVisual(text): starting"); //D console.trace();
  441. const parser = IVProgParser.createParser(text, false);
  442. const codeLinesMap = new Map();
  443. const tokens = Array.from(parser.lexer.reset(text));
  444. const tokenStream = [];
  445. for (const token of tokens) {
  446. if (token.type === parser.ruleNames.ERROR) {
  447. return null;
  448. }
  449. if (token.type === parser.ruleNames.COMMENTS) {
  450. for (let i = 0; i <= token.lineBreaks; i++) {
  451. if (codeLinesMap.has(i + token.line))
  452. codeLinesMap.get(i + token.line).push(token);
  453. else codeLinesMap.set(i + token.line, [token]);
  454. }
  455. continue;
  456. }
  457. if (token.type !== parser.ruleNames.WHITESPACE) {
  458. tokenStream.push(token);
  459. }
  460. }
  461. parser.fill(tokenStream);
  462. try {
  463. const program = parser.parseTree();
  464. const globals = program.global.map((decl) => variableDeclarationWalker(decl, true));
  465. const functions = program.functions.map(functionWalker);
  466. //Gleyce start: new code to read IVPH file with comment (//)
  467. const allComments = [];
  468. for (const [line, commentTokens] of codeLinesMap.entries()) {
  469. for (const token of commentTokens) {
  470. const commentText = token.text.replace(/^\/\//, "").trim();
  471. allComments.push({ type: "comment", comment_text: commentText, line: token.line, });
  472. }
  473. }
  474. const astFunctions = program.functions;
  475. functions.forEach((visualFunc, index) => {
  476. const astFunc = astFunctions[index];
  477. const funcStartLine = astFunc.sourceInfo.line;
  478. let funcEndLine;
  479. if (astFunctions[index + 1]) {
  480. funcEndLine = astFunctions[index + 1].sourceInfo.line;
  481. } else {
  482. funcEndLine = Infinity;
  483. }
  484. const funcComments = allComments.filter((comment) => comment.line > funcStartLine && comment.line < funcEndLine);
  485. if (funcComments.length > 0) {
  486. let firstCommandLine = Infinity;
  487. if (visualFunc.commands.length > 0) {
  488. firstCommandLine = visualFunc.commands[0].line;
  489. }
  490. const commentsForVariables = funcComments.filter((c) => c.line < firstCommandLine);
  491. if (commentsForVariables.length > 0) {
  492. const allVariables = [ ...visualFunc.variables_list, ...commentsForVariables, ];
  493. allVariables.sort((a, b) => a.line - b.line);
  494. visualFunc.variables_list = allVariables;
  495. }
  496. if (visualFunc.commands.length > 0) {
  497. const lastCommandLine = visualFunc.commands[visualFunc.commands.length - 1]?.line || funcEndLine;
  498. const commentsForCommands = funcComments.filter((c) => c.line >= firstCommandLine);
  499. visualFunc.commands = associateCommentsToCommands(visualFunc.commands, commentsForCommands, firstCommandLine - 1, lastCommandLine + 100);
  500. }
  501. }
  502. });
  503. //Gleyce end: new code to read IVPH file with comment (//)
  504. return { globals, functions };
  505. } catch (e) {
  506. console.error(e);
  507. return null;
  508. }
  509. } // export function parserCodeVisual(text)
  510. //comments starts (Edilson)
  511. function associateCommentsToCommands (commands, allComments, startLine, endLine) {
  512. const scopeComments = allComments.filter((c) => c.line > startLine && c.line < endLine);
  513. if (scopeComments.length === 0) return commands;
  514. const processedCommands = commands.map((cmd) => {
  515. if (cmd.type === "comment") return cmd;
  516. const processedCmd = { ...cmd };
  517. if (cmd.type === "iftrue") {
  518. if (cmd.ifTrue && cmd.ifTrue.length > 0) {
  519. const ifBlock = cmd.ifTrue;
  520. const blockStart = cmd.line;
  521. const blockEnd = ifBlock[ifBlock.length - 1]?.line || cmd.line;
  522. processedCmd.ifTrue = associateCommentsToCommands(ifBlock, allComments, blockStart, blockEnd);
  523. }
  524. if (cmd.ifFalse && cmd.ifFalse.length > 0) {
  525. const elseBlock = cmd.ifFalse;
  526. const blockStart = cmd.ifTrue && cmd.ifTrue.length > 0 ? cmd.ifTrue[cmd.ifTrue.length - 1]?.line || cmd.line : cmd.line;
  527. const blockEnd = elseBlock[elseBlock.length - 1]?.line || blockStart;
  528. processedCmd.ifFalse = associateCommentsToCommands(elseBlock, allComments, blockStart, blockEnd);
  529. }
  530. }
  531. if (cmd.type === "whiletrue" || cmd.type === "dowhiletrue") {
  532. if (cmd.commands && cmd.commands.length > 0) {
  533. const blockStart = cmd.line;
  534. const blockEnd = cmd.commands[cmd.commands.length - 1]?.line || cmd.line;
  535. processedCmd.commands = associateCommentsToCommands(cmd.commands, allComments, blockStart, blockEnd);
  536. }
  537. }
  538. if (cmd.type === "repeatNtimes") {
  539. if (cmd.commands && cmd.commands.length > 0) {
  540. const blockStart = cmd.line;
  541. const blockEnd = cmd.commands[cmd.commands.length - 1]?.line || cmd.line;
  542. processedCmd.commands = associateCommentsToCommands(cmd.commands, allComments, blockStart, blockEnd);
  543. }
  544. }
  545. if (cmd.type === "switch") {
  546. if (cmd.cases) {
  547. processedCmd.cases = cmd.cases.map((caseObj) => {
  548. if (caseObj.commands && caseObj.commands.length > 0) {
  549. const blockStart = caseObj.line || cmd.line;
  550. const blockEnd = caseObj.commands[caseObj.commands.length - 1]?.line || blockStart;
  551. return {
  552. ...caseObj,
  553. commands: associateCommentsToCommands(caseObj.commands, allComments, blockStart, blockEnd),
  554. };
  555. }
  556. return caseObj;
  557. });
  558. }
  559. }
  560. return processedCmd;
  561. });
  562. const usedCommentLines = new Set();
  563. function collectUsedComments (cmdList) {
  564. cmdList.forEach((cmd) => {
  565. if (cmd.type === "comment") {
  566. usedCommentLines.add(cmd.line);
  567. return;
  568. }
  569. if (cmd.type === "iftrue") {
  570. if (cmd.ifTrue) collectUsedComments(cmd.ifTrue);
  571. if (cmd.ifFalse) collectUsedComments(cmd.ifFalse);
  572. }
  573. if ((cmd.type === "whiletrue" || cmd.type === "dowhiletrue" || cmd.type === "repeatNtimes") && cmd.commands) {
  574. collectUsedComments(cmd.commands);
  575. }
  576. if (cmd.type === "switch" && cmd.cases) {
  577. cmd.cases.forEach((c) => {
  578. if (c.commands) collectUsedComments(c.commands);
  579. });
  580. }
  581. });
  582. }
  583. collectUsedComments(processedCommands);
  584. const availableComments = scopeComments.filter((c) => !usedCommentLines.has(c.line));
  585. const merged = [...processedCommands, ...availableComments].sort((a, b) => a.line - b.line);
  586. return associateInlineComments(merged, allComments);
  587. }
  588. function associateInlineComments (commands, allComments) {
  589. if (!allComments || allComments.length === 0) return commands;
  590. const commentsByLine = new Map();
  591. allComments.forEach((comment) => {
  592. if (!commentsByLine.has(comment.line)) {
  593. commentsByLine.set(comment.line, []);
  594. }
  595. commentsByLine.get(comment.line).push(comment);
  596. });
  597. const inlineCommentLines = new Set();
  598. function processCommands (cmdList) {
  599. return cmdList.map((cmd) => {
  600. if (cmd.type === "comment") return cmd;
  601. const processedCmd = { ...cmd };
  602. if (cmd.line && commentsByLine.has(cmd.line)) {
  603. const commentsOnLine = commentsByLine.get(cmd.line);
  604. const availableComment = commentsOnLine.find((c) => !inlineCommentLines.has(c.line));
  605. if (availableComment) {
  606. processedCmd.inlineComment = availableComment.comment_text;
  607. inlineCommentLines.add(cmd.line);
  608. }
  609. }
  610. if (cmd.type === "iftrue") {
  611. if (cmd.ifTrue) processedCmd.ifTrue = processCommands(cmd.ifTrue);
  612. if (cmd.ifFalse) processedCmd.ifFalse = processCommands(cmd.ifFalse);
  613. }
  614. if ((cmd.type === "whiletrue" || cmd.type === "dowhiletrue" || cmd.type === "repeatNtimes") && cmd.commands) {
  615. processedCmd.commands = processCommands(cmd.commands);
  616. }
  617. if (cmd.type === "switch" && cmd.cases) {
  618. processedCmd.cases = cmd.cases.map((caseObj) => ({
  619. ...caseObj,
  620. commands: caseObj.commands ? processCommands(caseObj.commands) : [],
  621. }));
  622. }
  623. return processedCmd;
  624. });
  625. } // function processCommands(cmdList)
  626. const processedCommands = processCommands(commands);
  627. function filterInlineComments (cmdList) {
  628. return cmdList.filter((cmd) => {
  629. if (cmd.type === "comment" && inlineCommentLines.has(cmd.line)) {
  630. return false;
  631. }
  632. if (cmd.type === "iftrue") {
  633. if (cmd.ifTrue) cmd.ifTrue = filterInlineComments(cmd.ifTrue);
  634. if (cmd.ifFalse) cmd.ifFalse = filterInlineComments(cmd.ifFalse);
  635. }
  636. if ((cmd.type === "whiletrue" || cmd.type === "dowhiletrue" || cmd.type === "repeatNtimes") && cmd.commands) {
  637. cmd.commands = filterInlineComments(cmd.commands);
  638. }
  639. if (cmd.type === "switch" && cmd.cases) {
  640. cmd.cases = cmd.cases.map((caseObj) => ({
  641. ...caseObj,
  642. commands: caseObj.commands ? filterInlineComments(caseObj.commands) : [],
  643. }));
  644. }
  645. return true;
  646. });
  647. }
  648. return filterInlineComments(processedCommands);
  649. } // function associateInlineComments(commands, allComments)
  650. //comments end (Edilson)