parseFromVisual.js 9.8 KB

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