codeParser.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  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"
  4. import * as Models from '../visualUI/ivprog_elements';
  5. import { LocalizedStrings } from './../services/localizedStringsService';
  6. import * as VariableValueMenuManagement from '../visualUI/commands/variable_value_menu';
  7. import * as CodeParser from '../visualUI/commands/generic_expression';
  8. function parseBoolean (var_value, dimensions) {
  9. if (dimensions == 0)
  10. return var_value == LocalizedStrings.getUI("logic_value_true");
  11. if (dimensions == 1) {
  12. var final_array = [];
  13. var_value.forEach(function(el) {
  14. final_array.push(el == LocalizedStrings.getUI("logic_value_true"));
  15. });
  16. return final_array;
  17. }
  18. if (dimensions == 2) {
  19. var final_array = [];
  20. var_value.forEach(function(row) {
  21. var temp = [];
  22. row.forEach(function(el) {
  23. temp.push(el == LocalizedStrings.getUI("logic_value_true"));
  24. });
  25. final_array.push(temp);
  26. });
  27. return final_array;
  28. }
  29. }
  30. function parseGlobal (global_obj) {
  31. var new_global = new Models.Variable(global_obj.type, global_obj.name, global_obj.value);
  32. new_global.is_constant = global_obj.is_const;
  33. new_global.columns = global_obj.columns;
  34. new_global.dimensions = global_obj.dimension;
  35. new_global.rows = global_obj.rows;
  36. if (global_obj.type == "boolean")
  37. new_global.value = parseBoolean(global_obj.value, global_obj.dimension);
  38. window.program_obj.addGlobal(new_global);
  39. }
  40. function parseParameter (parameter_obj) {
  41. const new_parameter = new Models.Variable(
  42. parameter_obj.type,
  43. parameter_obj.name,
  44. null,
  45. parameter_obj.dimension,
  46. parameter_obj.is_const,
  47. parameter_obj.rows,
  48. parameter_obj.columns,
  49. parameter_obj.reference
  50. );
  51. new_parameter.value = parameter_obj.value;
  52. if (parameter_obj.type == "boolean" && parameter_obj.value)
  53. new_parameter.value = parseBoolean(parameter_obj.value, parameter_obj.dimension);
  54. return new_parameter;
  55. }
  56. function parseFunction (function_obj) {
  57. const new_function = new Models.Function(function_obj.name, function_obj.return_type, function_obj.return_dimensions, [], false, false, []);
  58. if (!new_function.name) {
  59. new_function.name = LocalizedStrings.getUI("start");
  60. new_function.is_main = true;
  61. }
  62. if (function_obj.parameters_list) {
  63. function_obj.parameters_list.forEach(function(el) {
  64. new_function.parameters_list.push(parseParameter(el));
  65. });
  66. }
  67. if (function_obj.variables_list) {
  68. function_obj.variables_list.forEach(function(el) {
  69. new_function.variables_list.push(parseParameter(el));
  70. });
  71. }
  72. window.program_obj.addFunction(new_function);
  73. }
  74. // Auxiliary to debug
  75. function printCommandText (code) {
  76. if (code) {
  77. //if (code.commands) return "commands.length=" + code.commands.length; else return "Object.commands <empty>";
  78. var aux = "";
  79. if (code.globals) aux = "#globals=" + code.globals.length;
  80. else aux = "#globals=0";
  81. if (code.functions) aux += ", #functions=" + code.functions.length;
  82. else aux += ", #functions=0";
  83. return aux;
  84. }
  85. return "Object <empty>";
  86. }
  87. // @calledby Recursive, "parserCodeVisual(.)": preparedFunction.commands = parseCommands(rawFunction.commands, preparedFunction);
  88. // @calledby Generic parser, "parseCommands(.)": temp.push(parseCommands(command, function_obj));
  89. // @calledby Each parser command as "function parseIfTrue(command,function_obj)": "ifTrueBlock=parseCommands(command.ifTrue,function_obj)" and "ifFalseBlock=parseCommands(command.ifFalse,function_obj)"
  90. // Sequence calls:
  91. // parserCodeVisual here
  92. // js/util/iassignHelpers.js!setPreviousAlgorithm(code): var result = parserCodeVisual(code_obj);
  93. // js/iassign-integration-functions.js!prepareActivityToStudent(ilm_cont, ignore_logs = false): var result = ivprogCore.setPreviousAlgorithm(ilm_cont);
  94. // js/iassign-integration-functions.js!getiLMContent(): prepareActivityToStudent(data);
  95. export function parserCodeVisual (code_obj = null) {
  96. console.log("js/util/codeParser.js!parserCodeVisual(.): code_obj has " + printCommandText(code_obj)); // JSON.stringify(code_obj));
  97. if (!code_obj || code_obj===null) {
  98. // Avoid severe error! parserCodeVisual@http://localhost/ivprog/ivprogh/js/main.ecdd914f315cb1bf2925.js:11054:5...
  99. console.log("js/util/codeParser.js!parserCodeVisual(.): code_obj is empty: " + code_obj); // JSON.stringify(code_obj));
  100. //D console.trace();
  101. return null;
  102. }
  103. // console.trace();
  104. window.conteudo = code_obj;
  105. // Globals:
  106. window.program_obj.globals = [];
  107. code_obj.globals.forEach(parseGlobal);
  108. // Functions:
  109. window.program_obj.functions = [];
  110. code_obj.functions.forEach(parseFunction);
  111. // Commands:
  112. window.program_obj.functions.forEach(function (preparedFunction) {
  113. code_obj.functions.forEach(function (rawFunction) {
  114. if (preparedFunction.name == rawFunction.name || (!rawFunction.name && preparedFunction.name == LocalizedStrings.getUI("start"))) {
  115. //comments: starts
  116. if (rawFunction.variables_list && rawFunction.variables_list.length > 0) {
  117. const newVariablesList = [];
  118. rawFunction.variables_list.forEach(function(varItem) {
  119. if (varItem.type === "comment") {
  120. // This is a comment - create "Comment"
  121. const comment = parseComment(varItem, preparedFunction);
  122. if (comment) {
  123. newVariablesList.push(comment);
  124. }
  125. } else {
  126. // This is a comment - get existing variable
  127. const existingVar = preparedFunction.variables_list.find((v) => v.name === varItem.name);
  128. if (existingVar) {
  129. newVariablesList.push(existingVar);
  130. }
  131. }
  132. });
  133. preparedFunction.variables_list = newVariablesList;
  134. } //comments: end
  135. preparedFunction.commands = parseCommands(rawFunction.commands, preparedFunction);
  136. }
  137. });
  138. });
  139. console.log("codeParser.js!parserCodeVisual(.): finished!");
  140. return true; // set to js/util/iassignHelpers.js!setPreviousAlgorithm(code) success
  141. }
  142. function parseCommands (commands_block, function_obj) {
  143. console.log("codeParser.js!parseCommands(.): commands_block=" + printCommandText(commands_block)); // "JSON.stringify(commands_block));" is infinity recursive...
  144. //D console.trace();
  145. if (Array.isArray(commands_block)) {
  146. var temp = [];
  147. commands_block.forEach(function (command) {
  148. //comments: starts
  149. var parsedCommand = parseCommands(command, function_obj);
  150. if (Array.isArray(parsedCommand)) {
  151. parsedCommand.forEach(function (decl) {
  152. temp.push(decl);
  153. });
  154. } else if (parsedCommand !== null) {
  155. if (command.inlineComment && parsedCommand.type !== "comment") {
  156. parsedCommand.inlineComment = command.inlineComment;
  157. }
  158. temp.push(parsedCommand);
  159. }
  160. //comments: end
  161. });
  162. return temp;
  163. }
  164. else { // if (Array.isArray(commands_block))
  165. var parsedCmd = null;
  166. switch (commands_block.type) {
  167. case Models.COMMAND_TYPES.reader:
  168. parsedCmd = parseReader(commands_block, function_obj);
  169. break;
  170. case Models.COMMAND_TYPES.return:
  171. parsedCmd = parseReturn(commands_block, function_obj);
  172. break;
  173. case Models.COMMAND_TYPES.writer:
  174. parsedCmd = parseWriter(commands_block, function_obj);
  175. break;
  176. case Models.COMMAND_TYPES.break:
  177. parsedCmd = parseBreak(commands_block, function_obj);
  178. break;
  179. case Models.COMMAND_TYPES.comment:
  180. parsedCmd = parseComment(commands_block, function_obj);
  181. break;
  182. case Models.COMMAND_TYPES.attribution:
  183. parsedCmd = parseAttribution(commands_block, function_obj);
  184. break;
  185. case Models.COMMAND_TYPES.functioncall:
  186. parsedCmd = parseFunctionCall(commands_block, function_obj);
  187. break;
  188. case Models.COMMAND_TYPES.iftrue:
  189. parsedCmd = parseIfTrue(commands_block, function_obj);
  190. break;
  191. case Models.COMMAND_TYPES.repeatNtimes:
  192. parsedCmd = parseRepeatNTimes(commands_block, function_obj);
  193. break;
  194. case Models.COMMAND_TYPES.whiletrue:
  195. parsedCmd = parseWhileTrue(commands_block, function_obj);
  196. break;
  197. case Models.COMMAND_TYPES.dowhiletrue:
  198. parsedCmd = parseDoWhileTrue(commands_block, function_obj);
  199. break;
  200. case Models.COMMAND_TYPES.switch:
  201. parsedCmd = parseSwitch(commands_block, function_obj);
  202. break;
  203. } // switch (commands_block.type)
  204. //comments: preserves "in-line" comments
  205. if (parsedCmd && commands_block.inlineComment) {
  206. parsedCmd.inlineComment = commands_block.inlineComment;
  207. }
  208. return parsedCmd;
  209. } // else if (Array.isArray(commands_block))
  210. } // function parseCommands(commands_block, function_obj)
  211. function parseReader (command, function_obj) {
  212. var temp = CodeParser.expressionParserCodeVisual(command.variable, function_obj);
  213. if (Array.isArray(temp) && temp[0]) temp = temp[0];
  214. return new Models.Reader(temp);
  215. }
  216. function parseReturn (command, function_obj) {
  217. var temp = CodeParser.expressionParserCodeVisual(command.expression, function_obj);
  218. return new Models.Return(temp);
  219. }
  220. // Generate command "write(...)"
  221. // @calls js/visualUI/commands/attribution.js: renderExpression
  222. function parseWriter (command, function_obj) {
  223. //D var len_cmd = command.content.length; //leo
  224. //D var str = ""; // "#command.content=" + len_cmd + "\n"; //leo
  225. //D for (var i=0; i<len_cmd; i++) str += JSON.stringify(command.content[i]) + "; "; // "; " + command.content[i];
  226. //D console.log("./ivprog/js/util/codeParser.js: parseWriter(.): command=" + JSON.stringify(command)) // + "\nfunction_obj=||" + JSON.stringify(function_obj) + "||\n" + str); //leo
  227. console.log("./ivprog/js/util/codeParser.js: parseWriter(.): command=" + JSON.stringify(command));
  228. //#command=" + (command ? command.length : "<>") ); //leo + ";
  229. //leo
  230. //TODO It is missing to implement the visualUI construtor to "write_separator" in 'getVariable(.)'
  231. //TODO Incomplete solution: I change "Models.EXPRESSION_TYPES.write_sep" to "Models.ARITHMETIC_TYPES.plus" in ./ivprog/js/visualUI/commands/generic_expression.js
  232. //TODO See ./ivprog/js/visualUI/commands/generic_expression.js : expressionParserCodeVisual(.) : missing treat to 'write_sep' in 'getVariable(.)' final command
  233. // ATTENTION must pass all the vector to work with several variables in "write(.)"
  234. var temp = CodeParser.expressionParserCodeVisual(command.content, function_obj); // provide HTML elements
  235. //0 temp = CodeParser.expressionParserCodeVisual(command.content[0], function_obj);
  236. //D console.log("./ivprog/js/util/codeParser.js: parseWriter(.): #temp=" + temp.length + "; type=" + temp.type + ": temp=" + JSON.stringify(temp));
  237. return new Models.Writer(temp, command.newLine);
  238. }
  239. function parseBreak (command, function_obj) {
  240. return new Models.Break();
  241. }
  242. function parseAttribution (command, function_obj) {
  243. var variable = CodeParser.expressionParserCodeVisual(command.variable, function_obj);
  244. var expression = CodeParser.expressionParserCodeVisual(command.expression, function_obj);
  245. if (Array.isArray(variable)) variable = variable[0];
  246. return new Models.Attribution(variable, expression);
  247. }
  248. // By Gleyce 2025/06/23; Edilson 2026/01/30
  249. function parseComment (command, function_obj) {
  250. var text = command.comment || command.comment_text || command.value || command.text || "";
  251. if (!text) {
  252. console.warn("Comment without text!", command);
  253. return null;
  254. }
  255. var commentTextMenu = new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_value, text, null, null, false);
  256. var commentObj = new Models.Comment(commentTextMenu);
  257. commentObj.comment = text;
  258. commentObj.value = text;
  259. commentObj._text = text;
  260. commentObj.comment_text = commentTextMenu;
  261. return commentObj;
  262. }
  263. function parseFunctionCall (command, function_obj) {
  264. var parameters = [];
  265. if (command.parameters_list) {
  266. command.parameters_list.forEach(function(el) {
  267. var temp = CodeParser.expressionParserCodeVisual(el, function_obj);
  268. if (temp.content === 0) temp.content = "0";
  269. parameters.push(temp[0]);
  270. });
  271. }
  272. var function_called = CodeParser.searchFunction(command.name);
  273. var temp = new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, null, null, null, false);
  274. temp.function_called = function_called;
  275. temp.parameters_list = parameters;
  276. return new Models.FunctionCall(temp, null);
  277. }
  278. function parseIfTrue (command, function_obj) {
  279. var expression = CodeParser.expressionParserCodeVisual(command.expression, function_obj);
  280. var ifTrueBlock = parseCommands(command.ifTrue, function_obj);
  281. var ifFalseBlock = parseCommands(command.ifFalse, function_obj);
  282. return new Models.IfTrue(expression, ifTrueBlock, ifFalseBlock);
  283. }
  284. function parseRepeatNTimes (command, function_obj) {
  285. //D console.log("codeParser.js!parseRepeatNTimes(.): command=" + JSON.stringify(command));
  286. console.log("codeParser.js!parseRepeatNTimes(.): command=" + command);
  287. var var_attribution = CodeParser.expressionParserCodeVisual(command.var_attribution, function_obj);
  288. var_attribution = var_attribution[0];
  289. var expression1 = CodeParser.expressionParserCodeVisual(command.var_initial, function_obj);
  290. expression1 = expression1[0];
  291. var expression2 = CodeParser.expressionParserCodeVisual(command.condition, function_obj);
  292. if (expression2[0].item == 'minus') {
  293. expression2 = expression2[1];
  294. expression2.content *= -1;
  295. }
  296. else expression2 = expression2[0];
  297. var var_step = CodeParser.expressionParserCodeVisual(command.step_expression, function_obj);
  298. var commands_block = parseCommands(command.commands, function_obj);
  299. var operator = command.step_expression[0].value == '+' ? Models.ARITHMETIC_TYPES.plus : Models.ARITHMETIC_TYPES.minus;
  300. var expression3 = new Models.ExpressionElement(Models.EXPRESSION_ELEMENTS.exp_op_exp, [null, operator, var_step[1]]);
  301. console.log("codeParser.js!parseRepeatNTimes(.): expression3=" + expression3);
  302. return new Models.RepeatNTimes(
  303. var_attribution,
  304. new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_variable, null, null, null, false),
  305. expression1,
  306. expression2,
  307. expression3,
  308. commands_block);
  309. } // function parseRepeatNTimes(command, function_obj)
  310. function parseWhileTrue (command, function_obj) {
  311. var expression = CodeParser.expressionParserCodeVisual(command.expression, function_obj);
  312. var commands = parseCommands(command.commands, function_obj);
  313. return new Models.WhileTrue(expression, commands);
  314. }
  315. function parseDoWhileTrue (command, function_obj) {
  316. var expression = CodeParser.expressionParserCodeVisual(command.expression, function_obj);
  317. var commands = parseCommands(command.commands, function_obj);
  318. return new Models.DoWhileTrue(expression, commands);
  319. }
  320. function parseSwitch (command, function_obj) {
  321. var expression = CodeParser.expressionParserCodeVisual(command.expression, function_obj);
  322. var sc = [];
  323. if (command.cases) {
  324. command.cases.forEach(function (case_el) {
  325. var temp_exp = CodeParser.expressionParserCodeVisual(case_el.expression, function_obj);
  326. var temp_commands = parseCommands(case_el.commands, function_obj);
  327. var temp_case = new Models.SwitchCase(temp_exp[0], temp_commands);
  328. sc.push(temp_case);
  329. })
  330. }
  331. return new Models.Switch(expression[0], sc);
  332. }