ivprogParser.js 46 KB

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