ivprogProcessor.js 45 KB

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