parseFromVisual.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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. const TYPES = {
  8. VARIABLE: "var",
  9. CONST: "const",
  10. FUNCTION: "function",
  11. RELATIONAL: "relational",
  12. LOGIC: "logic",
  13. ARITHMETIC: "arithmetic",
  14. };
  15. function translateOp (type, op) {
  16. switch (type) {
  17. case TYPES.ARITHMETIC:
  18. return op.value;
  19. case TYPES.RELATIONAL:
  20. return op.value;
  21. case TYPES.LOGIC: {
  22. if (op.ord === 11) {
  23. return "and";
  24. } else if (op.ord === 12) {
  25. return "or";
  26. } else {
  27. return "not";
  28. }
  29. }
  30. }
  31. }
  32. function getOpType (op) {
  33. switch (op.ord) {
  34. case 0:
  35. case 1:
  36. case 2:
  37. case 3:
  38. case 4:
  39. return TYPES.ARITHMETIC;
  40. case 5:
  41. case 6:
  42. case 7:
  43. case 8:
  44. case 9:
  45. case 10:
  46. return TYPES.RELATIONAL;
  47. default:
  48. return TYPES.LOGIC;
  49. }
  50. }
  51. /**
  52. * @param {Commands.Assign} assingment
  53. * */
  54. function assignmentWalker (assingment) {
  55. let variable = null
  56. if (assingment instanceof Commands.ArrayIndexAssign) {
  57. const line = expressionWalker(assingment.line);
  58. let arrayClass = "vector";
  59. let column = null;
  60. if (assingment.column) {
  61. arrayClass = "matrix";
  62. column = expressionWalker(assingment.column);
  63. }
  64. variable = [
  65. {
  66. instance: "expression",
  67. type: TYPES.VARIABLE,
  68. class: arrayClass,
  69. column: column,
  70. line: line,
  71. value: assingment.id,
  72. },
  73. ];
  74. } else {
  75. variable = [
  76. { instance: "expression", type: TYPES.VARIABLE, value: assingment.id },
  77. ]
  78. }
  79. const expression = expressionWalker(assingment.expression)
  80. return {
  81. type: "attribution",
  82. variable,
  83. expression
  84. }
  85. }
  86. /**
  87. * @param {Command} command
  88. * */
  89. function commandWalker (command) {
  90. if (command instanceof Commands.FunctionCall) {
  91. return functionCallWalker(command)
  92. } else if (command instanceof Commands.Assign) {
  93. return assignmentWalker(command)
  94. }
  95. throw new Error("not implemented")
  96. }
  97. /**
  98. * @param {Commands.FunctionCall} functionCall
  99. * */
  100. function functionCallWalker (functionCall) {
  101. let name = functionCall.id;
  102. if (name.indexOf(".") !== -1) {
  103. name = name.split(".")[1]
  104. }
  105. if (name === "$read") {
  106. const variable = functionCall.actualParameters.map(expressionWalker)[0]
  107. return {
  108. type:"reader",
  109. variable
  110. }
  111. }
  112. if (name === "$write") {
  113. const content = functionCall.actualParameters.map(expressionWalker)
  114. const lastInput = content[content.length - 1][0];
  115. // if lastInput is an object with value === '\n', newLine is true
  116. const newLine = lastInput.value && lastInput.value.match(/\n/) !== null
  117. return {
  118. type:"writer",
  119. newLine,
  120. content
  121. }
  122. }
  123. throw new Error("not implemented")
  124. }
  125. /**
  126. * @param {Commands.Function} func
  127. * */
  128. function functionWalker (func) {
  129. const funcDeclaration = {
  130. name: func.name,
  131. return_type: "",
  132. return_dimensions: 0,
  133. parameters_list: [],
  134. variables_list: [],
  135. commands: [],
  136. };
  137. if (func.returnType instanceof ArrayType) {
  138. funcDeclaration.return_type = func.returnType.innerType.value;
  139. funcDeclaration.return_dimensions = func.returnType.dimensions;
  140. } else {
  141. funcDeclaration.return_type = func.returnType.value;
  142. }
  143. funcDeclaration.parameters_list = func.formalParameters.map(
  144. functionParameterWalker
  145. );
  146. funcDeclaration.variables_list = func.variablesDeclarations.map(
  147. variableDeclarationWalker
  148. );
  149. funcDeclaration.commands = func.commands.map(commandWalker)
  150. return funcDeclaration;
  151. }
  152. /**
  153. * @param {Commands.FormalParameter} formalParameter
  154. * */
  155. function functionParameterWalker (formalParameter) {
  156. const variable = {
  157. name: formalParameter.id,
  158. type: "",
  159. rows: 0,
  160. columns: 0,
  161. dimension: 0,
  162. value: 0,
  163. is_const: false,
  164. reference: formalParameter.byRef,
  165. };
  166. if (formalParameter.type instanceof ArrayType) {
  167. variable.type = formalParameter.type.innerType.value;
  168. variable.dimension = formalParameter.type.dimensions;
  169. } else {
  170. variable.type = formalParameter.type.value;
  171. }
  172. return variable;
  173. }
  174. /**
  175. * @param {Commands.Declaration} command
  176. * @param {boolean} global
  177. * */
  178. function variableDeclarationWalker (command, global = false) {
  179. const variable = {
  180. name: command.id,
  181. type: "",
  182. rows: 0,
  183. columns: 0,
  184. dimension: 0,
  185. value: 0,
  186. is_const: false,
  187. };
  188. variable.is_const = global && command.isConst;
  189. if (command instanceof Commands.ArrayDeclaration) {
  190. // array
  191. const lines = expressionWalker(command.lines).pop();
  192. variable.type = command.type.innerType.value;
  193. if (command.isVector) {
  194. variable.rows = 1;
  195. variable.columns = lines.value;
  196. variable.dimension = 1;
  197. const values = command.initial.map(
  198. (exp) => expressionWalker(exp).pop().value
  199. );
  200. variable.value = values;
  201. } else {
  202. const columns = expressionWalker(command.columns).pop();
  203. variable.dimension = 2;
  204. variable.rows = lines.value;
  205. variable.columns = columns.value;
  206. const values = command.initial.map((rows) =>
  207. rows.map((exp) => expressionWalker(exp).pop().value)
  208. );
  209. variable.value = values;
  210. }
  211. } else {
  212. // atomic
  213. variable.type = command.type.value;
  214. variable.value = expressionWalker(command.initial).pop().value;
  215. }
  216. return variable;
  217. }
  218. /**
  219. *
  220. * @return {[]}
  221. **/
  222. function expressionWalker (expression) {
  223. let result;
  224. if (expression instanceof Expressions.VariableLiteral) {
  225. result = [
  226. { instance: "expression", type: TYPES.VARIABLE, value: expression.id },
  227. ];
  228. } else if (expression instanceof Expressions.FunctionCall) {
  229. const funcObj = {
  230. instance: "expression",
  231. type: TYPES.FUNCTION,
  232. value: expression.id,
  233. };
  234. const paramsList = expression.actualParameters.map((e) =>
  235. expressionWalker(e)
  236. );
  237. //const params = Array.prototype.concat.apply([], paramsList);
  238. funcObj.params = paramsList;
  239. result = [funcObj];
  240. } else if (expression instanceof Expressions.UnaryApp) {
  241. const left = expressionWalker(expression.left);
  242. const opType = getOpType(expression.op);
  243. const opValue = translateOp(opType, expression.op);
  244. result = [{ instance: "operator", type: opType, value: opValue }, ...left];
  245. } else if (expression instanceof Expressions.InfixApp) {
  246. const left = expressionWalker(expression.left);
  247. const right = expressionWalker(expression.right);
  248. const opType = getOpType(expression.op);
  249. const opValue = translateOp(opType, expression.op);
  250. result = [
  251. ...left,
  252. { instance: "operator", type: opType, value: opValue },
  253. ...right,
  254. ];
  255. } else if (expression instanceof Expressions.ArrayAccess) {
  256. const line = expressionWalker(expression.line);
  257. let arrayClass = "vector";
  258. let column = null;
  259. if (expression.column) {
  260. arrayClass = "matrix";
  261. column = expressionWalker(expression.column);
  262. }
  263. result = [
  264. {
  265. instance: "expression",
  266. type: TYPES.VARIABLE,
  267. class: arrayClass,
  268. column: column,
  269. line: line,
  270. value: expression.id,
  271. },
  272. ];
  273. } else if (expression instanceof Expressions.BoolLiteral) {
  274. const value = expression.value;
  275. result = [
  276. {
  277. instance: "expression",
  278. class: "simple",
  279. type: TYPES.CONST,
  280. value: convertBoolToString(value),
  281. },
  282. ];
  283. } else {
  284. let value = expression.value;
  285. if (expression.value.toNumber) {
  286. if (
  287. Types.REAL.isCompatible(expression.type) &&
  288. expression.value.decimalPlaces() == 0
  289. ) {
  290. value = expression.value.toFixed(2);
  291. } else {
  292. value = expression.value.toNumber();
  293. }
  294. }
  295. result = [
  296. {
  297. instance: "expression",
  298. class: "simple",
  299. type: TYPES.CONST,
  300. value: value,
  301. },
  302. ];
  303. }
  304. if (expression.parenthesis) return ["(", ...result, ")"];
  305. else return result;
  306. }
  307. export function parseExpression (text) {
  308. const parser = IVProgParser.createParser(text);
  309. const expressionAST = parser.parseExpressionOR();
  310. return expressionWalker(expressionAST);
  311. }
  312. /**
  313. * @param {string} text
  314. * */
  315. export function parseCode (text) {
  316. const parser = IVProgParser.createParser(text, false);
  317. const codeLinesMap = new Map();
  318. const tokens = Array.from(parser.lexer.reset(text));
  319. const tokenStream = [];
  320. for (const token of tokens) {
  321. if (token.type === parser.ruleNames.ERROR) {
  322. return null;
  323. }
  324. if (token.type === parser.ruleNames.COMMENTS) {
  325. for (let i = 0; i <= token.lineBreaks; i++) {
  326. if (codeLinesMap.has(i + token.line))
  327. codeLinesMap.get(i + token.line).push(token);
  328. else codeLinesMap.set(i + token.line, [token]);
  329. }
  330. continue;
  331. }
  332. if (token.type !== parser.ruleNames.WHITESPACE) {
  333. tokenStream.push(token);
  334. }
  335. }
  336. parser.fill(tokenStream);
  337. const program = parser.parseTree();
  338. const globals = program.global.map((decl) =>
  339. variableDeclarationWalker(decl, true)
  340. );
  341. const functions = program.functions.map(functionWalker);
  342. return { globals, functions };
  343. }