ivprogParser.js 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564
  1. import * as Expressions from "./expressions";
  2. import * as Commands from "./commands";
  3. import * as Parsers from "../typeSystem/parsers";
  4. import { Types } from "../typeSystem/types";
  5. import { ArrayType } from "../typeSystem/array_type";
  6. import { SourceInfo } from "./sourceInfo";
  7. import { convertFromString } from "./operators";
  8. import { SyntaxErrorFactory } from "./error/syntaxErrorFactory";
  9. import { LanguageDefinedFunction } from "../processor/definedFunctions";
  10. import { LanguageService } from "../services/languageService";
  11. export class IVProgParser {
  12. static createParser (input, fill = true) {
  13. const lexer = LanguageService.getCurrentLexer();
  14. const parser = new IVProgParser(input, lexer);
  15. if (fill) {
  16. parser.fill();
  17. }
  18. return parser;
  19. }
  20. // <BEGIN scope consts>
  21. static get BASE () {
  22. return 0;
  23. }
  24. static get FUNCTION () {
  25. return 1;
  26. }
  27. static get COMMAND () {
  28. return 2;
  29. }
  30. static get BREAKABLE () {
  31. return 4;
  32. }
  33. // </ END scope consts>
  34. //
  35. static get EOF_TOKEN () {
  36. return {
  37. text: null,
  38. line: -1,
  39. col: -1,
  40. value: null,
  41. offset: -1,
  42. lineBreaks: false,
  43. type: "EOF",
  44. };
  45. }
  46. /**
  47. * @param {string} input
  48. * @param {IVProgLexer} ivprogLexer
  49. **/
  50. constructor (input, ivprogLexer) {
  51. this.ivprogLexer = ivprogLexer;
  52. this.inputStream = input;
  53. this.lexer = ivprogLexer.lexer;
  54. this.tokenStream = [];
  55. this.pos = 0;
  56. this.ruleNames = ivprogLexer.getRules();
  57. this.variableTypes = Object.entries(this.ivprogLexer.getTypeKeys()).map(
  58. ([key, _]) => key
  59. );
  60. this.functionTypes = this.variableTypes.concat(this.ruleNames.RK_VOID);
  61. this.parsingArrayDimension = 0;
  62. this.scope = [];
  63. this.langFuncs = this.ivprogLexer.getLangFuncs();
  64. this.definedFuncsNameList = [];
  65. this.definedVariablesStack = [];
  66. }
  67. fill (stream = null) {
  68. if (stream) {
  69. this.tokenStream = stream;
  70. return;
  71. }
  72. this.tokenStream = Array.from(this.lexer.reset(this.inputStream));
  73. this.tokenStream = this.tokenStream.filter((token) => {
  74. // Throws an exception in case of invalid syntax
  75. if (token.type === this.ruleNames.ERROR) {
  76. let text = token.text;
  77. const line = token.line;
  78. const column = token.col;
  79. throw SyntaxErrorFactory.invalid_syntax(text, line, column);
  80. }
  81. // remove all whitespaces token and comments
  82. return (
  83. token.type !== this.ruleNames.WHITESPACE &&
  84. token.type !== this.ruleNames.COMMENTS
  85. );
  86. });
  87. }
  88. parseTree () {
  89. return this.parseProgram();
  90. }
  91. /**
  92. * @param {number} index
  93. * @return {moo.Token}
  94. * */
  95. getToken (index = this.pos) {
  96. // if(index === null)
  97. // index = this.pos;
  98. if (index >= this.tokenStream.length) {
  99. return IVProgParser.EOF_TOKEN;
  100. }
  101. return this.tokenStream[index];
  102. }
  103. insideScope (scope) {
  104. if (this.scope.length <= 0) {
  105. return IVProgParser.BASE === scope;
  106. } else {
  107. return this.scope[this.scope.length - 1] === scope;
  108. }
  109. }
  110. pushScope (scope) {
  111. this.scope.push(scope);
  112. }
  113. pushVariableStack () {
  114. this.definedVariablesStack.push([]);
  115. }
  116. popScope () {
  117. return this.scope.pop();
  118. }
  119. popVariableStack () {
  120. return this.definedVariablesStack.pop();
  121. }
  122. getCurrentVariableStack () {
  123. return this.definedVariablesStack[this.definedVariablesStack.length - 1];
  124. }
  125. isEOF () {
  126. return this.getToken(this.pos).type === IVProgParser.EOF_TOKEN.type;
  127. }
  128. parseProgram () {
  129. this.consumeNewLines();
  130. const token = this.getToken();
  131. let globalVars = [];
  132. let functions = [];
  133. if (this.ruleNames.RK_PROGRAM === token.type) {
  134. this.pos++;
  135. this.consumeNewLines();
  136. this.checkOpenCurly();
  137. this.pos++;
  138. this.pushVariableStack();
  139. for (;;) {
  140. this.consumeNewLines();
  141. const token = this.getToken();
  142. if (
  143. token.type === this.ruleNames.RK_CONST ||
  144. this.isVariableType(token)
  145. ) {
  146. globalVars = globalVars.concat(this.parseGlobalVariables());
  147. } else if (token.type === this.ruleNames.RK_FUNCTION) {
  148. this.pushVariableStack();
  149. functions = functions.concat(this.parseFunction());
  150. this.popVariableStack();
  151. } else {
  152. break;
  153. }
  154. }
  155. this.consumeNewLines();
  156. this.checkCloseCurly();
  157. this.pos++;
  158. this.consumeNewLines();
  159. if (!this.isEOF()) {
  160. console.log(this.getToken());
  161. throw SyntaxErrorFactory.extra_lines();
  162. }
  163. this.popVariableStack();
  164. return { global: globalVars, functions: functions };
  165. } else {
  166. throw SyntaxErrorFactory.token_missing_one(
  167. this.ivprogLexer.getReservedKeys()[this.ruleNames.RK_PROGRAM],
  168. token
  169. );
  170. }
  171. }
  172. checkOpenCurly (attempt = false) {
  173. const token = this.getToken();
  174. if (this.ruleNames.OPEN_CURLY !== token.type) {
  175. if (!attempt) throw SyntaxErrorFactory.token_missing_one("{", token);
  176. else return false;
  177. }
  178. return true;
  179. }
  180. checkCloseCurly (attempt = false) {
  181. const token = this.getToken();
  182. if (this.ruleNames.CLOSE_CURLY !== token.type) {
  183. if (!attempt) throw SyntaxErrorFactory.token_missing_one("}", token);
  184. else return false;
  185. }
  186. return true;
  187. }
  188. /* It checks if the current token at position pos is a ']'.
  189. * As a check function it doesn't increment pos.
  190. *
  191. * @params bool:attempt, indicates that the token is optional. Defaults: false
  192. *
  193. * @returns true if the attempt is true and current token is '[',
  194. * false is attempt is true and current token is not '['
  195. **/
  196. checkOpenBrace (attempt = false) {
  197. const token = this.getToken();
  198. if (this.ruleNames.OPEN_BRACE !== token.type) {
  199. if (!attempt) {
  200. throw SyntaxErrorFactory.token_missing_one("[", token);
  201. } else {
  202. return false;
  203. }
  204. }
  205. return true;
  206. }
  207. checkCloseBrace (attempt = false) {
  208. const token = this.getToken();
  209. if (this.ruleNames.CLOSE_BRACE !== token.type) {
  210. if (!attempt) {
  211. throw SyntaxErrorFactory.token_missing_one("]", token);
  212. } else {
  213. return false;
  214. }
  215. }
  216. return true;
  217. }
  218. checkOpenParenthesis (attempt = false) {
  219. const token = this.getToken();
  220. if (this.ruleNames.OPEN_PARENTHESIS !== token.type) {
  221. if (!attempt) {
  222. throw SyntaxErrorFactory.token_missing_one("(", token);
  223. } else {
  224. return false;
  225. }
  226. }
  227. return true;
  228. }
  229. checkCloseParenthesis (attempt = false) {
  230. const token = this.getToken();
  231. if (this.ruleNames.CLOSE_PARENTHESIS !== token.type) {
  232. if (!attempt) {
  233. throw SyntaxErrorFactory.token_missing_one(")", token);
  234. } else {
  235. return false;
  236. }
  237. }
  238. return true;
  239. }
  240. checkEOS (attempt = false) {
  241. const eosToken = this.getToken();
  242. if (eosToken.type !== this.ruleNames.EOS) {
  243. if (!attempt) throw SyntaxErrorFactory.eos_missing(eosToken);
  244. else return false;
  245. }
  246. return true;
  247. }
  248. checkFunctionDuplicate (functionID, funcIDToken) {
  249. const id = functionID === null ? "$main" : functionID;
  250. const index = this.definedFuncsNameList.indexOf(id);
  251. if (index !== -1) {
  252. throw SyntaxErrorFactory.duplicate_function(funcIDToken);
  253. }
  254. this.definedFuncsNameList.push(id);
  255. }
  256. checkVariableDuplicate (variableID, sourceInfo) {
  257. const index = this.getCurrentVariableStack().indexOf(variableID);
  258. if (index !== -1) {
  259. throw SyntaxErrorFactory.duplicate_variable(sourceInfo);
  260. }
  261. this.getCurrentVariableStack().push(variableID);
  262. }
  263. consumeForSemiColon () {
  264. const eosToken = this.getToken();
  265. if (eosToken.type === this.ruleNames.EOS && eosToken.text.match("^;$")) {
  266. this.pos++;
  267. return;
  268. }
  269. throw SyntaxErrorFactory.token_missing_one(";", eosToken);
  270. }
  271. parseGlobalVariables () {
  272. const decl = this.parseMaybeConst();
  273. this.checkEOS();
  274. this.pos++;
  275. return decl;
  276. }
  277. /*
  278. * Checks if the next token is PR_CONST. It's only available
  279. * at global variables declaration level
  280. * @returns Declararion(const, type, id, initVal?)
  281. **/
  282. parseMaybeConst () {
  283. const constToken = this.getToken();
  284. if (constToken.type === this.ruleNames.RK_CONST) {
  285. this.pos++;
  286. const typeString = this.parseType();
  287. return this.parseDeclaration(typeString, true);
  288. } else if (this.isVariableType(constToken)) {
  289. const typeString = this.parseType();
  290. return this.parseDeclaration(typeString);
  291. } else {
  292. throw SyntaxErrorFactory.token_missing_list(
  293. [this.ivprogLexer.getReservedKeys()[this.ruleNames.RK_CONST]].concat(
  294. this.getTypeArray()
  295. ),
  296. constToken
  297. );
  298. }
  299. }
  300. /**
  301. * Parses a declarion of the form: type --- id --- (= --- EAnd)?
  302. * @return {Commands.Declartion[]} a list of Declararion(const, type, id, initVal?)
  303. **/
  304. parseDeclaration (typeString, isConst = false) {
  305. let initial = null;
  306. let dim1 = null;
  307. let dim2 = null;
  308. let dimensions = 0;
  309. const sourceInfo = SourceInfo.createSourceInfo(this.getToken());
  310. const idString = this.parseID();
  311. this.checkVariableDuplicate(idString, sourceInfo);
  312. // Check for array or vector
  313. // ID[int/IDi?][int/IDj?]
  314. if (this.checkOpenBrace(true)) {
  315. this.pos += 1;
  316. this.consumeNewLines();
  317. dim1 = this.parseArrayDimension();
  318. this.consumeNewLines();
  319. this.checkCloseBrace();
  320. this.pos += 1;
  321. dimensions += 1;
  322. if (this.checkOpenBrace(true)) {
  323. this.pos += 1;
  324. this.consumeNewLines();
  325. dim2 = this.parseArrayDimension();
  326. this.consumeNewLines();
  327. this.checkCloseBrace();
  328. this.pos += 1;
  329. dimensions += 1;
  330. }
  331. return this.parseArrayDeclaration(
  332. typeString,
  333. isConst,
  334. idString,
  335. sourceInfo,
  336. dimensions,
  337. dim1,
  338. dim2
  339. );
  340. } else {
  341. const assignmentToken = this.getToken();
  342. if (isConst && assignmentToken.type !== this.ruleNames.ASSIGNMENT) {
  343. throw SyntaxErrorFactory.const_not_init(sourceInfo);
  344. }
  345. if (assignmentToken.type === this.ruleNames.ASSIGNMENT) {
  346. this.pos++;
  347. initial = this.parseExpressionOR();
  348. }
  349. const declaration = new Commands.Declaration(
  350. idString,
  351. typeString,
  352. initial,
  353. isConst
  354. );
  355. declaration.sourceInfo = sourceInfo;
  356. const commaToken = this.getToken();
  357. if (commaToken.type === this.ruleNames.COMMA) {
  358. this.pos++;
  359. this.consumeNewLines();
  360. return [declaration].concat(this.parseDeclaration(typeString, isConst));
  361. } else {
  362. return [declaration];
  363. }
  364. }
  365. }
  366. parseArrayDeclaration (
  367. typeString,
  368. isConst,
  369. idString,
  370. sourceInfo,
  371. dimensions,
  372. dim1,
  373. dim2
  374. ) {
  375. const assignmentToken = this.getToken();
  376. let n_lines = dim1;
  377. let n_columns = dim2;
  378. let initial = null;
  379. let dim_is_id = false;
  380. if (
  381. dim1 instanceof Expressions.VariableLiteral ||
  382. dim2 instanceof Expressions.VariableLiteral
  383. ) {
  384. dim_is_id = true;
  385. if (dimensions > 1 && (dim1 == null || dim2 == null)) {
  386. throw SyntaxErrorFactory.invalid_matrix_id_dimension(
  387. SourceInfo.createSourceInfo(assignmentToken)
  388. );
  389. }
  390. }
  391. if (isConst && assignmentToken.type !== this.ruleNames.ASSIGNMENT) {
  392. throw SyntaxErrorFactory.const_not_init(sourceInfo);
  393. }
  394. if (assignmentToken.type === this.ruleNames.ASSIGNMENT) {
  395. if (dim_is_id) {
  396. if (dimensions == 1) {
  397. throw SyntaxErrorFactory.invalid_vector_init(
  398. SourceInfo.createSourceInfo(assignmentToken)
  399. );
  400. } else {
  401. throw SyntaxErrorFactory.invalid_matrix_init(
  402. SourceInfo.createSourceInfo(assignmentToken)
  403. );
  404. }
  405. }
  406. this.pos += 1;
  407. initial = this.parseArrayLiteral(typeString);
  408. }
  409. if (initial == null && dim1 == null) {
  410. if (dimensions > 1) {
  411. throw SyntaxErrorFactory.cannot_infer_matrix_line(idString, sourceInfo);
  412. }
  413. throw SyntaxErrorFactory.cannot_infer_vector_size(idString, sourceInfo);
  414. }
  415. if (dimensions > 1) {
  416. if (initial == null && dim2 == null) {
  417. throw SyntaxErrorFactory.cannot_infer_matrix_column(
  418. idString,
  419. sourceInfo
  420. );
  421. }
  422. }
  423. if (dimensions === 1 && initial != null && !initial.isVector) {
  424. const expString = initial.toString();
  425. throw SyntaxErrorFactory.matrix_to_vector_literal_attr(
  426. idString,
  427. expString,
  428. initial.sourceInfo
  429. );
  430. } else if (dimensions > 1 && initial != null && initial.isVector) {
  431. const expString = initial.toString();
  432. throw SyntaxErrorFactory.vector_to_matrix_literal_attr(
  433. idString,
  434. expString,
  435. initial.sourceInfo
  436. );
  437. }
  438. if (dim1 == null) {
  439. n_lines = new Expressions.IntLiteral(Parsers.toInt(initial.lines));
  440. n_lines.sourceInfo = sourceInfo;
  441. }
  442. if (dimensions > 1) {
  443. if (dim2 == null) {
  444. n_columns = new Expressions.IntLiteral(Parsers.toInt(initial.columns));
  445. n_columns.sourceInfo = sourceInfo;
  446. }
  447. }
  448. const declaration = new Commands.ArrayDeclaration(
  449. idString,
  450. new ArrayType(typeString, dimensions),
  451. n_lines,
  452. n_columns,
  453. initial,
  454. isConst
  455. );
  456. declaration.sourceInfo = sourceInfo;
  457. const commaToken = this.getToken();
  458. if (commaToken.type === this.ruleNames.COMMA) {
  459. this.pos++;
  460. this.consumeNewLines();
  461. return [declaration].concat(this.parseDeclaration(typeString, isConst));
  462. } else {
  463. return [declaration];
  464. }
  465. }
  466. consumeNewLines () {
  467. let token = this.getToken();
  468. while (
  469. token &&
  470. token.type === this.ruleNames.EOS &&
  471. token.text.match("^[\r\n]+$")
  472. ) {
  473. this.pos++;
  474. token = this.getToken();
  475. }
  476. }
  477. isVariableType (token) {
  478. return this.variableTypes.find((v) => v === token.type);
  479. }
  480. /**
  481. * Reads the next token of the stream to check if it is a Integer or an ID.
  482. * @returns Integer | ID
  483. **/
  484. parseArrayDimension () {
  485. const dimToken = this.getToken();
  486. if (dimToken.type === this.ruleNames.INTEGER) {
  487. //parse as int literal
  488. this.pos++;
  489. return this.getIntLiteral(dimToken);
  490. } else if (dimToken.type === this.ruleNames.ID) {
  491. //parse as variable
  492. this.pos++;
  493. return this.parseVariable(dimToken);
  494. } else if (dimToken.type === this.ruleNames.CLOSE_BRACE) {
  495. return null;
  496. } else {
  497. throw SyntaxErrorFactory.invalid_array_dimension(
  498. this.ivprogLexer.getReservedKeys()[this.ruleNames.RK_INTEGER],
  499. dimToken
  500. );
  501. }
  502. }
  503. /**
  504. * Returns an object {type: 'int', value: value}.
  505. * It checks for binary and hexadecimal integers.
  506. * @param {moo.Token} token
  507. * @return {Object} object with fields type and value
  508. **/
  509. getIntLiteral (token) {
  510. const text = token.text;
  511. const sourceInfo = SourceInfo.createSourceInfo(token);
  512. const exp = new Expressions.IntLiteral(Parsers.toInt(text));
  513. exp.sourceInfo = sourceInfo;
  514. return exp;
  515. }
  516. getRealLiteral (token) {
  517. const sourceInfo = SourceInfo.createSourceInfo(token);
  518. const exp = new Expressions.RealLiteral(Parsers.toReal(token.text));
  519. exp.sourceInfo = sourceInfo;
  520. return exp;
  521. }
  522. getStringLiteral (token) {
  523. const text = token.text;
  524. const sourceInfo = SourceInfo.createSourceInfo(token);
  525. const exp = new Expressions.StringLiteral(Parsers.toString(text));
  526. exp.sourceInfo = sourceInfo;
  527. return exp;
  528. }
  529. getCharLiteral (token) {
  530. const text = token.text;
  531. const exp = new Expressions.CharLiteral(Parsers.toChar(text));
  532. exp.sourceInfo = SourceInfo.createSourceInfo(token);
  533. return exp;
  534. }
  535. getBoolLiteral (token) {
  536. const val = Parsers.toBool(token.text);
  537. const exp = new Expressions.BoolLiteral(val);
  538. exp.sourceInfo = SourceInfo.createSourceInfo(token);
  539. return exp;
  540. }
  541. parseArrayLiteral (typeString) {
  542. const openCurly = this.checkOpenCurly(true);
  543. if (!openCurly) {
  544. const invalid_token = this.getToken();
  545. throw SyntaxErrorFactory.array_init_not_literal(
  546. SourceInfo.createSourceInfo(invalid_token)
  547. );
  548. }
  549. const beginArray = this.getToken();
  550. if (this.parsingArrayDimension >= 2) {
  551. throw SyntaxErrorFactory.array_exceeds_2d(
  552. SourceInfo.createSourceInfo(beginArray)
  553. );
  554. }
  555. this.pos += 1;
  556. this.parsingArrayDimension += 1;
  557. this.consumeNewLines();
  558. let data = null;
  559. const maybeCurlyOpen = this.checkOpenCurly(true);
  560. if (maybeCurlyOpen) {
  561. // This is potentially a list of vectors
  562. data = this.parseVectorList(typeString);
  563. } else {
  564. data = this.parseExpressionList();
  565. }
  566. this.consumeNewLines();
  567. this.checkCloseCurly();
  568. const endArray = this.getToken();
  569. this.pos += 1;
  570. this.parsingArrayDimension -= 1;
  571. const sourceInfo = SourceInfo.createSourceInfoFromList(
  572. beginArray,
  573. endArray
  574. );
  575. let dataDim = 1;
  576. if (data[0] instanceof Expressions.ArrayLiteral) {
  577. dataDim += 1;
  578. } else if (data.length == 1) {
  579. console.log("Talvez uma variável seja uma melhor opção");
  580. }
  581. const type = new ArrayType(typeString, dataDim);
  582. const exp = new Expressions.ArrayLiteral(type, data);
  583. exp.sourceInfo = sourceInfo;
  584. return exp;
  585. }
  586. /**
  587. * Returns a list of ArrayLiterals. Helper function for parsing matrices
  588. */
  589. parseVectorList (typeString) {
  590. const list = [];
  591. let lastSize = null;
  592. for (;;) {
  593. this.checkOpenCurly();
  594. const beginArray = this.getToken();
  595. if (this.parsingArrayDimension >= 2) {
  596. throw SyntaxErrorFactory.array_exceeds_2d(
  597. SourceInfo.createSourceInfo(beginArray)
  598. );
  599. }
  600. this.pos += 1;
  601. this.parsingArrayDimension += 1;
  602. this.consumeNewLines();
  603. const data = this.parseExpressionList();
  604. this.consumeNewLines();
  605. this.checkCloseCurly();
  606. const endArray = this.getToken();
  607. this.pos += 1;
  608. this.parsingArrayDimension -= 1;
  609. const sourceInfo = SourceInfo.createSourceInfoFromList(
  610. beginArray,
  611. endArray
  612. );
  613. if (lastSize == null) {
  614. lastSize = data.length;
  615. } else if (lastSize !== data.length) {
  616. const expString = this.inputStream.substring(
  617. beginArray.offset,
  618. endArray.offset + endArray.text.length
  619. );
  620. throw SyntaxErrorFactory.invalid_matrix_literal_line(
  621. expString,
  622. sourceInfo
  623. );
  624. }
  625. const type = new ArrayType(typeString, 1);
  626. const exp = new Expressions.ArrayLiteral(type, data);
  627. exp.sourceInfo = sourceInfo;
  628. list.push(exp);
  629. const commaToken = this.getToken();
  630. if (commaToken.type !== this.ruleNames.COMMA) {
  631. break;
  632. }
  633. this.pos += 1;
  634. this.consumeNewLines();
  635. }
  636. if (list.length == 1) {
  637. console.log("Talvez um vetor seja uma melhor opção");
  638. }
  639. return list;
  640. }
  641. /*
  642. * Returns an object {type: 'variable', value: value}.
  643. * @returns object with fields type and value
  644. **/
  645. parseVariable (token) {
  646. const sourceInfo = SourceInfo.createSourceInfo(token);
  647. const exp = new Expressions.VariableLiteral(token.text);
  648. exp.sourceInfo = sourceInfo;
  649. return exp;
  650. }
  651. /*
  652. * Returns an object representing a function. It has
  653. * four attributes: returnType, id, formalParams and block.
  654. * The block object has two attributes: declarations and commands
  655. **/
  656. parseFunction () {
  657. this.pushScope(IVProgParser.FUNCTION);
  658. let formalParams = [];
  659. const token = this.getToken();
  660. if (token.type !== this.ruleNames.RK_FUNCTION) {
  661. //throw SyntaxError.createError(this.lexer.literalNames[this.lexerClass.PR_FUNCAO], token);
  662. return null;
  663. }
  664. this.pos++;
  665. const funType = this.parseType();
  666. let dimensions = 0;
  667. if (this.checkOpenBrace(true)) {
  668. this.pos++;
  669. this.checkCloseBrace();
  670. this.pos++;
  671. dimensions++;
  672. if (this.checkOpenBrace(true)) {
  673. this.pos++;
  674. this.checkCloseBrace();
  675. this.pos++;
  676. dimensions++;
  677. }
  678. }
  679. const funcIDToken = this.getToken();
  680. const functionID = this.parseID();
  681. this.checkFunctionDuplicate(functionID, funcIDToken);
  682. this.checkOpenParenthesis();
  683. this.pos++;
  684. this.consumeNewLines();
  685. if (!this.checkCloseParenthesis(true)) {
  686. formalParams = this.parseFormalParameters(); // formal parameters
  687. this.consumeNewLines();
  688. this.checkCloseParenthesis();
  689. this.pos++;
  690. } else {
  691. this.pos++;
  692. }
  693. this.consumeNewLines();
  694. const commandsBlock = this.parseCommandBlock();
  695. let returnType = funType;
  696. if (dimensions > 0) {
  697. returnType = new ArrayType(funType, dimensions);
  698. }
  699. const func = new Commands.Function(
  700. functionID,
  701. returnType,
  702. formalParams,
  703. commandsBlock
  704. );
  705. if (functionID === null && !func.isMain) {
  706. throw SyntaxErrorFactory.invalid_main_return(
  707. LanguageDefinedFunction.getMainFunctionName(),
  708. this.ivprogLexer.getReservedKeys()[this.ruleNames.RK_VOID],
  709. token.line
  710. );
  711. } else if (func.isMain && formalParams.length !== 0) {
  712. throw SyntaxErrorFactory.main_parameters();
  713. }
  714. this.popScope();
  715. func.sourceInfo = SourceInfo.createSourceInfo(funcIDToken);
  716. return func;
  717. }
  718. /*
  719. * Parse the formal parameters of a function.
  720. * @returns a list of objects with the following attributes: type, id and dimensions.
  721. **/
  722. parseFormalParameters () {
  723. const list = [];
  724. for (;;) {
  725. let dimensions = 0;
  726. let reference = false;
  727. const typeString = this.parseType();
  728. let maybeIDToken = this.getToken();
  729. if (maybeIDToken.type === this.ruleNames.RK_REFERENCE) {
  730. reference = true;
  731. this.pos += 1;
  732. maybeIDToken = this.getToken();
  733. }
  734. const idString = this.parseID();
  735. this.checkVariableDuplicate(idString, maybeIDToken);
  736. if (this.checkOpenBrace(true)) {
  737. this.pos += 1;
  738. dimensions += 1;
  739. this.checkCloseBrace();
  740. this.pos += 1;
  741. if (this.checkOpenBrace(true)) {
  742. this.pos += 1;
  743. dimensions += 1;
  744. this.checkCloseBrace();
  745. this.pos += 1;
  746. }
  747. }
  748. let type = null;
  749. if (dimensions > 0) {
  750. type = new ArrayType(typeString, dimensions);
  751. } else {
  752. type = typeString;
  753. }
  754. const parameter = new Commands.FormalParameter(type, idString, reference);
  755. parameter.sourceInfo = SourceInfo.createSourceInfo(maybeIDToken);
  756. list.push(parameter);
  757. const commaToken = this.getToken();
  758. if (commaToken.type !== this.ruleNames.COMMA) break;
  759. this.pos++;
  760. this.consumeNewLines();
  761. }
  762. return list;
  763. }
  764. parseID () {
  765. const token = this.getToken();
  766. if (token.type !== this.ruleNames.ID) {
  767. throw SyntaxErrorFactory.id_missing(token);
  768. }
  769. this.pos++;
  770. if (this.insideScope(IVProgParser.FUNCTION)) {
  771. if (token.text === LanguageDefinedFunction.getMainFunctionName()) {
  772. return null;
  773. }
  774. }
  775. return token.text;
  776. }
  777. /**
  778. * @return {string}
  779. **/
  780. parseMaybeLibID () {
  781. const token = this.getToken();
  782. if (token.type !== this.ruleNames.ID) {
  783. throw SyntaxErrorFactory.id_missing(token);
  784. }
  785. const maybeDOT = this.getToken(this.pos + 1);
  786. if (maybeDOT.type === this.ruleNames.DOT) {
  787. this.pos += 2;
  788. const anotherID = this.getToken();
  789. if (anotherID.type !== this.ruleNames.ID) {
  790. throw SyntaxErrorFactory.id_missing(anotherID);
  791. }
  792. this.pos++;
  793. return `${token.text}.${anotherID.text}`;
  794. }
  795. this.pos++;
  796. return token.text;
  797. }
  798. parseType () {
  799. const token = this.getToken();
  800. if (
  801. token.type === this.ruleNames.ID &&
  802. this.insideScope(IVProgParser.FUNCTION)
  803. ) {
  804. return Types.VOID;
  805. } else if (
  806. token.type === this.ruleNames.RK_VOID &&
  807. this.insideScope(IVProgParser.FUNCTION)
  808. ) {
  809. this.pos++;
  810. return Types.VOID;
  811. } else if (this.isVariableType(token)) {
  812. this.pos++;
  813. switch (token.type) {
  814. case this.ruleNames.RK_INTEGER:
  815. return Types.INTEGER;
  816. case this.ruleNames.RK_BOOLEAN:
  817. return Types.BOOLEAN;
  818. case this.ruleNames.RK_REAL:
  819. return Types.REAL;
  820. case this.ruleNames.RK_STRING:
  821. return Types.STRING;
  822. case this.ruleNames.RK_CHARACTER:
  823. return Types.CHAR;
  824. default:
  825. break;
  826. }
  827. }
  828. throw SyntaxErrorFactory.invalid_type(this.getTypeArray(), token);
  829. }
  830. parseCommandBlock (optionalCurly = false) {
  831. let variablesDecl = [];
  832. const commands = [];
  833. let hasOpen = false;
  834. if (this.checkOpenCurly(optionalCurly)) {
  835. this.pos++;
  836. hasOpen = true;
  837. }
  838. this.consumeNewLines();
  839. let parsedCommand = false;
  840. for (;;) {
  841. const cmd = this.parseCommand();
  842. if (cmd === null) break;
  843. if (cmd !== -1) {
  844. if (cmd instanceof Array) {
  845. if (parsedCommand) {
  846. const lastToken = this.getToken(this.pos - 1);
  847. throw SyntaxErrorFactory.invalid_var_declaration(lastToken);
  848. }
  849. variablesDecl = variablesDecl.concat(cmd);
  850. } else {
  851. parsedCommand = true;
  852. commands.push(cmd);
  853. }
  854. }
  855. }
  856. this.consumeNewLines();
  857. if (hasOpen) {
  858. this.checkCloseCurly();
  859. this.pos++;
  860. this.consumeNewLines();
  861. }
  862. return new Commands.CommandBlock(variablesDecl, commands);
  863. }
  864. parseCommand () {
  865. const token = this.getToken();
  866. if (this.isVariableType(token)) {
  867. if (!this.insideScope(IVProgParser.FUNCTION)) {
  868. throw SyntaxErrorFactory.invalid_var_declaration(token);
  869. }
  870. this.pushScope(IVProgParser.BASE);
  871. const varType = this.parseType();
  872. this.popScope();
  873. const cmd = this.parseDeclaration(varType);
  874. this.checkEOS();
  875. this.pos++;
  876. return cmd;
  877. } else if (token.type === this.ruleNames.ID) {
  878. return this.parseIDCommand();
  879. } else if (token.type === this.ruleNames.DOT) {
  880. // TODO Check if this is relevant since DOT is a replacement for antlr4 LIB_ID :=> ID . ID
  881. throw SyntaxErrorFactory.invalid_syntax(
  882. token.text,
  883. token.line,
  884. token.col
  885. );
  886. } else if (token.type === this.ruleNames.RK_RETURN) {
  887. return this.parseReturn();
  888. } else if (
  889. token.type === this.ruleNames.RK_WHILE ||
  890. token.type === this.ruleNames.RK_WHILE_ALT
  891. ) {
  892. return this.parseWhile();
  893. } else if (
  894. token.type === this.ruleNames.RK_FOR ||
  895. token.type === this.ruleNames.RK_FOR_ALT
  896. ) {
  897. return this.parseFor();
  898. } else if (token.type === this.ruleNames.RK_BREAK) {
  899. if (!this.insideScope(IVProgParser.BREAKABLE)) {
  900. throw SyntaxErrorFactory.invalid_break_command(
  901. this.ivprogLexer.getReservedKeys()[this.ruleNames.RK_BREAK],
  902. token
  903. );
  904. }
  905. return this.parseBreak();
  906. } else if (token.type === this.ruleNames.RK_SWITCH) {
  907. return this.parseSwitchCase();
  908. } else if (token.type === this.ruleNames.RK_DO) {
  909. return this.parseRepeatUntil();
  910. } else if (token.type === this.ruleNames.RK_IF) {
  911. return this.parseIfThenElse();
  912. } else if (this.checkEOS(true)) {
  913. this.pos++;
  914. return -1;
  915. } else {
  916. return null;
  917. }
  918. }
  919. parseSwitchCase () {
  920. this.pushScope(IVProgParser.BREAKABLE);
  921. this.pos++;
  922. this.checkOpenParenthesis();
  923. this.pos++;
  924. this.consumeNewLines();
  925. const exp = this.parseExpressionOR();
  926. this.consumeNewLines();
  927. this.checkCloseParenthesis();
  928. this.pos++;
  929. this.consumeNewLines();
  930. this.checkOpenCurly();
  931. this.pos++;
  932. this.consumeNewLines();
  933. const casesList = this.parseCases();
  934. this.consumeNewLines();
  935. this.checkCloseCurly();
  936. this.pos++;
  937. this.consumeNewLines();
  938. this.popScope();
  939. return new Commands.Switch(exp, casesList);
  940. }
  941. parseRepeatUntil () {
  942. this.pos++;
  943. this.consumeNewLines();
  944. this.pushScope(IVProgParser.BREAKABLE);
  945. const commandsBlock = this.parseCommandBlock();
  946. this.consumeNewLines(); //Maybe not...
  947. const whileToken = this.getToken();
  948. if (whileToken.type !== this.ruleNames.RK_DO_UNTIL) {
  949. throw SyntaxErrorFactory.token_missing_one(
  950. this.ivprogLexer.getReservedKeys()[this.ruleNames.RK_DO_UNTIL],
  951. whileToken
  952. );
  953. }
  954. this.pos++;
  955. this.checkOpenParenthesis();
  956. this.pos++;
  957. this.consumeNewLines();
  958. const condition = this.parseExpressionOR();
  959. this.consumeNewLines();
  960. this.checkCloseParenthesis();
  961. this.pos++;
  962. this.checkEOS();
  963. this.popScope();
  964. return new Commands.RepeatUntil(condition, commandsBlock);
  965. }
  966. parseIfThenElse () {
  967. if (this.insideScope(IVProgParser.BREAKABLE)) {
  968. this.pushScope(IVProgParser.BREAKABLE);
  969. } else {
  970. this.pushScope(IVProgParser.COMMAND);
  971. }
  972. const token = this.getToken();
  973. this.pos++;
  974. this.checkOpenParenthesis();
  975. this.pos++;
  976. this.consumeNewLines();
  977. const logicalExpression = this.parseExpressionOR();
  978. this.consumeNewLines();
  979. this.checkCloseParenthesis();
  980. this.pos++;
  981. this.consumeNewLines();
  982. const cmdBlocks = this.parseCommandBlock();
  983. const maybeElse = this.getToken();
  984. if (maybeElse.type === this.ruleNames.RK_ELSE) {
  985. this.pos++;
  986. this.consumeNewLines();
  987. const maybeIf = this.getToken();
  988. let elseBlock = null;
  989. if (this.checkOpenCurly(true)) {
  990. elseBlock = this.parseCommandBlock();
  991. } else if (maybeIf.type === this.ruleNames.RK_IF) {
  992. elseBlock = this.parseIfThenElse();
  993. } else {
  994. throw SyntaxErrorFactory.token_missing_list(
  995. [this.ivprogLexer.getReservedKeys()[this.ruleNames.RK_IF], "{"],
  996. maybeIf
  997. );
  998. }
  999. this.popScope();
  1000. const cmd = new Commands.IfThenElse(
  1001. logicalExpression,
  1002. cmdBlocks,
  1003. elseBlock
  1004. );
  1005. cmd.sourceInfo = SourceInfo.createSourceInfo(token);
  1006. return cmd;
  1007. }
  1008. this.popScope();
  1009. const cmd = new Commands.IfThenElse(logicalExpression, cmdBlocks, null);
  1010. cmd.sourceInfo = SourceInfo.createSourceInfo(token);
  1011. return cmd;
  1012. }
  1013. parseFor () {
  1014. this.pushScope(IVProgParser.BREAKABLE);
  1015. const for_token = this.getToken();
  1016. this.pos += 1;
  1017. // parse ID
  1018. const id_token = this.getToken();
  1019. const id = this.parseID();
  1020. const for_id = new Expressions.VariableLiteral(id);
  1021. for_id.sourceInfo = SourceInfo.createSourceInfo(id_token);
  1022. // END parse ID
  1023. const for_from = this.parseForParameters(this.ruleNames.RK_FOR_FROM);
  1024. const for_to = this.parseForParameters(this.ruleNames.RK_FOR_TO);
  1025. const maybePass = this.parseForParameters(this.ruleNames.RK_FOR_PASS);
  1026. this.consumeNewLines();
  1027. const commandsBlock = this.parseCommandBlock();
  1028. this.popScope();
  1029. const cmd = new Commands.For(
  1030. for_id,
  1031. for_from,
  1032. for_to,
  1033. maybePass,
  1034. commandsBlock
  1035. );
  1036. cmd.sourceInfo = SourceInfo.createSourceInfo(for_token);
  1037. return cmd;
  1038. }
  1039. parseWhile () {
  1040. this.pushScope(IVProgParser.BREAKABLE);
  1041. const token = this.getToken();
  1042. this.pos++;
  1043. this.checkOpenParenthesis();
  1044. this.pos++;
  1045. this.consumeNewLines();
  1046. const logicalExpression = this.parseExpressionOR();
  1047. this.consumeNewLines();
  1048. this.checkCloseParenthesis();
  1049. this.pos++;
  1050. this.consumeNewLines();
  1051. const cmdBlocks = this.parseCommandBlock();
  1052. this.popScope();
  1053. const cmd = new Commands.While(logicalExpression, cmdBlocks);
  1054. cmd.sourceInfo = SourceInfo.createSourceInfo(token);
  1055. return cmd;
  1056. }
  1057. parseBreak () {
  1058. const token = this.getToken();
  1059. this.pos++;
  1060. this.checkEOS();
  1061. this.pos++;
  1062. const command = new Commands.Break();
  1063. command.sourceInfo = SourceInfo.createSourceInfo(token);
  1064. return command;
  1065. }
  1066. parseReturn () {
  1067. const token = this.getToken();
  1068. this.pos++;
  1069. let exp = null;
  1070. if (!this.checkEOS(true)) {
  1071. exp = this.parseExpressionOR();
  1072. this.checkEOS();
  1073. }
  1074. this.pos++;
  1075. const returnCommand = new Commands.Return(exp);
  1076. returnCommand.sourceInfo = SourceInfo.createSourceInfo(token);
  1077. return returnCommand;
  1078. }
  1079. parseIDCommand () {
  1080. const refToken = this.getToken();
  1081. const id = this.parseMaybeLibID();
  1082. const isID = id.indexOf(".") === -1;
  1083. if (this.checkOpenBrace(true)) {
  1084. this.pos++;
  1085. let lineExpression = null;
  1086. let columnExpression = null;
  1087. this.consumeNewLines();
  1088. lineExpression = this.parseExpression();
  1089. this.consumeNewLines();
  1090. this.checkCloseBrace();
  1091. this.pos++;
  1092. if (this.checkOpenBrace(true)) {
  1093. this.pos++;
  1094. this.consumeNewLines();
  1095. columnExpression = this.parseExpression();
  1096. this.consumeNewLines();
  1097. this.checkCloseBrace();
  1098. this.pos++;
  1099. }
  1100. const assignmentToken = this.getToken();
  1101. if (assignmentToken.type !== this.ruleNames.ASSIGNMENT) {
  1102. // TODO BETTER MESSAGE
  1103. throw SyntaxErrorFactory.token_missing_one("<-", assignmentToken);
  1104. }
  1105. this.pos++;
  1106. const exp = this.parseExpressionOR();
  1107. this.checkEOS();
  1108. this.pos++;
  1109. const cmd = new Commands.ArrayIndexAssign(
  1110. id,
  1111. lineExpression,
  1112. columnExpression,
  1113. exp
  1114. );
  1115. cmd.sourceInfo = SourceInfo.createSourceInfo(assignmentToken);
  1116. return cmd;
  1117. }
  1118. const assignmentOrParenthesis = this.getToken();
  1119. if (isID && assignmentOrParenthesis.type === this.ruleNames.ASSIGNMENT) {
  1120. this.pos++;
  1121. const exp = this.parseExpressionOR();
  1122. this.checkEOS();
  1123. this.pos++;
  1124. const cmd = new Commands.Assign(id, exp);
  1125. cmd.sourceInfo = SourceInfo.createSourceInfo(assignmentOrParenthesis);
  1126. return cmd;
  1127. } else if (
  1128. assignmentOrParenthesis.type === this.ruleNames.OPEN_PARENTHESIS
  1129. ) {
  1130. const funcCall = this.parseFunctionCallCommand(id);
  1131. this.checkEOS();
  1132. this.pos++;
  1133. return funcCall;
  1134. } else if (isID) {
  1135. throw SyntaxErrorFactory.token_missing_list(
  1136. ["<-", "("],
  1137. assignmentOrParenthesis
  1138. );
  1139. } else {
  1140. throw SyntaxErrorFactory.invalid_id_format(refToken);
  1141. }
  1142. }
  1143. parseForParameters (keyword_code) {
  1144. if (keyword_code === this.ruleNames.RK_FOR_PASS) {
  1145. if (this.checkOpenCurly(true)) {
  1146. return null;
  1147. }
  1148. }
  1149. const from_token = this.getToken();
  1150. if (from_token.type !== keyword_code) {
  1151. // TODO better error message
  1152. const keyword = this.ivprogLexer.getReservedKeys()[keyword_code];
  1153. throw new Error(
  1154. "Error de sintaxe no comando repita_para: esperava-se " +
  1155. keyword +
  1156. " mas encontrou " +
  1157. from_token.text
  1158. );
  1159. }
  1160. this.pos += 1;
  1161. let int_or_id = this.getToken();
  1162. let is_unary_op = false;
  1163. let op = null;
  1164. if (int_or_id.type === this.ruleNames.SUM_OP) {
  1165. is_unary_op = true;
  1166. op = int_or_id.text;
  1167. this.pos += 1;
  1168. int_or_id = this.getToken();
  1169. }
  1170. let for_from = null;
  1171. if (int_or_id.type === this.ruleNames.ID) {
  1172. for_from = new Expressions.VariableLiteral(this.parseID());
  1173. for_from.sourceInfo = SourceInfo.createSourceInfo(int_or_id);
  1174. } else if (int_or_id.type === this.ruleNames.INTEGER) {
  1175. this.pos += 1;
  1176. for_from = this.getIntLiteral(int_or_id);
  1177. }
  1178. if (for_from == null) {
  1179. // TODO better error message
  1180. const keyword = this.ivprogLexer.getReservedKeys()[keyword_code];
  1181. throw new Error(
  1182. "Error de sintaxe no comando repeita_para: " +
  1183. int_or_id.text +
  1184. " não é compativel com o esperado para o paramentro " +
  1185. keyword +
  1186. ". O valor deve ser um inteiro ou variável."
  1187. );
  1188. }
  1189. if (is_unary_op) {
  1190. for_from = new Expressions.UnaryApp(convertFromString(op), for_from);
  1191. }
  1192. return for_from;
  1193. }
  1194. parseCases () {
  1195. const token = this.getToken();
  1196. if (token.type !== this.ruleNames.RK_CASE) {
  1197. throw SyntaxErrorFactory.token_missing_one(
  1198. this.ivprogLexer.getReservedKeys()[this.ruleNames.RK_CASE],
  1199. token
  1200. );
  1201. }
  1202. this.pos++;
  1203. const nextToken = this.getToken();
  1204. if (nextToken.type === this.ruleNames.RK_DEFAULT) {
  1205. this.pos++;
  1206. const colonToken = this.getToken();
  1207. if (colonToken.type !== this.ruleNames.COLON) {
  1208. throw SyntaxErrorFactory.token_missing_one(":", colonToken);
  1209. }
  1210. this.pos++;
  1211. this.consumeNewLines();
  1212. const block = this.parseCommandBlock(true);
  1213. const defaultCase = new Commands.Case(null);
  1214. defaultCase.setCommands(block.commands);
  1215. return [defaultCase];
  1216. } else {
  1217. const exp = this.parseExpressionOR();
  1218. const colonToken = this.getToken();
  1219. if (colonToken.type !== this.ruleNames.COLON) {
  1220. throw SyntaxErrorFactory.token_missing_one(":", colonToken);
  1221. }
  1222. this.pos++;
  1223. this.consumeNewLines();
  1224. const block = this.parseCommandBlock(true);
  1225. const aCase = new Commands.Case(exp);
  1226. aCase.setCommands(block.commands);
  1227. const caseToken = this.getToken();
  1228. if (caseToken.type === this.ruleNames.RK_CASE) {
  1229. return [aCase].concat(this.parseCases());
  1230. } else {
  1231. return [aCase];
  1232. }
  1233. }
  1234. }
  1235. /*
  1236. * Parses an Expression following the structure:
  1237. *
  1238. * EOR => EAnd ( 'or' EOR)? #expression and
  1239. *
  1240. * EAnd => ENot ('and' EAnd)? #expression or
  1241. *
  1242. * ENot => 'not'? ER #expression not
  1243. *
  1244. * ER => E ((>=, <=, ==, >, <) ER)? #expression relational
  1245. *
  1246. * E => factor ((+, -) E)? #expression
  1247. *
  1248. * factor=> term ((*, /, %) factor)?
  1249. *
  1250. * term => literal || arrayAccess || FuncCall || ID || '('EOR')'
  1251. **/
  1252. parseExpressionOR () {
  1253. let exp1 = this.parseExpressionAND();
  1254. while (this.getToken().type === this.ruleNames.OR_OPERATOR) {
  1255. const opToken = this.getToken();
  1256. this.pos++;
  1257. const or = convertFromString("or");
  1258. this.consumeNewLines();
  1259. const exp2 = this.parseExpressionAND();
  1260. const finalExp = new Expressions.InfixApp(or, exp1, exp2);
  1261. finalExp.sourceInfo = SourceInfo.createSourceInfo(opToken);
  1262. exp1 = finalExp;
  1263. }
  1264. return exp1;
  1265. }
  1266. parseExpressionAND () {
  1267. let exp1 = this.parseExpressionNot();
  1268. while (this.getToken().type === this.ruleNames.AND_OPERATOR) {
  1269. const opToken = this.getToken();
  1270. this.pos++;
  1271. const and = convertFromString("and");
  1272. this.consumeNewLines();
  1273. const exp2 = this.parseExpressionNot();
  1274. const finalExp = new Expressions.InfixApp(and, exp1, exp2);
  1275. finalExp.sourceInfo = SourceInfo.createSourceInfo(opToken);
  1276. exp1 = finalExp;
  1277. }
  1278. return exp1;
  1279. }
  1280. parseExpressionNot () {
  1281. const maybeNotToken = this.getToken();
  1282. if (maybeNotToken.type === this.ruleNames.NOT_OPERATOR) {
  1283. const opToken = this.getToken();
  1284. this.pos++;
  1285. const not = convertFromString("not");
  1286. const exp1 = this.parseExpressionRel();
  1287. const finalExp = new Expressions.UnaryApp(not, exp1);
  1288. finalExp.sourceInfo = SourceInfo.createSourceInfo(opToken);
  1289. return finalExp;
  1290. } else {
  1291. return this.parseExpressionRel();
  1292. }
  1293. }
  1294. parseExpressionRel () {
  1295. let exp1 = this.parseExpression();
  1296. while (this.getToken().type === this.ruleNames.RELATIONAL_OPERATOR) {
  1297. const relToken = this.getToken();
  1298. this.pos++;
  1299. const rel = convertFromString(relToken.text);
  1300. const exp2 = this.parseExpression();
  1301. const finalExp = new Expressions.InfixApp(rel, exp1, exp2);
  1302. finalExp.sourceInfo = SourceInfo.createSourceInfo(relToken);
  1303. exp1 = finalExp;
  1304. }
  1305. return exp1;
  1306. }
  1307. parseExpression () {
  1308. let factor = this.parseFactor();
  1309. while (this.getToken().type === this.ruleNames.SUM_OP) {
  1310. const sumOpToken = this.getToken();
  1311. this.pos++;
  1312. const op = convertFromString(sumOpToken.text);
  1313. const factor2 = this.parseFactor();
  1314. const finalExp = new Expressions.InfixApp(op, factor, factor2);
  1315. finalExp.sourceInfo = SourceInfo.createSourceInfo(sumOpToken);
  1316. factor = finalExp;
  1317. }
  1318. return factor;
  1319. }
  1320. parseFactor () {
  1321. let term = this.parseTerm();
  1322. while (this.getToken().type === this.ruleNames.MULTI_OP) {
  1323. const multOpToken = this.getToken();
  1324. this.pos++;
  1325. const op = convertFromString(multOpToken.text);
  1326. const term2 = this.parseTerm();
  1327. const finalExp = new Expressions.InfixApp(op, term, term2);
  1328. finalExp.sourceInfo = SourceInfo.createSourceInfo(multOpToken);
  1329. term = finalExp;
  1330. }
  1331. return term;
  1332. }
  1333. parseTerm () {
  1334. const token = this.getToken();
  1335. let sourceInfo = null;
  1336. let exp = null;
  1337. switch (token.type) {
  1338. case this.ruleNames.SUM_OP:
  1339. this.pos++;
  1340. sourceInfo = SourceInfo.createSourceInfo(token);
  1341. exp = new Expressions.UnaryApp(
  1342. convertFromString(token.text),
  1343. this.parseTerm()
  1344. );
  1345. exp.sourceInfo = sourceInfo;
  1346. return exp;
  1347. case this.ruleNames.INTEGER:
  1348. this.pos++;
  1349. return this.getIntLiteral(token);
  1350. case this.ruleNames.REAL:
  1351. this.pos++;
  1352. return this.getRealLiteral(token);
  1353. case this.ruleNames.STRING:
  1354. this.pos++;
  1355. return this.getStringLiteral(token);
  1356. case this.ruleNames.CHARACTER:
  1357. this.pos++;
  1358. return this.getCharLiteral(token);
  1359. case this.ruleNames.RK_TRUE:
  1360. case this.ruleNames.RK_FALSE:
  1361. this.pos++;
  1362. return this.getBoolLiteral(token);
  1363. case this.ruleNames.OPEN_CURLY:
  1364. // No more annonymous array
  1365. // return this.parseArrayLiteral();
  1366. throw SyntaxErrorFactory.annonymous_array_literal(token);
  1367. case this.ruleNames.ID:
  1368. return this.parseIDTerm();
  1369. case this.ruleNames.OPEN_PARENTHESIS:
  1370. return this.parseParenthesisExp();
  1371. default:
  1372. throw SyntaxErrorFactory.invalid_terminal(token);
  1373. }
  1374. }
  1375. parseIDTerm () {
  1376. const tokenA = this.getToken();
  1377. const id = this.parseMaybeLibID();
  1378. const isID = id.indexOf(".") === -1;
  1379. if (isID && this.checkOpenBrace(true)) {
  1380. let tokenB = null;
  1381. this.pos++;
  1382. const firstIndex = this.parseExpression();
  1383. let secondIndex = null;
  1384. this.consumeNewLines();
  1385. this.checkCloseBrace();
  1386. tokenB = this.getToken();
  1387. this.pos++;
  1388. if (this.checkOpenBrace(true)) {
  1389. this.pos++;
  1390. secondIndex = this.parseExpression();
  1391. this.consumeNewLines();
  1392. this.checkCloseBrace();
  1393. tokenB = this.getToken();
  1394. this.pos++;
  1395. }
  1396. const sourceInfo = SourceInfo.createSourceInfoFromList(tokenA, tokenB);
  1397. const exp = new Expressions.ArrayAccess(id, firstIndex, secondIndex);
  1398. exp.sourceInfo = sourceInfo;
  1399. return exp;
  1400. } else if (this.checkOpenParenthesis(true)) {
  1401. return this.parseFunctionCallExpression(id);
  1402. } else if (isID) {
  1403. const sourceInfo = SourceInfo.createSourceInfo(tokenA);
  1404. const exp = new Expressions.VariableLiteral(id);
  1405. exp.sourceInfo = sourceInfo;
  1406. return exp;
  1407. } else {
  1408. throw SyntaxErrorFactory.invalid_id_format(tokenA);
  1409. }
  1410. }
  1411. getFunctionName (id) {
  1412. const name = LanguageDefinedFunction.getInternalName(id);
  1413. if (name === null) {
  1414. if (id === LanguageDefinedFunction.getMainFunctionName()) {
  1415. return null;
  1416. }
  1417. return id;
  1418. } else {
  1419. return name;
  1420. }
  1421. }
  1422. parseFunctionCallExpression (id) {
  1423. const stepBack = id.indexOf(".") === -1 ? 1 : 3;
  1424. const tokenA = this.getToken(this.pos - stepBack);
  1425. const actualParameters = this.parseActualParameters();
  1426. const tokenB = this.getToken(this.pos - 1);
  1427. const funcName = this.getFunctionName(id);
  1428. const sourceInfo = SourceInfo.createSourceInfoFromList(tokenA, tokenB);
  1429. const cmd = new Expressions.FunctionCall(funcName, actualParameters);
  1430. cmd.sourceInfo = sourceInfo;
  1431. return cmd;
  1432. }
  1433. parseFunctionCallCommand (id) {
  1434. return this.parseFunctionCallExpression(id);
  1435. }
  1436. parseParenthesisExp () {
  1437. this.checkOpenParenthesis();
  1438. const tokenA = this.getToken();
  1439. this.consumeNewLines();
  1440. const exp = this.parseExpressionOR();
  1441. this.consumeNewLines();
  1442. this.checkCloseParenthesis();
  1443. const tokenB = this.getToken();
  1444. this.pos += 1;
  1445. exp.sourceInfo = SourceInfo.createSourceInfoFromList(tokenA, tokenB);
  1446. exp.parenthesis = true;
  1447. return exp;
  1448. }
  1449. parseActualParameters () {
  1450. this.checkOpenParenthesis();
  1451. this.pos++;
  1452. if (this.checkCloseParenthesis(true)) {
  1453. this.pos++;
  1454. return [];
  1455. }
  1456. this.consumeNewLines();
  1457. const list = this.parseExpressionList();
  1458. this.consumeNewLines();
  1459. this.checkCloseParenthesis();
  1460. this.pos++;
  1461. return list;
  1462. }
  1463. parseExpressionList () {
  1464. const list = [];
  1465. for (;;) {
  1466. const exp = this.parseExpressionOR();
  1467. list.push(exp);
  1468. const maybeToken = this.getToken();
  1469. if (maybeToken.type !== this.ruleNames.COMMA) {
  1470. break;
  1471. } else {
  1472. this.pos++;
  1473. this.consumeNewLines();
  1474. }
  1475. }
  1476. return list;
  1477. }
  1478. getTypeArray () {
  1479. const types = this.insideScope(IVProgParser.FUNCTION)
  1480. ? this.functionTypes
  1481. : this.variableTypes;
  1482. return types.map((x) => this.lexer.literalNames[x]);
  1483. }
  1484. }