ivprogParser.js 44 KB

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