ivprogProcessor.js 44 KB

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