ivprogParser.js 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572
  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. const token = this.getToken();
  921. this.pushScope(IVProgParser.BREAKABLE);
  922. this.pos++;
  923. this.checkOpenParenthesis();
  924. this.pos++;
  925. this.consumeNewLines();
  926. const exp = this.parseExpressionOR();
  927. this.consumeNewLines();
  928. this.checkCloseParenthesis();
  929. this.pos++;
  930. this.consumeNewLines();
  931. this.checkOpenCurly();
  932. this.pos++;
  933. this.consumeNewLines();
  934. const casesList = this.parseCases();
  935. this.consumeNewLines();
  936. this.checkCloseCurly();
  937. this.pos++;
  938. this.consumeNewLines();
  939. this.popScope();
  940. const command = new Commands.Switch(exp, casesList);
  941. command.sourceInfo = SourceInfo.createSourceInfo(token);
  942. return command;
  943. }
  944. parseRepeatUntil () {
  945. const token = this.getToken();
  946. this.pos++;
  947. this.consumeNewLines();
  948. this.pushScope(IVProgParser.BREAKABLE);
  949. const commandsBlock = this.parseCommandBlock();
  950. this.consumeNewLines(); //Maybe not...
  951. const whileToken = this.getToken();
  952. if (whileToken.type !== this.ruleNames.RK_DO_UNTIL) {
  953. throw SyntaxErrorFactory.token_missing_one(
  954. this.ivprogLexer.getReservedKeys()[this.ruleNames.RK_DO_UNTIL],
  955. whileToken
  956. );
  957. }
  958. this.pos++;
  959. this.checkOpenParenthesis();
  960. this.pos++;
  961. this.consumeNewLines();
  962. const condition = this.parseExpressionOR();
  963. this.consumeNewLines();
  964. this.checkCloseParenthesis();
  965. this.pos++;
  966. this.checkEOS();
  967. this.popScope();
  968. const command = new Commands.RepeatUntil(condition, commandsBlock);
  969. command.sourceInfo = SourceInfo.createSourceInfo(token);
  970. return command;
  971. }
  972. parseIfThenElse () {
  973. if (this.insideScope(IVProgParser.BREAKABLE)) {
  974. this.pushScope(IVProgParser.BREAKABLE);
  975. } else {
  976. this.pushScope(IVProgParser.COMMAND);
  977. }
  978. const token = this.getToken();
  979. this.pos++;
  980. this.checkOpenParenthesis();
  981. this.pos++;
  982. this.consumeNewLines();
  983. const logicalExpression = this.parseExpressionOR();
  984. this.consumeNewLines();
  985. this.checkCloseParenthesis();
  986. this.pos++;
  987. this.consumeNewLines();
  988. const cmdBlocks = this.parseCommandBlock();
  989. const maybeElse = this.getToken();
  990. if (maybeElse.type === this.ruleNames.RK_ELSE) {
  991. this.pos++;
  992. this.consumeNewLines();
  993. const maybeIf = this.getToken();
  994. let elseBlock = null;
  995. if (this.checkOpenCurly(true)) {
  996. elseBlock = this.parseCommandBlock();
  997. } else if (maybeIf.type === this.ruleNames.RK_IF) {
  998. elseBlock = this.parseIfThenElse();
  999. } else {
  1000. throw SyntaxErrorFactory.token_missing_list(
  1001. [this.ivprogLexer.getReservedKeys()[this.ruleNames.RK_IF], "{"],
  1002. maybeIf
  1003. );
  1004. }
  1005. this.popScope();
  1006. const cmd = new Commands.IfThenElse(
  1007. logicalExpression,
  1008. cmdBlocks,
  1009. elseBlock
  1010. );
  1011. cmd.sourceInfo = SourceInfo.createSourceInfo(token);
  1012. return cmd;
  1013. }
  1014. this.popScope();
  1015. const cmd = new Commands.IfThenElse(logicalExpression, cmdBlocks, null);
  1016. cmd.sourceInfo = SourceInfo.createSourceInfo(token);
  1017. return cmd;
  1018. }
  1019. parseFor () {
  1020. this.pushScope(IVProgParser.BREAKABLE);
  1021. const for_token = this.getToken();
  1022. this.pos += 1;
  1023. // parse ID
  1024. const id_token = this.getToken();
  1025. const id = this.parseID();
  1026. const for_id = new Expressions.VariableLiteral(id);
  1027. for_id.sourceInfo = SourceInfo.createSourceInfo(id_token);
  1028. // END parse ID
  1029. const for_from = this.parseForParameters(this.ruleNames.RK_FOR_FROM);
  1030. const for_to = this.parseForParameters(this.ruleNames.RK_FOR_TO);
  1031. const maybePass = this.parseForParameters(this.ruleNames.RK_FOR_PASS);
  1032. this.consumeNewLines();
  1033. const commandsBlock = this.parseCommandBlock();
  1034. this.popScope();
  1035. const cmd = new Commands.For(
  1036. for_id,
  1037. for_from,
  1038. for_to,
  1039. maybePass,
  1040. commandsBlock
  1041. );
  1042. cmd.sourceInfo = SourceInfo.createSourceInfo(for_token);
  1043. return cmd;
  1044. }
  1045. parseWhile () {
  1046. this.pushScope(IVProgParser.BREAKABLE);
  1047. const token = this.getToken();
  1048. this.pos++;
  1049. this.checkOpenParenthesis();
  1050. this.pos++;
  1051. this.consumeNewLines();
  1052. const logicalExpression = this.parseExpressionOR();
  1053. this.consumeNewLines();
  1054. this.checkCloseParenthesis();
  1055. this.pos++;
  1056. this.consumeNewLines();
  1057. const cmdBlocks = this.parseCommandBlock();
  1058. this.popScope();
  1059. const cmd = new Commands.While(logicalExpression, cmdBlocks);
  1060. cmd.sourceInfo = SourceInfo.createSourceInfo(token);
  1061. return cmd;
  1062. }
  1063. parseBreak () {
  1064. const token = this.getToken();
  1065. this.pos++;
  1066. this.checkEOS();
  1067. this.pos++;
  1068. const command = new Commands.Break();
  1069. command.sourceInfo = SourceInfo.createSourceInfo(token);
  1070. return command;
  1071. }
  1072. parseReturn () {
  1073. const token = this.getToken();
  1074. this.pos++;
  1075. let exp = null;
  1076. if (!this.checkEOS(true)) {
  1077. exp = this.parseExpressionOR();
  1078. this.checkEOS();
  1079. }
  1080. this.pos++;
  1081. const returnCommand = new Commands.Return(exp);
  1082. returnCommand.sourceInfo = SourceInfo.createSourceInfo(token);
  1083. return returnCommand;
  1084. }
  1085. parseIDCommand () {
  1086. const refToken = this.getToken();
  1087. const id = this.parseMaybeLibID();
  1088. const isID = id.indexOf(".") === -1;
  1089. if (this.checkOpenBrace(true)) {
  1090. this.pos++;
  1091. let lineExpression = null;
  1092. let columnExpression = null;
  1093. this.consumeNewLines();
  1094. lineExpression = this.parseExpression();
  1095. this.consumeNewLines();
  1096. this.checkCloseBrace();
  1097. this.pos++;
  1098. if (this.checkOpenBrace(true)) {
  1099. this.pos++;
  1100. this.consumeNewLines();
  1101. columnExpression = this.parseExpression();
  1102. this.consumeNewLines();
  1103. this.checkCloseBrace();
  1104. this.pos++;
  1105. }
  1106. const assignmentToken = this.getToken();
  1107. if (assignmentToken.type !== this.ruleNames.ASSIGNMENT) {
  1108. // TODO BETTER MESSAGE
  1109. throw SyntaxErrorFactory.token_missing_one("<-", assignmentToken);
  1110. }
  1111. this.pos++;
  1112. const exp = this.parseExpressionOR();
  1113. this.checkEOS();
  1114. this.pos++;
  1115. const cmd = new Commands.ArrayIndexAssign(
  1116. id,
  1117. lineExpression,
  1118. columnExpression,
  1119. exp
  1120. );
  1121. cmd.sourceInfo = SourceInfo.createSourceInfo(assignmentToken);
  1122. return cmd;
  1123. }
  1124. const assignmentOrParenthesis = this.getToken();
  1125. if (isID && assignmentOrParenthesis.type === this.ruleNames.ASSIGNMENT) {
  1126. this.pos++;
  1127. const exp = this.parseExpressionOR();
  1128. this.checkEOS();
  1129. this.pos++;
  1130. const cmd = new Commands.Assign(id, exp);
  1131. cmd.sourceInfo = SourceInfo.createSourceInfo(assignmentOrParenthesis);
  1132. return cmd;
  1133. } else if (
  1134. assignmentOrParenthesis.type === this.ruleNames.OPEN_PARENTHESIS
  1135. ) {
  1136. const funcCall = this.parseFunctionCallCommand(id);
  1137. this.checkEOS();
  1138. this.pos++;
  1139. return funcCall;
  1140. } else if (isID) {
  1141. throw SyntaxErrorFactory.token_missing_list(
  1142. ["<-", "("],
  1143. assignmentOrParenthesis
  1144. );
  1145. } else {
  1146. throw SyntaxErrorFactory.invalid_id_format(refToken);
  1147. }
  1148. }
  1149. parseForParameters (keyword_code) {
  1150. if (keyword_code === this.ruleNames.RK_FOR_PASS) {
  1151. if (this.checkOpenCurly(true)) {
  1152. return null;
  1153. }
  1154. }
  1155. const from_token = this.getToken();
  1156. if (from_token.type !== keyword_code) {
  1157. // TODO better error message
  1158. const keyword = this.ivprogLexer.getReservedKeys()[keyword_code];
  1159. throw new Error(
  1160. "Error de sintaxe no comando repita_para: esperava-se " +
  1161. keyword +
  1162. " mas encontrou " +
  1163. from_token.text
  1164. );
  1165. }
  1166. this.pos += 1;
  1167. let int_or_id = this.getToken();
  1168. let is_unary_op = false;
  1169. let op = null;
  1170. if (int_or_id.type === this.ruleNames.SUM_OP) {
  1171. is_unary_op = true;
  1172. op = int_or_id.text;
  1173. this.pos += 1;
  1174. int_or_id = this.getToken();
  1175. }
  1176. let for_from = null;
  1177. if (int_or_id.type === this.ruleNames.ID) {
  1178. for_from = new Expressions.VariableLiteral(this.parseID());
  1179. for_from.sourceInfo = SourceInfo.createSourceInfo(int_or_id);
  1180. } else if (int_or_id.type === this.ruleNames.INTEGER) {
  1181. this.pos += 1;
  1182. for_from = this.getIntLiteral(int_or_id);
  1183. }
  1184. if (for_from == null) {
  1185. // TODO better error message
  1186. const keyword = this.ivprogLexer.getReservedKeys()[keyword_code];
  1187. throw new Error(
  1188. "Error de sintaxe no comando repeita_para: " +
  1189. int_or_id.text +
  1190. " não é compativel com o esperado para o paramentro " +
  1191. keyword +
  1192. ". O valor deve ser um inteiro ou variável."
  1193. );
  1194. }
  1195. if (is_unary_op) {
  1196. for_from = new Expressions.UnaryApp(convertFromString(op), for_from);
  1197. }
  1198. return for_from;
  1199. }
  1200. parseCases () {
  1201. const token = this.getToken();
  1202. if (token.type !== this.ruleNames.RK_CASE) {
  1203. throw SyntaxErrorFactory.token_missing_one(
  1204. this.ivprogLexer.getReservedKeys()[this.ruleNames.RK_CASE],
  1205. token
  1206. );
  1207. }
  1208. this.pos++;
  1209. const nextToken = this.getToken();
  1210. if (nextToken.type === this.ruleNames.RK_DEFAULT) {
  1211. this.pos++;
  1212. const colonToken = this.getToken();
  1213. if (colonToken.type !== this.ruleNames.COLON) {
  1214. throw SyntaxErrorFactory.token_missing_one(":", colonToken);
  1215. }
  1216. this.pos++;
  1217. this.consumeNewLines();
  1218. const block = this.parseCommandBlock(true);
  1219. const defaultCase = new Commands.Case(null);
  1220. defaultCase.sourceInfo = SourceInfo.createSourceInfo(token);
  1221. defaultCase.setCommands(block.commands);
  1222. return [defaultCase];
  1223. } else {
  1224. const exp = this.parseExpressionOR();
  1225. const colonToken = this.getToken();
  1226. if (colonToken.type !== this.ruleNames.COLON) {
  1227. throw SyntaxErrorFactory.token_missing_one(":", colonToken);
  1228. }
  1229. this.pos++;
  1230. this.consumeNewLines();
  1231. const block = this.parseCommandBlock(true);
  1232. const aCase = new Commands.Case(exp);
  1233. aCase.sourceInfo = SourceInfo.createSourceInfo(token);
  1234. aCase.setCommands(block.commands);
  1235. const caseToken = this.getToken();
  1236. if (caseToken.type === this.ruleNames.RK_CASE) {
  1237. return [aCase].concat(this.parseCases());
  1238. } else {
  1239. return [aCase];
  1240. }
  1241. }
  1242. }
  1243. /*
  1244. * Parses an Expression following the structure:
  1245. *
  1246. * EOR => EAnd ( 'or' EOR)? #expression and
  1247. *
  1248. * EAnd => ENot ('and' EAnd)? #expression or
  1249. *
  1250. * ENot => 'not'? ER #expression not
  1251. *
  1252. * ER => E ((>=, <=, ==, >, <) ER)? #expression relational
  1253. *
  1254. * E => factor ((+, -) E)? #expression
  1255. *
  1256. * factor=> term ((*, /, %) factor)?
  1257. *
  1258. * term => literal || arrayAccess || FuncCall || ID || '('EOR')'
  1259. **/
  1260. parseExpressionOR () {
  1261. let exp1 = this.parseExpressionAND();
  1262. while (this.getToken().type === this.ruleNames.RK_LOGICAL_OR) {
  1263. const opToken = this.getToken();
  1264. this.pos++;
  1265. const or = convertFromString("or");
  1266. this.consumeNewLines();
  1267. const exp2 = this.parseExpressionAND();
  1268. const finalExp = new Expressions.InfixApp(or, exp1, exp2);
  1269. finalExp.sourceInfo = SourceInfo.createSourceInfo(opToken);
  1270. exp1 = finalExp;
  1271. }
  1272. return exp1;
  1273. }
  1274. parseExpressionAND () {
  1275. let exp1 = this.parseExpressionNot();
  1276. while (this.getToken().type === this.ruleNames.RK_LOGICAL_AND) {
  1277. const opToken = this.getToken();
  1278. this.pos++;
  1279. const and = convertFromString("and");
  1280. this.consumeNewLines();
  1281. const exp2 = this.parseExpressionNot();
  1282. const finalExp = new Expressions.InfixApp(and, exp1, exp2);
  1283. finalExp.sourceInfo = SourceInfo.createSourceInfo(opToken);
  1284. exp1 = finalExp;
  1285. }
  1286. return exp1;
  1287. }
  1288. parseExpressionNot () {
  1289. const maybeNotToken = this.getToken();
  1290. if (maybeNotToken.type === this.ruleNames.RK_LOGICAL_NOT) {
  1291. const opToken = this.getToken();
  1292. this.pos++;
  1293. const not = convertFromString("not");
  1294. const exp1 = this.parseExpressionRel();
  1295. const finalExp = new Expressions.UnaryApp(not, exp1);
  1296. finalExp.sourceInfo = SourceInfo.createSourceInfo(opToken);
  1297. return finalExp;
  1298. } else {
  1299. return this.parseExpressionRel();
  1300. }
  1301. }
  1302. parseExpressionRel () {
  1303. let exp1 = this.parseExpression();
  1304. while (this.getToken().type === this.ruleNames.RELATIONAL_OPERATOR) {
  1305. const relToken = this.getToken();
  1306. this.pos++;
  1307. const rel = convertFromString(relToken.text);
  1308. const exp2 = this.parseExpression();
  1309. const finalExp = new Expressions.InfixApp(rel, exp1, exp2);
  1310. finalExp.sourceInfo = SourceInfo.createSourceInfo(relToken);
  1311. exp1 = finalExp;
  1312. }
  1313. return exp1;
  1314. }
  1315. parseExpression () {
  1316. let factor = this.parseFactor();
  1317. while (this.getToken().type === this.ruleNames.SUM_OP) {
  1318. const sumOpToken = this.getToken();
  1319. this.pos++;
  1320. const op = convertFromString(sumOpToken.text);
  1321. const factor2 = this.parseFactor();
  1322. const finalExp = new Expressions.InfixApp(op, factor, factor2);
  1323. finalExp.sourceInfo = SourceInfo.createSourceInfo(sumOpToken);
  1324. factor = finalExp;
  1325. }
  1326. return factor;
  1327. }
  1328. parseFactor () {
  1329. let term = this.parseTerm();
  1330. while (this.getToken().type === this.ruleNames.MULTI_OP) {
  1331. const multOpToken = this.getToken();
  1332. this.pos++;
  1333. const op = convertFromString(multOpToken.text);
  1334. const term2 = this.parseTerm();
  1335. const finalExp = new Expressions.InfixApp(op, term, term2);
  1336. finalExp.sourceInfo = SourceInfo.createSourceInfo(multOpToken);
  1337. term = finalExp;
  1338. }
  1339. return term;
  1340. }
  1341. parseTerm () {
  1342. const token = this.getToken();
  1343. let sourceInfo = null;
  1344. let exp = null;
  1345. switch (token.type) {
  1346. case this.ruleNames.SUM_OP:
  1347. this.pos++;
  1348. sourceInfo = SourceInfo.createSourceInfo(token);
  1349. exp = new Expressions.UnaryApp(
  1350. convertFromString(token.text),
  1351. this.parseTerm()
  1352. );
  1353. exp.sourceInfo = sourceInfo;
  1354. return exp;
  1355. case this.ruleNames.INTEGER:
  1356. this.pos++;
  1357. return this.getIntLiteral(token);
  1358. case this.ruleNames.REAL:
  1359. this.pos++;
  1360. return this.getRealLiteral(token);
  1361. case this.ruleNames.STRING:
  1362. this.pos++;
  1363. return this.getStringLiteral(token);
  1364. case this.ruleNames.CHARACTER:
  1365. this.pos++;
  1366. return this.getCharLiteral(token);
  1367. case this.ruleNames.RK_TRUE:
  1368. case this.ruleNames.RK_FALSE:
  1369. this.pos++;
  1370. return this.getBoolLiteral(token);
  1371. case this.ruleNames.OPEN_CURLY:
  1372. // No more annonymous array
  1373. // return this.parseArrayLiteral();
  1374. throw SyntaxErrorFactory.annonymous_array_literal(token);
  1375. case this.ruleNames.ID:
  1376. return this.parseIDTerm();
  1377. case this.ruleNames.OPEN_PARENTHESIS:
  1378. return this.parseParenthesisExp();
  1379. default:
  1380. throw SyntaxErrorFactory.invalid_terminal(token);
  1381. }
  1382. }
  1383. parseIDTerm () {
  1384. const tokenA = this.getToken();
  1385. const id = this.parseMaybeLibID();
  1386. const isID = id.indexOf(".") === -1;
  1387. if (isID && this.checkOpenBrace(true)) {
  1388. let tokenB = null;
  1389. this.pos++;
  1390. const firstIndex = this.parseExpression();
  1391. let secondIndex = null;
  1392. this.consumeNewLines();
  1393. this.checkCloseBrace();
  1394. tokenB = this.getToken();
  1395. this.pos++;
  1396. if (this.checkOpenBrace(true)) {
  1397. this.pos++;
  1398. secondIndex = this.parseExpression();
  1399. this.consumeNewLines();
  1400. this.checkCloseBrace();
  1401. tokenB = this.getToken();
  1402. this.pos++;
  1403. }
  1404. const sourceInfo = SourceInfo.createSourceInfoFromList(tokenA, tokenB);
  1405. const exp = new Expressions.ArrayAccess(id, firstIndex, secondIndex);
  1406. exp.sourceInfo = sourceInfo;
  1407. return exp;
  1408. } else if (this.checkOpenParenthesis(true)) {
  1409. return this.parseFunctionCallExpression(id);
  1410. } else if (isID) {
  1411. const sourceInfo = SourceInfo.createSourceInfo(tokenA);
  1412. const exp = new Expressions.VariableLiteral(id);
  1413. exp.sourceInfo = sourceInfo;
  1414. return exp;
  1415. } else {
  1416. throw SyntaxErrorFactory.invalid_id_format(tokenA);
  1417. }
  1418. }
  1419. getFunctionName (id) {
  1420. const name = LanguageDefinedFunction.getInternalName(id);
  1421. if (name === null) {
  1422. if (id === LanguageDefinedFunction.getMainFunctionName()) {
  1423. return null;
  1424. }
  1425. return id;
  1426. } else {
  1427. return name;
  1428. }
  1429. }
  1430. parseFunctionCallExpression (id) {
  1431. const stepBack = id.indexOf(".") === -1 ? 1 : 3;
  1432. const tokenA = this.getToken(this.pos - stepBack);
  1433. const actualParameters = this.parseActualParameters();
  1434. const tokenB = this.getToken(this.pos - 1);
  1435. const funcName = this.getFunctionName(id);
  1436. const sourceInfo = SourceInfo.createSourceInfoFromList(tokenA, tokenB);
  1437. const cmd = new Expressions.FunctionCall(funcName, actualParameters);
  1438. cmd.sourceInfo = sourceInfo;
  1439. return cmd;
  1440. }
  1441. parseFunctionCallCommand (id) {
  1442. return this.parseFunctionCallExpression(id);
  1443. }
  1444. parseParenthesisExp () {
  1445. this.checkOpenParenthesis();
  1446. const tokenA = this.getToken();
  1447. this.pos += 1;
  1448. this.consumeNewLines();
  1449. const exp = this.parseExpressionOR();
  1450. this.consumeNewLines();
  1451. this.checkCloseParenthesis();
  1452. const tokenB = this.getToken();
  1453. this.pos += 1;
  1454. exp.sourceInfo = SourceInfo.createSourceInfoFromList(tokenA, tokenB);
  1455. exp.parenthesis = true;
  1456. return exp;
  1457. }
  1458. parseActualParameters () {
  1459. this.checkOpenParenthesis();
  1460. this.pos++;
  1461. if (this.checkCloseParenthesis(true)) {
  1462. this.pos++;
  1463. return [];
  1464. }
  1465. this.consumeNewLines();
  1466. const list = this.parseExpressionList();
  1467. this.consumeNewLines();
  1468. this.checkCloseParenthesis();
  1469. this.pos++;
  1470. return list;
  1471. }
  1472. parseExpressionList () {
  1473. const list = [];
  1474. for (;;) {
  1475. const exp = this.parseExpressionOR();
  1476. list.push(exp);
  1477. const maybeToken = this.getToken();
  1478. if (maybeToken.type !== this.ruleNames.COMMA) {
  1479. break;
  1480. } else {
  1481. this.pos++;
  1482. this.consumeNewLines();
  1483. }
  1484. }
  1485. return list;
  1486. }
  1487. getTypeArray () {
  1488. const types = this.insideScope(IVProgParser.FUNCTION)
  1489. ? this.functionTypes
  1490. : this.variableTypes;
  1491. return types.map((x) => this.lexer.literalNames[x]);
  1492. }
  1493. }