ivprogProcessor.js 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562
  1. import { Store } from "./store/store";
  2. import { Modes } from "./modes";
  3. import { Context } from "./context";
  4. import { Types } from "./../typeSystem/types";
  5. import { Operators } from "./../ast/operators";
  6. import { LanguageDefinedFunction } from "./definedFunctions";
  7. import {
  8. resultTypeAfterInfixOp,
  9. resultTypeAfterUnaryOp,
  10. } from "./compatibilityTable";
  11. import * as Commands from "./../ast/commands/";
  12. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  13. import { Command } from "./../ast/commands/command";
  14. import * as Expressions from "./../ast/expressions/";
  15. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  16. import { Expression } from "./../ast/expressions/expression";
  17. import * as Utils from "./../util/utils";
  18. import { ArrayType } from "./../typeSystem/array_type";
  19. import { convertToString, toInt } from "../typeSystem/parsers";
  20. import { Config } from "../util/config";
  21. import { ProcessorErrorFactory } from "./error/processorErrorFactory";
  22. import { RuntimeError } from "./error/runtimeError";
  23. import { Location } from "../memory/location";
  24. import { StoreValue } from "./store/value/store_value";
  25. import { StoreValueRef } from "./store/value/store_value_ref";
  26. import { ArrayStoreValue } from "./store/value/array_store_value";
  27. import { ArrayStoreValueRef } from "./store/value/array_store_value_ref";
  28. import { StoreValueAddress } from "./store/value/store_value_address";
  29. import { LocalizedStrings } from "../services/localizedStringsService";
  30. export class IVProgProcessor {
  31. static get MAIN_INTERNAL_ID () {
  32. return "$main";
  33. }
  34. constructor (ast) {
  35. this.ast = ast;
  36. this.globalStore = new Store("$global");
  37. this.stores = [this.globalStore];
  38. this.context = [Context.BASE];
  39. this.input = null;
  40. this.forceKill = false;
  41. this.output = null;
  42. this.mode = Modes.RUN;
  43. /**
  44. * Stores the sourceInfo of every function call, command or expression
  45. */
  46. this.function_call_stack = [];
  47. this.instruction_count = 0;
  48. this.function_call_count = 0;
  49. }
  50. registerInput (input) {
  51. if (this.input !== null) this.input = null;
  52. this.input = input;
  53. }
  54. registerOutput (output) {
  55. if (this.output !== null) this.output = null;
  56. this.output = output;
  57. }
  58. checkContext (context) {
  59. return this.context[this.context.length - 1] === context;
  60. }
  61. ignoreSwitchCases (store) {
  62. if (store.mode === Modes.RETURN) {
  63. return true;
  64. } else if (store.mode === Modes.BREAK) {
  65. return true;
  66. } else {
  67. return false;
  68. }
  69. }
  70. prepareState () {
  71. if (this.stores !== null) {
  72. for (let i = 0; i < this.stores.length; i++) {
  73. delete this.stores[i];
  74. }
  75. this.stores = null;
  76. }
  77. if (this.globalStore !== null) this.globalStore = null;
  78. this.globalStore = new Store("$global");
  79. this.stores = [this.globalStore];
  80. this.context = [Context.BASE];
  81. this.instruction_count = 0;
  82. this.mode = Modes.RUN;
  83. }
  84. async interpretAST () {
  85. this.prepareState();
  86. Location.clear();
  87. await this.initGlobal();
  88. const mainFunc = this.findMainFunction();
  89. if (mainFunc === null) {
  90. throw ProcessorErrorFactory.main_missing();
  91. }
  92. return this.runFunction(mainFunc, [], this.globalStore);
  93. }
  94. async initGlobal () {
  95. if (!this.checkContext(Context.BASE)) {
  96. return ProcessorErrorFactory.invalid_global_var();
  97. }
  98. return this.executeCommands(this.globalStore, this.ast.global);
  99. }
  100. findMainFunction () {
  101. return this.ast.functions.find((v) => v.isMain);
  102. }
  103. findFunction (name) {
  104. if (name.match(/^\$.+$/)) {
  105. if (name === IVProgProcessor.MAIN_INTERNAL_ID) {
  106. return this.findMainFunction();
  107. }
  108. const fun = LanguageDefinedFunction.getFunction(name);
  109. if (!fun) {
  110. throw ProcessorErrorFactory.not_implemented(name);
  111. }
  112. return fun;
  113. } else {
  114. const val = this.ast.functions.find((v) => v.name === name);
  115. if (!val) {
  116. throw ProcessorErrorFactory.function_missing(name);
  117. }
  118. return val;
  119. }
  120. }
  121. async runFunction (func, actualParameters, store) {
  122. const funcName = func.isMain ? IVProgProcessor.MAIN_INTERNAL_ID : func.name;
  123. const funcStore = new Store(funcName);
  124. funcStore.extendStore(this.globalStore);
  125. await this.associateParameters(
  126. func.formalParameters,
  127. actualParameters,
  128. store,
  129. funcStore
  130. );
  131. this.context.push(Context.FUNCTION);
  132. this.stores.push(funcStore);
  133. const stoWithVars = await this.executeCommands(
  134. funcStore,
  135. func.variablesDeclarations
  136. );
  137. const finalSto = await this.executeCommands(stoWithVars, func.commands);
  138. this.stores.pop();
  139. this.context.pop();
  140. return finalSto;
  141. }
  142. /**
  143. *
  144. * @param {import('./../ast/commands/formalParameter').FormalParameter[]} formal_params
  145. * @param {Expression[]} effective_params
  146. * @param {Store} caller_store
  147. * @param {Store} callee_store
  148. */
  149. async associateParameters (
  150. formal_params,
  151. effective_params,
  152. caller_store,
  153. callee_store
  154. ) {
  155. const funcName =
  156. callee_store.name === IVProgProcessor.MAIN_INTERNAL_ID
  157. ? LanguageDefinedFunction.getMainFunctionName()
  158. : callee_store.name;
  159. const hasVariadic = formal_params.some((p) => p.variadic);
  160. if (
  161. (formal_params.length != effective_params.length && !hasVariadic) ||
  162. formal_params.length > effective_params.length
  163. ) {
  164. throw ProcessorErrorFactory.invalid_parameters_size(
  165. funcName,
  166. formal_params.length,
  167. effective_params.length
  168. );
  169. }
  170. for (
  171. let i = 0, j = 0;
  172. i < formal_params.length && j < effective_params.length;
  173. i += 1, j += 1
  174. ) {
  175. const formalParameter = formal_params[i];
  176. if (formalParameter.variadic) {
  177. [j, callee_store] = await this.associateVariadicParameter(
  178. funcName,
  179. formalParameter,
  180. j,
  181. effective_params,
  182. caller_store,
  183. callee_store
  184. );
  185. } else {
  186. const actualParam = effective_params[i];
  187. callee_store = await this.associateParameter(
  188. funcName,
  189. formalParameter,
  190. actualParam,
  191. caller_store,
  192. callee_store
  193. );
  194. }
  195. }
  196. return callee_store;
  197. }
  198. /**
  199. *
  200. * @param {string} funcName
  201. * @param {import('./../ast/commands/formalParameter').FormalParameter} formalParameter
  202. * @param {number} index
  203. * @param {Expression[]} effective_params
  204. * @param {Store} caller_store
  205. * @param {Store} callee_store
  206. */
  207. async associateVariadicParameter (
  208. funcName,
  209. formalParameter,
  210. index,
  211. effective_params,
  212. caller_store,
  213. callee_store
  214. ) {
  215. let i;
  216. let count = 1;
  217. for (i = index; i < effective_params.length; i += 1) {
  218. const actualParam = effective_params[i];
  219. callee_store = await this.associateParameter(
  220. funcName,
  221. formalParameter,
  222. actualParam,
  223. caller_store,
  224. callee_store,
  225. count
  226. );
  227. count += 1;
  228. }
  229. const variadicCount = new StoreValue(Types.INTEGER, count, undefined, true);
  230. callee_store.insertStore(`${formalParameter.id}.0`, variadicCount);
  231. return [i - 1, callee_store];
  232. }
  233. /**
  234. *
  235. * @param {string} funcName
  236. * @param {import('./../ast/commands/formalParameter').FormalParameter} formalParameter
  237. * @param {Expression} actualParameter
  238. * @param {Store} callerStore
  239. * @param {Store} calleeStore
  240. * @param {number} variadicCount The number of the current value being assigned to the variadic parameter, default 0
  241. */
  242. async associateParameter (
  243. funcName,
  244. formalParameter,
  245. actualParameter,
  246. callerStore,
  247. calleeStore,
  248. variadicCount = 0
  249. ) {
  250. const actualValue = await this.evaluateExpression(
  251. callerStore,
  252. actualParameter
  253. );
  254. let shouldTypeCast = false;
  255. if (!formalParameter.type.isCompatible(actualValue.type)) {
  256. if (
  257. Config.enable_type_casting &&
  258. !formalParameter.byRef &&
  259. Store.canImplicitTypeCast(formalParameter.type, actualValue.type)
  260. ) {
  261. shouldTypeCast = true;
  262. } else {
  263. throw ProcessorErrorFactory.invalid_parameter_type(
  264. funcName,
  265. actualParameter.toString()
  266. );
  267. }
  268. }
  269. if (formalParameter.byRef && !actualValue.inStore()) {
  270. throw ProcessorErrorFactory.invalid_ref(
  271. funcName,
  272. actualParameter.toString()
  273. );
  274. }
  275. if (formalParameter.byRef) {
  276. const realObj = callerStore.getStoreObject(actualValue.id);
  277. let ref = null;
  278. if (actualValue instanceof ArrayStoreValue) {
  279. // it's a vector or matrix...
  280. const values = actualValue.get();
  281. const array_type = actualValue.type;
  282. const addresses = values.map((v) =>
  283. realObj.getLocAddressOf(v.line, v.column)
  284. );
  285. const columns = actualValue.isVector() ? 0 : actualValue.columns;
  286. ref = new ArrayStoreValueRef(
  287. array_type,
  288. values,
  289. addresses,
  290. actualValue.lines,
  291. columns,
  292. realObj.id
  293. );
  294. } else {
  295. if (actualValue instanceof StoreValueAddress) {
  296. const line = actualValue.line;
  297. const column = actualValue.column;
  298. ref = new StoreValueRef(
  299. actualValue.type,
  300. actualValue.get(),
  301. realObj.getLocAddressOf(line, column),
  302. realObj.id
  303. );
  304. ref.setReferenceDimension(realObj.type.dimensions);
  305. } else {
  306. ref = new StoreValueRef(
  307. actualValue.type,
  308. actualValue.get(),
  309. realObj.locAddress,
  310. realObj.id
  311. );
  312. }
  313. }
  314. let varID = formalParameter.id;
  315. if (formalParameter.variadic) varID = `${varID}.${variadicCount}`;
  316. calleeStore.insertStore(varID, ref);
  317. } else {
  318. let realValue = actualValue;
  319. if (shouldTypeCast) {
  320. realValue = Store.doImplicitCasting(formalParameter.type, realValue);
  321. }
  322. let varID = formalParameter.id;
  323. if (formalParameter.variadic) varID = `${varID}.${variadicCount}`;
  324. calleeStore.insertStore(varID, realValue);
  325. }
  326. return calleeStore;
  327. }
  328. /**
  329. *
  330. * @param {Store} store
  331. * @param {Command[]} cmds
  332. *
  333. * @returns {Promise<Store>}
  334. */
  335. async executeCommands (store, cmds) {
  336. // helper to partially apply a function, in this case executeCommand
  337. let sto = store;
  338. for (let i = 0; i < cmds.length; i += 1) {
  339. sto = await this.executeCommand(sto, cmds[i]);
  340. }
  341. return sto;
  342. }
  343. /**
  344. *
  345. * @param {Store} store
  346. * @param {Command} cmd
  347. *
  348. * @returns {Promise<Store>}
  349. */
  350. async executeCommand (store, cmd) {
  351. this.instruction_count += 1;
  352. if (this.instruction_count % Config.suspend_threshold == 0) {
  353. //every Config.suspend_threshold instruction should briefly delay its execution in order to allow the browser to process other things
  354. await Utils.sleep(3);
  355. }
  356. // Checks if it must interrupt the execution for some reason
  357. if (this.instruction_count >= Config.max_instruction_count) {
  358. throw ProcessorErrorFactory.exceed_max_instructions();
  359. } else if (this.forceKill) {
  360. throw "FORCED_KILL!";
  361. } else if (store.mode === Modes.PAUSE) {
  362. return this.executeCommand(store, cmd);
  363. } else if (store.mode === Modes.RETURN) {
  364. return store;
  365. } else if (
  366. this.checkContext(Context.BREAKABLE) &&
  367. store.mode === Modes.BREAK
  368. ) {
  369. return store;
  370. } else if (this.mode === Modes.ABORT) {
  371. throw LocalizedStrings.getMessage("aborted_execution");
  372. }
  373. if (cmd instanceof Commands.Declaration) {
  374. return this.executeDeclaration(store, cmd);
  375. } else if (cmd instanceof Commands.ArrayIndexAssign) {
  376. return this.executeArrayIndexAssign(store, cmd);
  377. } else if (cmd instanceof Commands.Assign) {
  378. return this.executeAssign(store, cmd);
  379. } else if (cmd instanceof Commands.Break) {
  380. return this.executeBreak(store, cmd);
  381. } else if (cmd instanceof Commands.Return) {
  382. return this.executeReturn(store, cmd);
  383. } else if (cmd instanceof Commands.IfThenElse) {
  384. return this.executeIfThenElse(store, cmd);
  385. } else if (cmd instanceof Commands.RepeatUntil) {
  386. return this.executeRepeatUntil(store, cmd);
  387. } else if (cmd instanceof Commands.While) {
  388. return this.executeWhile(store, cmd);
  389. } else if (cmd instanceof Commands.For) {
  390. return this.executeFor(store, cmd);
  391. } else if (cmd instanceof Commands.Switch) {
  392. return this.executeSwitch(store, cmd);
  393. } else if (cmd instanceof Expressions.FunctionCall) {
  394. return this.executeFunctionCall(store, cmd);
  395. } else if (cmd instanceof Commands.SysCall) {
  396. return this.executeSysCall(store, cmd);
  397. } else {
  398. throw ProcessorErrorFactory.unknown_command(cmd.sourceInfo);
  399. }
  400. }
  401. /**
  402. *
  403. * @param {Store} store
  404. * @param {Commands.SysCall} cmd
  405. *
  406. * @returns {Promise<Store>}
  407. */
  408. async executeSysCall (store, cmd) {
  409. const func = cmd.langFunc.bind(this);
  410. return func(store, cmd);
  411. }
  412. /**
  413. *
  414. * @param {Store} store
  415. * @param {Commands.FunctionCall} cmd
  416. *
  417. * @returns {Promise<Store>}
  418. */
  419. async executeFunctionCall (store, cmd) {
  420. let func = null;
  421. if (cmd.isMainCall) {
  422. func = this.findMainFunction();
  423. } else {
  424. func = this.findFunction(cmd.id);
  425. }
  426. this.function_call_stack.push(cmd.sourceInfo);
  427. const sto = await this.runFunction(func, cmd.actualParameters, store);
  428. sto.destroy();
  429. if (
  430. !Types.VOID.isCompatible(func.returnType) &&
  431. sto.mode !== Modes.RETURN
  432. ) {
  433. const funcName =
  434. func.name === IVProgProcessor.MAIN_INTERNAL_ID
  435. ? LanguageDefinedFunction.getMainFunctionName()
  436. : func.name;
  437. throw ProcessorErrorFactory.function_no_return(funcName);
  438. } else {
  439. this.function_call_stack.pop();
  440. return store;
  441. }
  442. }
  443. /**
  444. *
  445. * @param {Store} store
  446. * @param {Commands.Switch} cmd
  447. *
  448. * @returns {Promise<Store>}
  449. */
  450. async executeSwitch (store, cmd) {
  451. this.context.push(Context.BREAKABLE);
  452. const switchCases = cmd.cases;
  453. let lastStore = store;
  454. let lastCaseCheckResult = false;
  455. for (
  456. let i = 0;
  457. i < switchCases.length && !this.ignoreSwitchCases(lastStore);
  458. i += 1
  459. ) {
  460. const switchCase = switchCases[i];
  461. if (lastCaseCheckResult || switchCase.isDefault) {
  462. lastStore = await this.executeCommands(lastStore, switchCase.commands);
  463. } else {
  464. const equalityInfixApp = new Expressions.InfixApp(
  465. Operators.EQ,
  466. cmd.expression,
  467. switchCase.expression
  468. );
  469. equalityInfixApp.sourceInfo = switchCase.sourceInfo;
  470. const result = await this.evaluateExpression(
  471. lastStore,
  472. equalityInfixApp
  473. );
  474. if (result.get()) {
  475. lastStore = await this.executeCommands(
  476. lastStore,
  477. switchCase.commands
  478. );
  479. }
  480. lastCaseCheckResult = result.get();
  481. }
  482. }
  483. this.context.pop();
  484. if (lastStore.mode === Modes.BREAK) {
  485. lastStore.mode = Modes.RUN;
  486. }
  487. return lastStore;
  488. }
  489. /**
  490. *
  491. * @param {Store} store
  492. * @param {Commands.For} cmd
  493. *
  494. * @returns {Promise<Store>}
  495. */
  496. async executeFor (store, cmd) {
  497. //BEGIN for -> while rewrite
  498. const initCmd = new Commands.Assign(cmd.for_id.id, cmd.for_from);
  499. initCmd.sourceInfo = cmd.sourceInfo;
  500. // Assume for is iterating forward and that pass is not missing
  501. let passValue = cmd.for_pass;
  502. let condition = new Expressions.InfixApp(
  503. Operators.LT,
  504. cmd.for_id,
  505. cmd.for_to
  506. );
  507. if (cmd.for_pass == null) {
  508. passValue = new Expressions.IntLiteral(toInt(1));
  509. const checkEndGTBegin = await this.evaluateExpression(
  510. store,
  511. new Expressions.InfixApp(Operators.GE, cmd.for_to, cmd.for_from)
  512. );
  513. if (!checkEndGTBegin.get()) {
  514. passValue = new Expressions.IntLiteral(toInt(-1));
  515. condition = new Expressions.InfixApp(
  516. Operators.GT,
  517. cmd.for_id,
  518. cmd.for_to
  519. );
  520. }
  521. } else {
  522. const isForward = await this.evaluateExpression(
  523. store,
  524. new Expressions.InfixApp(
  525. Operators.GE,
  526. cmd.for_pass,
  527. new Expressions.IntLiteral(toInt(0))
  528. )
  529. );
  530. if (!isForward.get()) {
  531. condition = new Expressions.InfixApp(
  532. Operators.GT,
  533. cmd.for_id,
  534. cmd.for_to
  535. );
  536. }
  537. }
  538. condition.sourceInfo = cmd.sourceInfo;
  539. const increment = new Commands.Assign(
  540. cmd.for_id.id,
  541. new Expressions.InfixApp(Operators.ADD, cmd.for_id, passValue)
  542. );
  543. increment.sourceInfo = cmd.sourceInfo;
  544. const whileBlock = new Commands.CommandBlock(
  545. [],
  546. cmd.commands.concat(increment)
  547. );
  548. const forAsWhile = new Commands.While(condition, whileBlock);
  549. forAsWhile.sourceInfo = cmd.sourceInfo;
  550. //END for -> while rewrite
  551. const newCmdList = [initCmd, forAsWhile];
  552. return this.executeCommands(store, newCmdList);
  553. }
  554. /**
  555. *
  556. * @param {Store} store
  557. * @param {Commands.RepeatUntil} cmd
  558. *
  559. * @returns {Promise<Store>}
  560. */
  561. async executeRepeatUntil (store, cmd) {
  562. this.context.push(Context.BREAKABLE);
  563. const sto = await this.executeCommands(store, cmd.commands);
  564. if (sto.mode === Modes.BREAK) {
  565. this.context.pop();
  566. sto.mode = Modes.RUN;
  567. return sto;
  568. }
  569. const checkCondition = await this.evaluateExpression(sto, cmd.expression);
  570. if (!checkCondition.type.isCompatible(Types.BOOLEAN)) {
  571. throw ProcessorErrorFactory.loop_condition_type_full(cmd.sourceInfo);
  572. }
  573. this.context.pop();
  574. if (checkCondition.get()) {
  575. return sto;
  576. } else {
  577. return this.executeCommand(sto, cmd);
  578. }
  579. }
  580. /**
  581. *
  582. * @param {Store} store
  583. * @param {Commands.While} cmd
  584. *
  585. * @returns {Promise<Store>}
  586. */
  587. async executeWhile (store, cmd) {
  588. this.context.push(Context.BREAKABLE);
  589. const checkCondition = await this.evaluateExpression(store, cmd.expression);
  590. if (!checkCondition.type.isCompatible(Types.BOOLEAN)) {
  591. throw ProcessorErrorFactory.loop_condition_type_full(
  592. cmd.expression.toString(),
  593. cmd.sourceInfo
  594. );
  595. }
  596. if (checkCondition.get()) {
  597. const sto = await this.executeCommands(store, cmd.commands);
  598. this.context.pop();
  599. if (sto.mode === Modes.BREAK) {
  600. sto.mode = Modes.RUN;
  601. return sto;
  602. }
  603. return this.executeCommand(sto, cmd);
  604. } else {
  605. this.context.pop();
  606. return store;
  607. }
  608. }
  609. /**
  610. *
  611. * @param {Store} store
  612. * @param {Commands.IfThenElse} cmd
  613. *
  614. * @returns {Promise<Store>}
  615. */
  616. async executeIfThenElse (store, cmd) {
  617. const isTrue = await this.evaluateExpression(store, cmd.condition);
  618. if (!isTrue.type.isCompatible(Types.BOOLEAN)) {
  619. throw ProcessorErrorFactory.if_condition_type_full(
  620. cmd.condition.toString(),
  621. cmd.sourceInfo
  622. );
  623. }
  624. if (isTrue.get()) {
  625. return this.executeCommands(store, cmd.ifTrue.commands);
  626. } else if (cmd.ifFalse !== null) {
  627. if (cmd.ifFalse instanceof Commands.IfThenElse) {
  628. return this.executeCommand(store, cmd.ifFalse);
  629. } else {
  630. return this.executeCommands(store, cmd.ifFalse.commands);
  631. }
  632. } else {
  633. return store;
  634. }
  635. }
  636. /**
  637. *
  638. * @param {Store} store
  639. * @param {Commands.Return} cmd
  640. *
  641. * @returns {Promise<Store>}
  642. */
  643. async executeReturn (store, cmd) {
  644. const funcName =
  645. store.name === IVProgProcessor.MAIN_INTERNAL_ID
  646. ? LanguageDefinedFunction.getMainFunctionName()
  647. : store.name;
  648. // console.log(funcName, store.name === IVProgProcessor.MAIN_INTERNAL_ID);
  649. const func = this.findFunction(store.name);
  650. const funcType = func.returnType;
  651. const value = await this.evaluateExpression(store, cmd.expression);
  652. if (value === null && funcType.isCompatible(Types.VOID)) {
  653. store.mode = Modes.RETURN;
  654. return store;
  655. }
  656. let real_value = value;
  657. if (value === null || !funcType.isCompatible(value.type)) {
  658. if (
  659. !Config.enable_type_casting ||
  660. !Store.canImplicitTypeCast(funcType, value.type)
  661. ) {
  662. const stringInfo = funcType.stringInfo();
  663. const info = stringInfo[0];
  664. throw ProcessorErrorFactory.invalid_return_type_full(
  665. funcName,
  666. info.type,
  667. info.dim,
  668. cmd.sourceInfo
  669. );
  670. }
  671. real_value = Store.doImplicitCasting(funcType, value);
  672. }
  673. store.insertStore("$", real_value);
  674. store.mode = Modes.RETURN;
  675. return store;
  676. }
  677. /**
  678. *
  679. * @param {Store} store
  680. * @param {Commands.Break} cmd
  681. *
  682. * @returns {Promise<Store>}
  683. */
  684. async executeBreak (store, cmd) {
  685. if (this.checkContext(Context.BREAKABLE)) {
  686. store.mode = Modes.BREAK;
  687. return store;
  688. } else {
  689. throw ProcessorErrorFactory.unexpected_break_command_full(cmd.sourceInfo);
  690. }
  691. }
  692. /**
  693. *
  694. * @param {Store} store
  695. * @param {Commands.Assign} cmd
  696. *
  697. * @returns {Promise<Store>}
  698. */
  699. async executeAssign (store, cmd) {
  700. const inStore = store.applyStore(cmd.id);
  701. if (inStore.isConst) {
  702. throw ProcessorErrorFactory.invalid_const_assignment_full(
  703. cmd.id,
  704. cmd.sourceInfo
  705. );
  706. }
  707. const value = await this.evaluateExpression(store, cmd.expression);
  708. let realValue = value;
  709. if (!inStore.type.isCompatible(realValue.type)) {
  710. if (
  711. Config.enable_type_casting &&
  712. Store.canImplicitTypeCast(inStore.type, value.type)
  713. ) {
  714. realValue = Store.doImplicitCasting(inStore.type, realValue);
  715. } else {
  716. const stringInfo = inStore.type.stringInfo();
  717. const info = stringInfo[0];
  718. const exp_type_string_info = value.type.stringInfo();
  719. const exp_type_info = exp_type_string_info[0];
  720. const exp = cmd.expression.toString();
  721. throw ProcessorErrorFactory.incompatible_types_full(
  722. info.type,
  723. info.dim,
  724. exp_type_info.type,
  725. exp_type_info.dim,
  726. exp,
  727. cmd.sourceInfo
  728. );
  729. }
  730. }
  731. if (inStore instanceof ArrayStoreValue) {
  732. const columns = realValue.columns == null ? 0 : realValue.columns;
  733. if (inStore.lines !== realValue.lines || inStore.columns !== columns) {
  734. const exp = cmd.expression.toString();
  735. if (inStore.isVector()) {
  736. throw ProcessorErrorFactory.invalid_vector_assignment_full(
  737. cmd.id,
  738. inStore.lines,
  739. exp,
  740. realValue.lines,
  741. cmd.sourceInfo
  742. );
  743. } else {
  744. throw ProcessorErrorFactory.invalid_matrix_assignment_full(
  745. cmd.id,
  746. inStore.lines,
  747. inStore.columns,
  748. exp,
  749. realValue.lines,
  750. realValue.columns,
  751. cmd.sourceInfo
  752. );
  753. }
  754. }
  755. }
  756. store.updateStore(cmd.id, realValue);
  757. return store;
  758. }
  759. /**
  760. *
  761. * @param {Store} store
  762. * @param {Commands.ArrayIndexAssign} cmd
  763. *
  764. * @returns {Promise<Store>}
  765. */
  766. async executeArrayIndexAssign (store, cmd) {
  767. const mustBeArray = store.applyStore(cmd.id);
  768. let used_dims = 0;
  769. if (mustBeArray.isConst) {
  770. throw ProcessorErrorFactory.invalid_const_assignment_full(
  771. cmd.id,
  772. cmd.sourceInfo
  773. );
  774. }
  775. if (!(mustBeArray.type instanceof ArrayType)) {
  776. throw ProcessorErrorFactory.invalid_array_access_full(
  777. cmd.id,
  778. cmd.sourceInfo
  779. );
  780. }
  781. const lineSV = await this.evaluateExpression(store, cmd.line);
  782. if (!Types.INTEGER.isCompatible(lineSV.type)) {
  783. throw ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo);
  784. }
  785. used_dims += 1;
  786. const line = lineSV.get().toNumber();
  787. const columnSV = await this.evaluateExpression(store, cmd.column);
  788. let column = null;
  789. if (columnSV != null) {
  790. if (!Types.INTEGER.isCompatible(columnSV.type)) {
  791. throw ProcessorErrorFactory.array_dimension_not_int_full(
  792. cmd.sourceInfo
  793. );
  794. }
  795. column = columnSV.get().toNumber();
  796. used_dims += 1;
  797. }
  798. const value = await this.evaluateExpression(store, cmd.expression);
  799. let actualValue = value;
  800. if (line >= mustBeArray.lines) {
  801. if (mustBeArray.isVector) {
  802. throw ProcessorErrorFactory.vector_line_outbounds_full(
  803. cmd.id,
  804. line,
  805. mustBeArray.lines,
  806. cmd.sourceInfo
  807. );
  808. } else {
  809. throw ProcessorErrorFactory.matrix_line_outbounds_full(
  810. cmd.id,
  811. line,
  812. mustBeArray.lines,
  813. cmd.sourceInfo
  814. );
  815. }
  816. } else if (line < 0) {
  817. throw ProcessorErrorFactory.array_dimension_not_positive_full(
  818. cmd.sourceInfo
  819. );
  820. }
  821. if (column != null && mustBeArray.columns === 0) {
  822. throw ProcessorErrorFactory.vector_not_matrix_full(
  823. cmd.id,
  824. cmd.sourceInfo
  825. );
  826. }
  827. if (column != null) {
  828. if (column >= mustBeArray.columns) {
  829. throw ProcessorErrorFactory.matrix_column_outbounds_full(
  830. cmd.id,
  831. column,
  832. mustBeArray.columns,
  833. cmd.sourceInfo
  834. );
  835. } else if (column < 0) {
  836. throw ProcessorErrorFactory.array_dimension_not_positive_full(
  837. cmd.sourceInfo
  838. );
  839. }
  840. }
  841. if (!mustBeArray.type.canAccept(value.type, used_dims)) {
  842. if (
  843. !Config.enable_type_casting ||
  844. !Store.canImplicitTypeCast(mustBeArray.type.innerType, value.type)
  845. ) {
  846. const type = mustBeArray.type.innerType;
  847. const stringInfo = type.stringInfo();
  848. const info = stringInfo[0];
  849. const exp_type_string_info = value.type.stringInfo();
  850. const exp_type_info = exp_type_string_info[0];
  851. const exp = cmd.expression.toString();
  852. throw ProcessorErrorFactory.incompatible_types_full(
  853. info.type,
  854. info.dim,
  855. exp_type_info.type,
  856. exp_type_info.dim,
  857. exp,
  858. cmd.sourceInfo
  859. );
  860. }
  861. actualValue = Store.doImplicitCasting(mustBeArray.type.innerType, value);
  862. }
  863. const current_value = mustBeArray.getAt(line, column);
  864. if (current_value instanceof ArrayStoreValue) {
  865. if (
  866. current_value.lines !== actualValue.lines ||
  867. current_value.columns !== actualValue.columns
  868. ) {
  869. const exp = cmd.expression.toString();
  870. throw ProcessorErrorFactory.invalid_matrix_index_assign_full(
  871. cmd.id,
  872. line,
  873. current_value.lines,
  874. exp,
  875. actualValue.lines,
  876. cmd.sourceInfo
  877. );
  878. }
  879. }
  880. return store.updateStoreArray(cmd.id, actualValue, line, column);
  881. }
  882. /**
  883. *
  884. * @param {Store} store
  885. * @param {Commands.Declaration} cmd
  886. *
  887. * @returns {Promise<Store>}
  888. */
  889. async executeDeclaration (store, cmd) {
  890. if (cmd instanceof Commands.ArrayDeclaration) {
  891. return this.executeArrayDeclaration(store, cmd);
  892. } else {
  893. let temp = new StoreValue(cmd.type, null, null, cmd.isConst);
  894. if (cmd.initial !== null) {
  895. const value = await this.evaluateExpression(store, cmd.initial);
  896. let realValue = value;
  897. if (!value.type.isCompatible(cmd.type)) {
  898. if (
  899. Config.enable_type_casting &&
  900. Store.canImplicitTypeCast(cmd.type, value.type)
  901. ) {
  902. realValue = Store.doImplicitCasting(cmd.type, realValue);
  903. } else {
  904. const stringInfo = value.type.stringInfo();
  905. const info = stringInfo[0];
  906. const exp_type_string_info = value.type.stringInfo();
  907. const exp_type_info = exp_type_string_info[0];
  908. const exp = cmd.expression.toString();
  909. throw ProcessorErrorFactory.incompatible_types_full(
  910. info.type,
  911. info.dim,
  912. exp_type_info.type,
  913. exp_type_info.dim,
  914. exp,
  915. cmd.sourceInfo
  916. );
  917. }
  918. }
  919. temp = new StoreValue(cmd.type, realValue.get(), null, cmd.isConst);
  920. }
  921. store.insertStore(cmd.id, temp);
  922. return store;
  923. }
  924. }
  925. /**
  926. *
  927. * @param {Store} store
  928. * @param {Commands.ArrayDeclaration} cmd
  929. *
  930. * @returns {Promise<Store>}
  931. */
  932. async executeArrayDeclaration (store, cmd) {
  933. const linesSV = await this.evaluateExpression(store, cmd.lines);
  934. if (!Types.INTEGER.isCompatible(linesSV.type)) {
  935. throw ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo);
  936. }
  937. const line = linesSV.get().toNumber();
  938. const columnsSV = await this.evaluateExpression(store, cmd.columns);
  939. let column = null;
  940. if (columnsSV !== null) {
  941. if (!Types.INTEGER.isCompatible(columnsSV.type)) {
  942. throw ProcessorErrorFactory.array_dimension_not_int_full(
  943. cmd.sourceInfo
  944. );
  945. }
  946. column = columnsSV.get().toNumber();
  947. if (column < 0) {
  948. throw ProcessorErrorFactory.array_dimension_not_positive_full(
  949. cmd.sourceInfo
  950. );
  951. }
  952. }
  953. let temp = new ArrayStoreValue(
  954. cmd.type,
  955. [],
  956. line,
  957. column,
  958. null,
  959. cmd.isConst
  960. );
  961. if (cmd.initial !== null) {
  962. // array can only be initialized by a literal....
  963. const valueList = await this.evaluateArrayLiteral(
  964. store,
  965. cmd.initial,
  966. cmd.type,
  967. line,
  968. column
  969. );
  970. temp = new ArrayStoreValue(
  971. cmd.type,
  972. valueList,
  973. line,
  974. column,
  975. null,
  976. cmd.isConst
  977. );
  978. }
  979. store.insertStore(cmd.id, temp);
  980. return store;
  981. }
  982. /**
  983. *
  984. * @param {Store} store
  985. * @param {Expression} exp
  986. *
  987. * @returns {Promise<import('./store/value/istore_value').IStoreValue>}
  988. */
  989. async evaluateExpression (store, exp) {
  990. this.instruction_count += 1;
  991. if (this.instruction_count % Config.suspend_threshold == 0) {
  992. //every Config.suspend_threshold instruction should briefly delay its execution in order to allow the browser to process other things
  993. await Utils.sleep(3);
  994. }
  995. if (this.mode === Modes.ABORT) {
  996. throw LocalizedStrings.getMessage("aborted_execution");
  997. }
  998. if (this.instruction_count >= Config.max_instruction_count) {
  999. throw new Error(
  1000. "Número de instruções excedeu o limite definido. Verifique se seu código não possui laços infinitos ou muitas chamadas de funções recursivas."
  1001. );
  1002. }
  1003. if (exp instanceof Expressions.UnaryApp) {
  1004. return this.evaluateUnaryApp(store, exp);
  1005. } else if (exp instanceof Expressions.InfixApp) {
  1006. return this.evaluateInfixApp(store, exp);
  1007. } else if (exp instanceof Expressions.ArrayAccess) {
  1008. return this.evaluateArrayAccess(store, exp);
  1009. } else if (exp instanceof Expressions.VariableLiteral) {
  1010. return this.evaluateVariableLiteral(store, exp);
  1011. } else if (exp instanceof Expressions.IntLiteral) {
  1012. return this.evaluateLiteral(store, exp);
  1013. } else if (exp instanceof Expressions.RealLiteral) {
  1014. return this.evaluateLiteral(store, exp);
  1015. } else if (exp instanceof Expressions.BoolLiteral) {
  1016. return this.evaluateLiteral(store, exp);
  1017. } else if (exp instanceof Expressions.StringLiteral) {
  1018. return this.evaluateLiteral(store, exp);
  1019. } else if (exp instanceof Expressions.CharLiteral) {
  1020. return this.evaluateLiteral(store, exp);
  1021. } else if (exp instanceof Expressions.ArrayLiteral) {
  1022. throw new Error(
  1023. "Internal Error: The system should not eval an array literal."
  1024. );
  1025. } else if (exp instanceof Expressions.FunctionCall) {
  1026. return this.evaluateFunctionCall(store, exp);
  1027. }
  1028. return null;
  1029. }
  1030. async evaluateFunctionCall (store, exp) {
  1031. if (exp.isMainCall) {
  1032. throw ProcessorErrorFactory.void_in_expression_full(
  1033. LanguageDefinedFunction.getMainFunctionName(),
  1034. exp.sourceInfo
  1035. );
  1036. }
  1037. const func = this.findFunction(exp.id);
  1038. if (Types.VOID.isCompatible(func.returnType)) {
  1039. throw ProcessorErrorFactory.void_in_expression_full(
  1040. exp.id,
  1041. exp.sourceInfo
  1042. );
  1043. }
  1044. if (this.function_call_stack.length >= Config.max_call_stack) {
  1045. throw ProcessorErrorFactory.exceeded_recursive_calls(exp.sourceInfo);
  1046. }
  1047. this.function_call_stack.push(exp.sourceInfo);
  1048. const sto = await this.runFunction(func, exp.actualParameters, store);
  1049. if (sto.mode !== Modes.RETURN) {
  1050. throw new Error(
  1051. "!!!Internal error: the function that was called did not have a return command or did not set the store mode properly -> " +
  1052. exp.id
  1053. );
  1054. }
  1055. const val = sto.applyStore("$");
  1056. sto.destroy();
  1057. this.function_call_stack.pop();
  1058. return val;
  1059. }
  1060. /**
  1061. *
  1062. * @param {Store} store
  1063. * @param {Expressions.ArrayLiteral} exp
  1064. * @param {ArrayType} type
  1065. *
  1066. * @returns {Promise<StoreValue[]>}
  1067. */
  1068. async evaluateArrayLiteral (store, exp, type, lines, columns) {
  1069. if (!exp.isVector) {
  1070. if (columns == null) {
  1071. throw new Error(
  1072. "This should never happen: Vector cannot be initialized by a matrix"
  1073. );
  1074. }
  1075. const storeValueMatrix = await this.evaluateMatrix(
  1076. store,
  1077. exp,
  1078. type,
  1079. lines,
  1080. columns
  1081. );
  1082. return storeValueMatrix.reduce((prev, next) => prev.concat(next), []);
  1083. } else {
  1084. if (columns != null) {
  1085. throw new Error(
  1086. "This should never happen: Matrix cannot be initialized by a vector"
  1087. );
  1088. }
  1089. return this.evaluateVector(store, exp, type, lines);
  1090. }
  1091. }
  1092. /**
  1093. * Evalautes a list of literals and expression composing the vector
  1094. * @param {Store} store
  1095. * @param {Expressions.ArrayLiteral} exps
  1096. * @param {ArrayType} type
  1097. * @param {number} n_elements
  1098. *
  1099. * @returns {Promise<StoreValue[]>} store object list
  1100. */
  1101. async evaluateVector (store, exps, type, n_elements) {
  1102. const values = exps.value;
  1103. if (n_elements !== values.length) {
  1104. throw ProcessorErrorFactory.invalid_number_elements_vector(
  1105. n_elements,
  1106. exps.toString(),
  1107. values.length,
  1108. exps.sourceInfo
  1109. );
  1110. }
  1111. const actualValues = await Promise.all(
  1112. values.map((exp) => this.evaluateExpression(store, exp))
  1113. );
  1114. return actualValues.map((v, index) => {
  1115. if (!type.canAccept(v.type, 1)) {
  1116. if (
  1117. !Config.enable_type_casting ||
  1118. !Store.canImplicitTypeCast(type.innerType, v.type)
  1119. ) {
  1120. // const stringInfo = v.type.stringInfo();
  1121. // const info = stringInfo[0];
  1122. const exp_str = values[index].toString();
  1123. // TODO - fix error message
  1124. throw ProcessorErrorFactory.invalid_array_literal_type_full(
  1125. exp_str,
  1126. values[index].sourceInfo
  1127. );
  1128. }
  1129. const newValue = Store.doImplicitCasting(type.innerType, v);
  1130. return newValue;
  1131. }
  1132. return v;
  1133. });
  1134. }
  1135. /**
  1136. * Evaluates a list of array literals composing the matrix
  1137. * @param {Store} store
  1138. * @param {Expressions.ArrayLiteral} exps
  1139. * @param {ArrayType} type
  1140. *
  1141. * @returns {Promise<StoreValue[][]>}
  1142. */
  1143. async evaluateMatrix (store, exps, type, lines, columns) {
  1144. const values = exps.value;
  1145. if (values.length !== lines) {
  1146. throw ProcessorErrorFactory.invalid_number_lines_matrix(
  1147. lines,
  1148. exps.toString(),
  1149. values.length,
  1150. exps.sourceInfo
  1151. );
  1152. }
  1153. const vectors = values.map((vector) => {
  1154. const vec_type = new ArrayType(type.innerType, 1);
  1155. return this.evaluateVector(store, vector, vec_type, columns);
  1156. });
  1157. return await Promise.all(vectors);
  1158. }
  1159. /**
  1160. *
  1161. * @param {Store} _
  1162. * @param {import('../ast/expressions/literal').Literal} exp
  1163. *
  1164. * @returns {import('./store/value/istore_value').IStoreValue}
  1165. */
  1166. async evaluateLiteral (_, exp) {
  1167. return new StoreValue(exp.type, exp.value);
  1168. }
  1169. /**
  1170. *
  1171. * @param {Store} store
  1172. * @param {Expressions.VariableLiteral} exp
  1173. *
  1174. * @returns {import('./store/value/istore_value').IStoreValue}
  1175. */
  1176. async evaluateVariableLiteral (store, exp) {
  1177. const val = store.applyStore(exp.id);
  1178. return val;
  1179. }
  1180. /**
  1181. *
  1182. * @param {Store} store
  1183. * @param {Expressions.ArrayAccess} exp
  1184. *
  1185. * @returns {import('./store/value/istore_value').IStoreValue}
  1186. */
  1187. async evaluateArrayAccess (store, exp) {
  1188. const mustBeArray = store.getStoreObject(exp.id);
  1189. if (!(mustBeArray.type instanceof ArrayType)) {
  1190. throw ProcessorErrorFactory.invalid_array_access_full(
  1191. exp.id,
  1192. exp.sourceInfo
  1193. );
  1194. }
  1195. const lineSV = await this.evaluateExpression(store, exp.line);
  1196. if (!Types.INTEGER.isCompatible(lineSV.type)) {
  1197. throw ProcessorErrorFactory.array_dimension_not_int_full(exp.sourceInfo);
  1198. }
  1199. const line = lineSV.get().toNumber();
  1200. const columnSV = await this.evaluateExpression(store, exp.column);
  1201. let column = null;
  1202. if (columnSV !== null) {
  1203. if (!Types.INTEGER.isCompatible(columnSV.type)) {
  1204. throw ProcessorErrorFactory.array_dimension_not_int_full(
  1205. exp.sourceInfo
  1206. );
  1207. }
  1208. column = columnSV.get().toNumber();
  1209. }
  1210. if (line >= mustBeArray.lines) {
  1211. if (mustBeArray.isVector) {
  1212. throw ProcessorErrorFactory.vector_line_outbounds_full(
  1213. exp.id,
  1214. line,
  1215. mustBeArray.lines,
  1216. exp.sourceInfo
  1217. );
  1218. } else {
  1219. throw ProcessorErrorFactory.matrix_line_outbounds_full(
  1220. exp.id,
  1221. line,
  1222. mustBeArray.lines,
  1223. exp.sourceInfo
  1224. );
  1225. }
  1226. } else if (line < 0) {
  1227. throw ProcessorErrorFactory.array_dimension_not_positive_full(
  1228. exp.sourceInfo
  1229. );
  1230. }
  1231. if (column !== null && mustBeArray.columns === 0) {
  1232. throw ProcessorErrorFactory.vector_not_matrix_full(
  1233. exp.id,
  1234. exp.sourceInfo
  1235. );
  1236. }
  1237. if (column !== null) {
  1238. if (column >= mustBeArray.columns) {
  1239. throw ProcessorErrorFactory.matrix_column_outbounds_full(
  1240. exp.id,
  1241. column,
  1242. mustBeArray.columns,
  1243. exp.sourceInfo
  1244. );
  1245. } else if (column < 0) {
  1246. throw ProcessorErrorFactory.array_dimension_not_positive_full(
  1247. exp.sourceInfo
  1248. );
  1249. }
  1250. }
  1251. const result = mustBeArray.getAt(line, column);
  1252. const type = mustBeArray.type.innerType;
  1253. if (Array.isArray(result)) {
  1254. const values = result.map((val, col) => {
  1255. return new StoreValueAddress(
  1256. type,
  1257. val,
  1258. line,
  1259. col,
  1260. mustBeArray.id,
  1261. mustBeArray.readOnly
  1262. );
  1263. });
  1264. return new ArrayStoreValue(
  1265. new ArrayType(type, 1),
  1266. values,
  1267. mustBeArray.columns,
  1268. null,
  1269. mustBeArray.id,
  1270. mustBeArray.readOnly
  1271. );
  1272. } else {
  1273. return new StoreValueAddress(
  1274. type,
  1275. result,
  1276. line,
  1277. column,
  1278. mustBeArray.id,
  1279. mustBeArray.readOnly
  1280. );
  1281. }
  1282. }
  1283. /**
  1284. *
  1285. * @param {Store} store
  1286. * @param {Expressions.UnaryApp} unaryApp
  1287. *
  1288. * @returns {import('./store/value/istore_value').IStoreValue}
  1289. */
  1290. async evaluateUnaryApp (store, unaryApp) {
  1291. const left = await this.evaluateExpression(store, unaryApp.left);
  1292. const resultType = resultTypeAfterUnaryOp(unaryApp.op, left.type);
  1293. if (Types.UNDEFINED.isCompatible(resultType)) {
  1294. const stringInfo = left.type.stringInfo();
  1295. const info = stringInfo[0];
  1296. throw ProcessorErrorFactory.invalid_unary_op_full(
  1297. unaryApp.op,
  1298. info.type,
  1299. info.dim,
  1300. unaryApp.sourceInfo
  1301. );
  1302. }
  1303. switch (unaryApp.op.ord) {
  1304. case Operators.ADD.ord:
  1305. return new StoreValue(resultType, left.get());
  1306. case Operators.SUB.ord:
  1307. return new StoreValue(resultType, left.get().negated());
  1308. case Operators.NOT.ord:
  1309. return new StoreValue(resultType, !left.get());
  1310. default:
  1311. throw new RuntimeError("!!!Critical Invalid UnaryApp " + unaryApp.op);
  1312. }
  1313. }
  1314. /**
  1315. *
  1316. * @param {Store} store
  1317. * @param {Expressions.InfixApp} infixApp
  1318. *
  1319. * @returns {import('./store/value/istore_value').IStoreValue}
  1320. */
  1321. async evaluateInfixApp (store, infixApp) {
  1322. const left = await this.evaluateExpression(store, infixApp.left);
  1323. const right = await this.evaluateExpression(store, infixApp.right);
  1324. let shouldImplicitCast = false;
  1325. let resultType = resultTypeAfterInfixOp(infixApp.op, left.type, right.type);
  1326. if (Types.UNDEFINED.isCompatible(resultType)) {
  1327. if (
  1328. Config.enable_type_casting &&
  1329. Store.canImplicitTypeCast(left.type, right.type)
  1330. ) {
  1331. shouldImplicitCast = true;
  1332. } else {
  1333. const stringInfoLeft = left.type.stringInfo();
  1334. const infoLeft = stringInfoLeft[0];
  1335. const stringInfoRight = right.type.stringInfo();
  1336. const infoRight = stringInfoRight[0];
  1337. throw ProcessorErrorFactory.invalid_infix_op_full(
  1338. infixApp.op,
  1339. infoLeft.type,
  1340. infoLeft.dim,
  1341. infoRight.type,
  1342. infoRight.dim,
  1343. infixApp.sourceInfo
  1344. );
  1345. }
  1346. }
  1347. let result = null;
  1348. switch (infixApp.op.ord) {
  1349. case Operators.ADD.ord: {
  1350. if (Types.STRING.isCompatible(left.type)) {
  1351. const rightStr = convertToString(right.get(), right.type);
  1352. return new StoreValue(resultType, left.get() + rightStr);
  1353. } else if (Types.STRING.isCompatible(right.type)) {
  1354. const leftStr = convertToString(left.get(), left.type);
  1355. return new StoreValue(resultType, leftStr + right.get());
  1356. } else if (Types.CHAR.isCompatible(left.type)) {
  1357. const strLeft = convertToString(left.get(), left.type);
  1358. const strRight = convertToString(right.get(), right.type);
  1359. return new StoreValue(resultType, strLeft + strRight);
  1360. } else {
  1361. return new StoreValue(resultType, left.get().plus(right.get()));
  1362. }
  1363. }
  1364. case Operators.SUB.ord:
  1365. return new StoreValue(resultType, left.get().minus(right.get()));
  1366. case Operators.MULT.ord: {
  1367. result = left.get().times(right.get());
  1368. return new StoreValue(resultType, result);
  1369. }
  1370. case Operators.DIV.ord: {
  1371. if (right.get() == 0) {
  1372. throw ProcessorErrorFactory.divsion_by_zero_full(
  1373. infixApp.toString(),
  1374. infixApp.sourceInfo
  1375. );
  1376. }
  1377. if (Types.INTEGER.isCompatible(resultType))
  1378. result = left.get().divToInt(right.get());
  1379. else result = left.get().div(right.get());
  1380. return new StoreValue(resultType, result);
  1381. }
  1382. case Operators.MOD.ord: {
  1383. let leftValue = left.get();
  1384. let rightValue = right.get();
  1385. if (shouldImplicitCast) {
  1386. resultType = Types.INTEGER;
  1387. leftValue = leftValue.trunc();
  1388. rightValue = rightValue.trunc();
  1389. }
  1390. result = leftValue.modulo(rightValue);
  1391. return new StoreValue(resultType, result);
  1392. }
  1393. case Operators.GT.ord: {
  1394. let leftValue = left.get();
  1395. let rightValue = right.get();
  1396. if (Types.STRING.isCompatible(left.type)) {
  1397. result = leftValue.length > rightValue.length;
  1398. } else if (Types.CHAR.isCompatible(left.type)) {
  1399. result = leftValue.charCodeAt(0) > rightValue.charCodeAt(0);
  1400. } else {
  1401. if (shouldImplicitCast) {
  1402. resultType = Types.BOOLEAN;
  1403. leftValue = leftValue.trunc();
  1404. rightValue = rightValue.trunc();
  1405. }
  1406. result = leftValue.gt(rightValue);
  1407. }
  1408. return new StoreValue(resultType, result);
  1409. }
  1410. case Operators.GE.ord: {
  1411. let leftValue = left.get();
  1412. let rightValue = right.get();
  1413. if (Types.STRING.isCompatible(left.type)) {
  1414. result = leftValue.length >= rightValue.length;
  1415. } else if (Types.CHAR.isCompatible(left.type)) {
  1416. result = leftValue.charCodeAt(0) >= rightValue.charCodeAt(0);
  1417. } else {
  1418. if (shouldImplicitCast) {
  1419. resultType = Types.BOOLEAN;
  1420. leftValue = leftValue.trunc();
  1421. rightValue = rightValue.trunc();
  1422. }
  1423. result = leftValue.gte(rightValue);
  1424. }
  1425. return new StoreValue(resultType, result);
  1426. }
  1427. case Operators.LT.ord: {
  1428. let leftValue = left.get();
  1429. let rightValue = right.get();
  1430. if (Types.STRING.isCompatible(left.type)) {
  1431. result = leftValue.length < rightValue.length;
  1432. } else if (Types.CHAR.isCompatible(left.type)) {
  1433. result = leftValue.charCodeAt(0) < rightValue.charCodeAt(0);
  1434. } else {
  1435. if (shouldImplicitCast) {
  1436. resultType = Types.BOOLEAN;
  1437. leftValue = leftValue.trunc();
  1438. rightValue = rightValue.trunc();
  1439. }
  1440. result = leftValue.lt(rightValue);
  1441. }
  1442. return new StoreValue(resultType, result);
  1443. }
  1444. case Operators.LE.ord: {
  1445. let leftValue = left.get();
  1446. let rightValue = right.get();
  1447. if (Types.STRING.isCompatible(left.type)) {
  1448. result = leftValue.length <= rightValue.length;
  1449. } else if (Types.CHAR.isCompatible(left.type)) {
  1450. result = leftValue.charCodeAt(0) <= rightValue.charCodeAt(0);
  1451. } else {
  1452. if (shouldImplicitCast) {
  1453. resultType = Types.BOOLEAN;
  1454. leftValue = leftValue.trunc();
  1455. rightValue = rightValue.trunc();
  1456. }
  1457. result = leftValue.lte(rightValue);
  1458. }
  1459. return new StoreValue(resultType, result);
  1460. }
  1461. case Operators.EQ.ord: {
  1462. let leftValue = left.get();
  1463. let rightValue = right.get();
  1464. if (
  1465. Types.INTEGER.isCompatible(left.type) ||
  1466. Types.REAL.isCompatible(left.type)
  1467. ) {
  1468. if (shouldImplicitCast) {
  1469. resultType = Types.BOOLEAN;
  1470. leftValue = leftValue.trunc();
  1471. rightValue = rightValue.trunc();
  1472. }
  1473. result = leftValue.eq(rightValue);
  1474. } else {
  1475. result = leftValue === rightValue;
  1476. }
  1477. return new StoreValue(resultType, result);
  1478. }
  1479. case Operators.NEQ.ord: {
  1480. let leftValue = left.get();
  1481. let rightValue = right.get();
  1482. if (
  1483. Types.INTEGER.isCompatible(left.type) ||
  1484. Types.REAL.isCompatible(left.type)
  1485. ) {
  1486. if (shouldImplicitCast) {
  1487. resultType = Types.BOOLEAN;
  1488. leftValue = leftValue.trunc();
  1489. rightValue = rightValue.trunc();
  1490. }
  1491. result = !leftValue.eq(rightValue);
  1492. } else {
  1493. result = leftValue !== rightValue;
  1494. }
  1495. return new StoreValue(resultType, result);
  1496. }
  1497. case Operators.AND.ord:
  1498. return new StoreValue(resultType, left.get() && right.get());
  1499. case Operators.OR.ord:
  1500. return new StoreValue(resultType, left.get() || right.get());
  1501. default:
  1502. throw new RuntimeError("!!!Critical Invalid InfixApp " + infixApp.op);
  1503. }
  1504. }
  1505. }