ivprogParser.js 45 KB

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