parseFromVisual.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. import { IVProgParser } from "../ast/ivprogParser";
  2. import * as Expressions from "../ast/expressions";
  3. import { Types } from "../typeSystem/types";
  4. import { convertBoolToString } from "../typeSystem/parsers";
  5. import * as Commands from "../ast/commands";
  6. import { ArrayType } from "../typeSystem/array_type";
  7. import { Literal } from "../ast/expressions/literal";
  8. const TYPES = {
  9. VARIABLE: "var",
  10. CONST: "const",
  11. FUNCTION: "function",
  12. RELATIONAL: "relational",
  13. LOGIC: "logic",
  14. ARITHMETIC: "arithmetic",
  15. };
  16. function translateOp (type, op) {
  17. switch (type) {
  18. case TYPES.ARITHMETIC:
  19. return op.value;
  20. case TYPES.RELATIONAL:
  21. return op.value;
  22. case TYPES.LOGIC: {
  23. if (op.ord === 11) {
  24. return "and";
  25. } else if (op.ord === 12) {
  26. return "or";
  27. } else {
  28. return "not";
  29. }
  30. }
  31. }
  32. }
  33. function getOpType (op) {
  34. switch (op.ord) {
  35. case 0:
  36. case 1:
  37. case 2:
  38. case 3:
  39. case 4:
  40. return TYPES.ARITHMETIC;
  41. case 5:
  42. case 6:
  43. case 7:
  44. case 8:
  45. case 9:
  46. case 10:
  47. return TYPES.RELATIONAL;
  48. default:
  49. return TYPES.LOGIC;
  50. }
  51. }
  52. /**
  53. * @param {Commands.Case} switchCase
  54. * */
  55. function switchCaseWalker (switchCase) {
  56. const commands = switchCase.commands.map(commandWalker);
  57. const expression = switchCase.isDefault
  58. ? null
  59. : expressionWalker(switchCase.expression);
  60. return {
  61. type: "switchcase",
  62. line: switchCase.sourceInfo.line,
  63. expression,
  64. commands,
  65. };
  66. }
  67. /**
  68. * @param {Commands.Switch} switchCommand
  69. * */
  70. function switchWalker (switchCommand) {
  71. const expression = expressionWalker(switchCommand.expression);
  72. const cases = switchCommand.cases.map(switchCaseWalker);
  73. return {
  74. type: "switch",
  75. expression,
  76. cases,
  77. };
  78. }
  79. /**
  80. * @param {Commands.Return} returnCommand
  81. * */
  82. function returnWalker (returnCommand) {
  83. const expression = expressionWalker(returnCommand.expression);
  84. return {
  85. type: "return",
  86. expression,
  87. };
  88. }
  89. function breakWalker (_) {
  90. return { type: "break" };
  91. }
  92. /**
  93. * @param {Commands.For} forLoop
  94. * */
  95. function forWalker (forLoop) {
  96. const var_attribution = expressionWalker(forLoop.for_id);
  97. const var_initial = expressionWalker(forLoop.for_from);
  98. const condition = expressionWalker(forLoop.for_to);
  99. const defaultStep = [{ instance: "operator", type: TYPES.ARITHMETIC, value: '+' }, {
  100. instance: "expression",
  101. class: "simple",
  102. type: TYPES.CONST,
  103. value: 1,
  104. }]
  105. const step_expression = forLoop.for_pass
  106. ? expressionWalker(forLoop.for_pass)
  107. : defaultStep;
  108. const commands = forLoop.commands.map(commandWalker);
  109. return {
  110. type: "repeatNtimes",
  111. var_attribution,
  112. var_initial,
  113. condition,
  114. step_expression,
  115. commands,
  116. };
  117. }
  118. /**
  119. * @param {Commands.While} whileLoop
  120. * */
  121. function whileWalker (whileLoop) {
  122. const expression = expressionWalker(whileLoop.expression);
  123. const commands = whileLoop.commands.map(commandWalker);
  124. let type = whileLoop.testFirst ? "whiletrue" : "dowhiletrue";
  125. return {
  126. type,
  127. expression,
  128. commands,
  129. };
  130. }
  131. /**
  132. * @param {Commands.IfThenElse} ifthenelse
  133. * */
  134. function ifThenElseWalker (ifthenelse) {
  135. //ifthenelse.
  136. const expression = expressionWalker(ifthenelse.condition);
  137. const ifTrue = ifthenelse.ifTrue.commands.map(commandWalker);
  138. let ifFalse = [];
  139. if (ifthenelse.ifFalse) {
  140. if (ifthenelse.ifFalse instanceof Commands.CommandBlock) {
  141. ifFalse = ifthenelse.ifFalse.commands.map(commandWalker);
  142. } else {
  143. ifFalse = [ifThenElseWalker(ifthenelse.ifFalse)];
  144. }
  145. }
  146. return {
  147. type: "iftrue",
  148. expression,
  149. ifTrue,
  150. ifFalse,
  151. };
  152. }
  153. /**
  154. * @param {Commands.Assign} assingment
  155. * */
  156. function assignmentWalker (assingment) {
  157. let variable = null;
  158. if (assingment instanceof Commands.ArrayIndexAssign) {
  159. const line = expressionWalker(assingment.line);
  160. let arrayClass = "vector";
  161. let column = null;
  162. if (assingment.column) {
  163. arrayClass = "matrix";
  164. column = expressionWalker(assingment.column);
  165. }
  166. variable = [
  167. {
  168. instance: "expression",
  169. type: TYPES.VARIABLE,
  170. class: arrayClass,
  171. column: column,
  172. line: line,
  173. value: assingment.id,
  174. },
  175. ];
  176. } else {
  177. variable = [
  178. { instance: "expression", type: TYPES.VARIABLE, value: assingment.id },
  179. ];
  180. }
  181. const expression = expressionWalker(assingment.expression);
  182. return {
  183. type: "attribution",
  184. variable,
  185. expression,
  186. };
  187. }
  188. /**
  189. * @param {Command} command
  190. * */
  191. function commandWalker (command) {
  192. let parsedCommand = null;
  193. if (command instanceof Commands.FunctionCall) {
  194. parsedCommand = functionCallWalker(command);
  195. } else if (command instanceof Commands.Assign) {
  196. parsedCommand = assignmentWalker(command);
  197. } else if (command instanceof Commands.IfThenElse) {
  198. parsedCommand = ifThenElseWalker(command);
  199. } else if (command instanceof Commands.While) {
  200. parsedCommand = whileWalker(command);
  201. } else if (command instanceof Commands.Break) {
  202. parsedCommand = breakWalker(command);
  203. } else if (command instanceof Commands.Return) {
  204. parsedCommand = returnWalker(command);
  205. } else if (command instanceof Commands.Switch) {
  206. parsedCommand = switchWalker(command);
  207. } else if (command instanceof Commands.For) {
  208. parsedCommand = forWalker(command);
  209. } else {
  210. throw new Error("not implemented");
  211. }
  212. parsedCommand.line = command.sourceInfo.line;
  213. return parsedCommand;
  214. }
  215. /**
  216. * @param {Commands.FunctionCall} functionCall
  217. * */
  218. function functionCallWalker (functionCall) {
  219. let name = functionCall.id;
  220. if (name.indexOf(".") !== -1) {
  221. name = name.split(".")[1];
  222. }
  223. const parameters = functionCall.actualParameters.map(expressionWalker);
  224. if (name === "$write") {
  225. const lastInput = parameters[parameters.length - 1][0];
  226. // if lastInput is an object with value === '\n', newLine is true
  227. const newLine = lastInput.value && lastInput.value.match && lastInput.value.match(/^\n$/) !== null;
  228. let content = newLine
  229. ? parameters.slice(0, parameters.length - 1)
  230. : parameters;
  231. console.log("cont");
  232. console.log([].concat(...parameters));
  233. content = [].concat(...content);
  234. return {
  235. type: "writer",
  236. newLine,
  237. content,
  238. };
  239. }
  240. if (name === "$read") {
  241. return {
  242. type: "reader",
  243. variable: parameters[0],
  244. };
  245. }
  246. return {
  247. type: "functioncall",
  248. parameters_list: parameters,
  249. name: functionCall.id,
  250. };
  251. }
  252. /**
  253. * @param {Commands.Function} func
  254. * */
  255. function functionWalker (func) {
  256. const funcDeclaration = {
  257. name: func.name,
  258. line: func.sourceInfo.line,
  259. return_type: "",
  260. return_dimensions: 0,
  261. parameters_list: [],
  262. variables_list: [],
  263. commands: [],
  264. };
  265. if (func.returnType instanceof ArrayType) {
  266. funcDeclaration.return_type = func.returnType.innerType.value;
  267. funcDeclaration.return_dimensions = func.returnType.dimensions;
  268. } else {
  269. funcDeclaration.return_type = func.returnType.value;
  270. }
  271. funcDeclaration.parameters_list = func.formalParameters.map(
  272. functionParameterWalker
  273. );
  274. funcDeclaration.variables_list = func.variablesDeclarations.map(
  275. variableDeclarationWalker
  276. );
  277. funcDeclaration.commands = func.commands.map(commandWalker);
  278. return funcDeclaration;
  279. }
  280. /**
  281. * @param {Commands.FormalParameter} formalParameter
  282. * */
  283. function functionParameterWalker (formalParameter) {
  284. const variable = {
  285. name: formalParameter.id,
  286. line: formalParameter.sourceInfo.line,
  287. type: "",
  288. rows: 0,
  289. columns: 0,
  290. dimension: 0,
  291. value: 0,
  292. is_const: false,
  293. reference: formalParameter.byRef,
  294. };
  295. if (formalParameter.type instanceof ArrayType) {
  296. variable.type = formalParameter.type.innerType.value;
  297. variable.dimension = formalParameter.type.dimensions;
  298. } else {
  299. variable.type = formalParameter.type.value;
  300. }
  301. return variable;
  302. }
  303. /**
  304. * @param {Commands.Declaration} command
  305. * @param {boolean} global
  306. * */
  307. function variableDeclarationWalker (command, global = false) {
  308. const variable = {
  309. name: command.id,
  310. line: command.sourceInfo.line,
  311. type: "",
  312. rows: 0,
  313. columns: 0,
  314. dimension: 0,
  315. value: 0,
  316. is_const: false,
  317. };
  318. variable.is_const = global && command.isConst;
  319. if (command instanceof Commands.ArrayDeclaration) {
  320. // array
  321. const lines = expressionWalker(command.lines).pop();
  322. variable.type = command.type.innerType.value;
  323. if (command.isVector) {
  324. variable.columns = lines.value;
  325. variable.dimension = 1;
  326. const values = command.initial.value.map((exp) =>
  327. variableInitialWalker(exp)
  328. );
  329. variable.value = values;
  330. } else {
  331. const columns = expressionWalker(command.columns).pop();
  332. variable.dimension = 2;
  333. variable.rows = lines.value;
  334. variable.columns = columns.value;
  335. const values = command.initial.value.map((rows) =>
  336. rows.value.map((exp) => variableInitialWalker(exp))
  337. );
  338. variable.value = values;
  339. }
  340. } else {
  341. // atomic
  342. variable.type = command.type.value;
  343. variable.value = variableInitialWalker(command.initial);
  344. }
  345. return variable;
  346. }
  347. /**
  348. * @param {any} expression
  349. * */
  350. function variableInitialWalker (expression) {
  351. if (expression instanceof Expressions.UnaryApp) {
  352. const left = variableInitialWalker(expression.left);
  353. const opType = getOpType(expression.op);
  354. if (opType !== TYPES.ARITHMETIC) {
  355. throw new Error(
  356. "invalid variable initial value: " + expression.toString()
  357. );
  358. }
  359. return `${expression.op.value}${left}`;
  360. } else if (expression instanceof Expressions.BoolLiteral) {
  361. const value = expression.value;
  362. return convertBoolToString(value);
  363. } else if (expression instanceof Literal) {
  364. let value = expression.value;
  365. if (expression.value.toNumber) {
  366. if (
  367. Types.REAL.isCompatible(expression.type) &&
  368. expression.value.decimalPlaces() == 0
  369. ) {
  370. value = Number(expression.value.toFixed(2));
  371. } else {
  372. value = expression.value.toNumber();
  373. }
  374. }
  375. return value;
  376. }
  377. throw new Error("invalid variable initial value: " + expression.toString());
  378. }
  379. /**
  380. *
  381. * @return {[]}
  382. **/
  383. function expressionWalker (expression) {
  384. let result;
  385. if (expression instanceof Expressions.VariableLiteral) {
  386. result = [
  387. { instance: "expression", type: TYPES.VARIABLE, value: expression.id },
  388. ];
  389. } else if (expression instanceof Expressions.FunctionCall) {
  390. const funcObj = {
  391. instance: "expression",
  392. type: TYPES.FUNCTION,
  393. value: expression.id,
  394. };
  395. const paramsList = expression.actualParameters.map((e) =>
  396. expressionWalker(e)
  397. );
  398. //const params = Array.prototype.concat.apply([], paramsList);
  399. funcObj.params = paramsList;
  400. result = [funcObj];
  401. } else if (expression instanceof Expressions.UnaryApp) {
  402. const left = expressionWalker(expression.left);
  403. const opType = getOpType(expression.op);
  404. const opValue = translateOp(opType, expression.op);
  405. result = [{ instance: "operator", type: opType, value: opValue }, ...left];
  406. } else if (expression instanceof Expressions.InfixApp) {
  407. const left = expressionWalker(expression.left);
  408. const right = expressionWalker(expression.right);
  409. const opType = getOpType(expression.op);
  410. const opValue = translateOp(opType, expression.op);
  411. result = [
  412. ...left,
  413. { instance: "operator", type: opType, value: opValue },
  414. ...right,
  415. ];
  416. } else if (expression instanceof Expressions.ArrayAccess) {
  417. const line = expressionWalker(expression.line);
  418. let arrayClass = "vector";
  419. let column = null;
  420. if (expression.column) {
  421. arrayClass = "matrix";
  422. column = expressionWalker(expression.column);
  423. }
  424. result = [
  425. {
  426. instance: "expression",
  427. type: TYPES.VARIABLE,
  428. class: arrayClass,
  429. column: column,
  430. line: line,
  431. value: expression.id,
  432. },
  433. ];
  434. } else if (expression instanceof Expressions.BoolLiteral) {
  435. const value = expression.value;
  436. result = [
  437. {
  438. instance: "expression",
  439. class: "simple",
  440. type: TYPES.CONST,
  441. value: convertBoolToString(value),
  442. },
  443. ];
  444. } else {
  445. let value = expression.value;
  446. if (expression.value.toNumber) {
  447. if (
  448. Types.REAL.isCompatible(expression.type) &&
  449. expression.value.decimalPlaces() == 0
  450. ) {
  451. value = Number(expression.value.toFixed(2));
  452. } else {
  453. value = expression.value.toNumber();
  454. }
  455. }
  456. result = [
  457. {
  458. instance: "expression",
  459. class: "simple",
  460. type: TYPES.CONST,
  461. value: value,
  462. },
  463. ];
  464. }
  465. if (expression.parenthesis) return ["(", ...result, ")"];
  466. else return result;
  467. }
  468. export function parseExpression (text) {
  469. const parser = IVProgParser.createParser(text);
  470. const expressionAST = parser.parseExpressionOR();
  471. return expressionWalker(expressionAST);
  472. }
  473. /**
  474. * @param {string} text
  475. * */
  476. export function parseCode (text) {
  477. console.log(text);
  478. const parser = IVProgParser.createParser(text, false);
  479. const codeLinesMap = new Map();
  480. const tokens = Array.from(parser.lexer.reset(text));
  481. const tokenStream = [];
  482. for (const token of tokens) {
  483. if (token.type === parser.ruleNames.ERROR) {
  484. return null;
  485. }
  486. if (token.type === parser.ruleNames.COMMENTS) {
  487. for (let i = 0; i <= token.lineBreaks; i++) {
  488. if (codeLinesMap.has(i + token.line))
  489. codeLinesMap.get(i + token.line).push(token);
  490. else codeLinesMap.set(i + token.line, [token]);
  491. }
  492. continue;
  493. }
  494. if (token.type !== parser.ruleNames.WHITESPACE) {
  495. tokenStream.push(token);
  496. }
  497. }
  498. parser.fill(tokenStream);
  499. try {
  500. const program = parser.parseTree();
  501. const globals = program.global.map((decl) =>
  502. variableDeclarationWalker(decl, true)
  503. );
  504. const functions = program.functions.map(functionWalker);
  505. return { globals, functions };
  506. } catch (e) {
  507. console.error(e);
  508. return null;
  509. }
  510. }