ivprogProcessor.js 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  1. import { Store } from './store/store';
  2. import { StoreObjectArray } from './store/storeObjectArray';
  3. import { Modes } from './modes';
  4. import { Context } from './context';
  5. import { Types } from './../typeSystem/types';
  6. import { Operators } from './../ast/operators';
  7. import { LanguageDefinedFunction } from './definedFunctions';
  8. import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from './compatibilityTable';
  9. import * as Commands from './../ast/commands/';
  10. import * as Expressions from './../ast/expressions/';
  11. import { StoreObjectArrayAddress } from './store/storeObjectArrayAddress';
  12. import { StoreObjectArrayAddressRef } from './store/storeObjectArrayAddressRef';
  13. import { ArrayType } from './../typeSystem/array_type';
  14. import { convertToString } from '../typeSystem/parsers';
  15. import { Config } from '../util/config';
  16. import { ProcessorErrorFactory } from './error/processorErrorFactory';
  17. import { RuntimeError } from './error/runtimeError';
  18. import { Location } from '../memory/location';
  19. import { StoreValue } from './store/value/store_value';
  20. import { StoreValueRef } from './store/value/store_value_ref';
  21. import { ArrayStoreValue } from './store/value/array_store_value';
  22. import { ArrayStoreValueRef } from './store/value/array_store_value_ref';
  23. import { StoreValueAddress } from './store/value/store_value_address';
  24. export class IVProgProcessor {
  25. static get LOOP_TIMEOUT () {
  26. return Config.loopTimeout;
  27. }
  28. static set LOOP_TIMEOUT (ms) {
  29. Config.setConfig({loopTimeout: ms});
  30. }
  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.loopTimers = [];
  42. this.output = null;
  43. }
  44. registerInput (input) {
  45. if(this.input !== null)
  46. this.input = null;
  47. this.input = input;
  48. }
  49. registerOutput (output) {
  50. if(this.output !== null)
  51. this.output = null;
  52. this.output = output;
  53. }
  54. checkContext(context) {
  55. return this.context[this.context.length - 1] === context;
  56. }
  57. ignoreSwitchCases (store) {
  58. if (store.mode === Modes.RETURN) {
  59. return true;
  60. } else if (store.mode === Modes.BREAK) {
  61. return true;
  62. } else {
  63. return false;
  64. }
  65. }
  66. prepareState () {
  67. if(this.stores !== null) {
  68. for (let i = 0; i < this.stores.length; i++) {
  69. delete this.stores[i];
  70. }
  71. this.stores = null;
  72. }
  73. if(this.globalStore !== null)
  74. this.globalStore = null;
  75. this.globalStore = new Store("$global");
  76. this.stores = [this.globalStore];
  77. this.context = [Context.BASE];
  78. }
  79. interpretAST () {
  80. this.prepareState();
  81. Location.clear();
  82. return this.initGlobal().then( _ => {
  83. const mainFunc = this.findMainFunction();
  84. if(mainFunc === null) {
  85. throw ProcessorErrorFactory.main_missing();
  86. }
  87. return this.runFunction(mainFunc, [], this.globalStore);
  88. });
  89. }
  90. initGlobal () {
  91. if(!this.checkContext(Context.BASE)) {
  92. throw ProcessorErrorFactory.invalid_global_var();
  93. }
  94. return this.executeCommands(this.globalStore, this.ast.global);
  95. }
  96. findMainFunction () {
  97. return this.ast.functions.find(v => v.isMain);
  98. }
  99. findFunction (name) {
  100. if(name.match(/^\$.+$/)) {
  101. const fun = LanguageDefinedFunction.getFunction(name);
  102. if(!fun) {
  103. throw ProcessorErrorFactory.not_implemented(name);
  104. }
  105. return fun;
  106. } else {
  107. const val = this.ast.functions.find( v => v.name === name);
  108. if (!val) {
  109. throw ProcessorErrorFactory.function_missing(name);
  110. }
  111. return val;
  112. }
  113. }
  114. runFunction (func, actualParameters, store) {
  115. const funcName = func.isMain ? IVProgProcessor.MAIN_INTERNAL_ID : func.name;
  116. const funcStore = new Store(funcName);
  117. funcStore.extendStore(this.globalStore);
  118. let returnStoreObject = null;
  119. if(func.returnType instanceof ArrayType) {
  120. if(func.returnType.dimensions > 1) {
  121. returnStoreObject = new StoreObjectArray(func.returnType,-1,-1,[[]]);
  122. } else {
  123. returnStoreObject = new StoreObjectArray(func.returnType,-1,null,[]);
  124. }
  125. } else {
  126. returnStoreObject = new StoreValue(func.returnType, null, null);//new StoreObject(func.returnType, Location.allocate(null));
  127. }
  128. funcStore.insertStore('$', returnStoreObject);
  129. const newFuncStore$ = this.associateParameters(func.formalParameters, actualParameters, store, funcStore);
  130. const outerRef = this;
  131. return newFuncStore$.then(sto => {
  132. this.context.push(Context.FUNCTION);
  133. this.stores.push(sto);
  134. return this.executeCommands(sto, func.variablesDeclarations)
  135. .then(stoWithVars => outerRef.executeCommands(stoWithVars, func.commands)).then(finalSto => {
  136. outerRef.stores.pop();
  137. outerRef.context.pop();
  138. return finalSto;
  139. });
  140. });
  141. }
  142. associateParameters (formal_params, effective_params, caller_store, callee_store) {
  143. const funcName = callee_store.name === IVProgProcessor.MAIN_INTERNAL_ID ?
  144. LanguageDefinedFunction.getMainFunctionName() : callee_store.name;
  145. if (formal_params.length != effective_params.length) {
  146. throw ProcessorErrorFactory.invalid_parameters_size(funcName, formal_params.length, effective_params.length);
  147. }
  148. const promises$ = effective_params.map(actual_param => this.evaluateExpression(caller_store, actual_param));
  149. return Promise.all(promises$).then(values => {
  150. for (let i = 0; i < values.length; i++) {
  151. const sto_value = values[i];
  152. // console.log(callee_store.name);
  153. // console.log(sto_value);
  154. const exp = effective_params[i];
  155. let shouldTypeCast = false;
  156. const formalParameter = formal_params[i];
  157. if(!formalParameter.type.isCompatible(sto_value.type)) {
  158. if (Config.enable_type_casting && !formalParameter.byRef
  159. && Store.canImplicitTypeCast(formalParameter.type, sto_value.type)) {
  160. shouldTypeCast = true;
  161. } else {
  162. throw ProcessorErrorFactory.invalid_parameter_type(funcName, exp.toString());
  163. }
  164. }
  165. if(formalParameter.byRef && !sto_value.inStore()) {
  166. throw ProcessorErrorFactory.invalid_ref(funcName, exp.toString());
  167. }
  168. if(formalParameter.byRef) {
  169. const realObj = caller_store.getStoreObject(sto_value.id);
  170. let ref = null;
  171. if(sto_value instanceof ArrayStoreValue) {
  172. // it's a vector or matrix...
  173. const values = sto_value.get();
  174. const array_type = sto_value.type;
  175. const addresses = values.map( v => realObj.getLocAddressOf(v.line, v.column));
  176. const columns = sto_value.isVector() ? 0 : sto_value.columns;
  177. ref = new ArrayStoreValueRef(array_type, values, addresses, sto_value.lines, columns, realObj.id);
  178. } else {
  179. if(sto_value instanceof StoreValueAddress) {
  180. const line = sto_value.line;
  181. const column = sto_value.column;
  182. ref = new StoreValueRef(sto_value.type, sto_value.get(),
  183. realObj.getLocAddressOf(line, column), realObj.id);
  184. } else {
  185. ref = new StoreValueRef(sto_value.type, sto_value.get(), realObj.locAddress, realObj.id);
  186. }
  187. }
  188. callee_store.insertStore(formalParameter.id, ref);
  189. } else {
  190. let realValue = sto_value;
  191. if (shouldTypeCast) {
  192. realValue = Store.doImplicitCasting(formalParameter.type, realValue);
  193. }
  194. callee_store.insertStore(formalParameter.id, realValue);
  195. }
  196. }
  197. return callee_store;
  198. });
  199. }
  200. executeCommands (store, cmds) {
  201. // helper to partially apply a function, in this case executeCommand
  202. const outerRef = this;
  203. const partial = (fun, cmd) => (sto) => fun(sto, cmd);
  204. return cmds.reduce((lastCommand, next) => {
  205. const nextCommand = partial(outerRef.executeCommand.bind(outerRef), next);
  206. return lastCommand.then(nextCommand);
  207. }, Promise.resolve(store));
  208. }
  209. executeCommand (store, cmd) {
  210. if(this.forceKill) {
  211. return Promise.reject("FORCED_KILL!");
  212. } else if (store.mode === Modes.PAUSE) {
  213. return Promise.resolve(this.executeCommand(store, cmd));
  214. } else if(store.mode === Modes.RETURN) {
  215. return Promise.resolve(store);
  216. } else if(this.checkContext(Context.BREAKABLE) && store.mode === Modes.BREAK) {
  217. return Promise.resolve(store);
  218. }
  219. if (cmd instanceof Commands.Declaration) {
  220. return this.executeDeclaration(store, cmd);
  221. } else if (cmd instanceof Commands.ArrayIndexAssign) {
  222. return this.executeArrayIndexAssign(store, cmd);
  223. } else if (cmd instanceof Commands.Assign) {
  224. return this.executeAssign(store, cmd);
  225. } else if (cmd instanceof Commands.Break) {
  226. return this.executeBreak(store, cmd);
  227. } else if (cmd instanceof Commands.Return) {
  228. return this.executeReturn(store, cmd);
  229. } else if (cmd instanceof Commands.IfThenElse) {
  230. return this.executeIfThenElse(store, cmd);
  231. } else if (cmd instanceof Commands.DoWhile) {
  232. return this.executeDoWhile(store, cmd);
  233. } else if (cmd instanceof Commands.While) {
  234. return this.executeWhile(store, cmd);
  235. } else if (cmd instanceof Commands.For) {
  236. return this.executeFor(store, cmd);
  237. } else if (cmd instanceof Commands.Switch) {
  238. return this.executeSwitch(store, cmd);
  239. } else if (cmd instanceof Expressions.FunctionCall) {
  240. return this.executeFunctionCall(store, cmd);
  241. } else if (cmd instanceof Commands.SysCall) {
  242. return this.executeSysCall(store, cmd);
  243. } else {
  244. throw ProcessorErrorFactory.unknown_command(cmd.sourceInfo);
  245. }
  246. }
  247. executeSysCall (store, cmd) {
  248. const func = cmd.langFunc.bind(this);
  249. return func(store, cmd);
  250. }
  251. executeFunctionCall (store, cmd) {
  252. let func = null;
  253. if(cmd.isMainCall) {
  254. func = this.findMainFunction();
  255. } else {
  256. func = this.findFunction(cmd.id);
  257. }
  258. return this.runFunction(func, cmd.actualParameters, store)
  259. .then(sto => {
  260. sto.destroy();
  261. if(!Types.VOID.isCompatible(func.returnType) && sto.mode !== Modes.RETURN) {
  262. const funcName = func.name === IVProgProcessor.MAIN_INTERNAL_ID ?
  263. LanguageDefinedFunction.getMainFunctionName() : func.name;
  264. return Promise.reject(ProcessorErrorFactory.function_no_return(funcName));
  265. } else {
  266. return store;
  267. }
  268. });
  269. }
  270. executeSwitch (store, cmd) {
  271. this.context.push(Context.BREAKABLE);
  272. const outerRef = this;
  273. const caseSequence = cmd.cases.reduce( (prev,next) => {
  274. return prev.then( tuple => {
  275. if(outerRef.ignoreSwitchCases(tuple[1])) {
  276. return Promise.resolve(tuple);
  277. } else if(tuple[0] || next.isDefault) {
  278. return outerRef.executeCommands(tuple[1], next.commands)
  279. .then(nSto => Promise.resolve([true, nSto]));
  280. } else {
  281. const equalityInfixApp = new Expressions.InfixApp(Operators.EQ, cmd.expression, next.expression);
  282. equalityInfixApp.sourceInfo = next.sourceInfo;
  283. return outerRef.evaluateExpression(tuple[1],equalityInfixApp).then(stoObj => stoObj.get())
  284. .then(isEqual => {
  285. if (isEqual) {
  286. return this.executeCommands(tuple[1], next.commands)
  287. .then(nSto => Promise.resolve([true, nSto]));
  288. } else {
  289. return Promise.resolve(tuple);
  290. }
  291. });
  292. }
  293. });
  294. }, Promise.resolve([false, store]));
  295. return caseSequence.then(tuple => {
  296. outerRef.context.pop();
  297. const newStore = tuple[1];
  298. if (newStore.mode === Modes.BREAK) {
  299. newStore.mode = Modes.RUN;
  300. }
  301. return newStore;
  302. });
  303. }
  304. executeFor (store, cmd) {
  305. try {
  306. //BEGIN for -> while rewrite
  307. const initCmd = cmd.assignment;
  308. const condition = cmd.condition;
  309. const increment = cmd.increment;
  310. const whileBlock = new Commands.CommandBlock([],
  311. cmd.commands.concat(increment));
  312. const forAsWhile = new Commands.While(condition, whileBlock);
  313. forAsWhile.sourceInfo = cmd.sourceInfo;
  314. //END for -> while rewrite
  315. const newCmdList = [initCmd,forAsWhile];
  316. return this.executeCommands(store, newCmdList);
  317. } catch (error) {
  318. return Promise.reject(error);
  319. }
  320. }
  321. executeDoWhile (store, cmd) {
  322. const outerRef = this;
  323. try {
  324. outerRef.loopTimers.push(Date.now());
  325. outerRef.context.push(Context.BREAKABLE);
  326. const $newStore = outerRef.executeCommands(store, cmd.commands);
  327. return $newStore.then(sto => {
  328. if(sto.mode === Modes.BREAK) {
  329. outerRef.context.pop();
  330. sto.mode = Modes.RUN;
  331. outerRef.loopTimers.pop();
  332. return sto;
  333. }
  334. const $value = outerRef.evaluateExpression(sto, cmd.expression);
  335. return $value.then(vl => {
  336. if (!vl.type.isCompatible(Types.BOOLEAN)) {
  337. return Promise.reject(ProcessorErrorFactory.loop_condition_type_full(cmd.sourceInfo));
  338. }
  339. if (vl.get()) {
  340. outerRef.context.pop();
  341. if(outerRef.loopTimers.length > 0) {
  342. const time = outerRef.loopTimers[0];
  343. if(Date.now() - time >= IVProgProcessor.LOOP_TIMEOUT) {
  344. outerRef.forceKill = true;
  345. return Promise.reject(ProcessorErrorFactory.endless_loop_full(cmd.sourceInfo));
  346. }
  347. }
  348. return outerRef.executeCommand(sto, cmd);
  349. } else {
  350. outerRef.context.pop();
  351. outerRef.loopTimers.pop();
  352. return sto;
  353. }
  354. })
  355. })
  356. } catch (error) {
  357. return Promise.reject(error);
  358. }
  359. }
  360. executeWhile (store, cmd) {
  361. const outerRef = this;
  362. try {
  363. outerRef.loopTimers.push(Date.now());
  364. outerRef.context.push(Context.BREAKABLE);
  365. const $value = outerRef.evaluateExpression(store, cmd.expression);
  366. return $value.then(vl => {
  367. if(vl.type.isCompatible(Types.BOOLEAN)) {
  368. if(vl.get()) {
  369. const $newStore = outerRef.executeCommands(store, cmd.commands);
  370. return $newStore.then(sto => {
  371. outerRef.context.pop();
  372. if (sto.mode === Modes.BREAK) {
  373. outerRef.loopTimers.pop();
  374. sto.mode = Modes.RUN;
  375. return sto;
  376. }
  377. if (outerRef.loopTimers.length > 0) {
  378. const time = outerRef.loopTimers[0];
  379. if(Date.now() - time >= IVProgProcessor.LOOP_TIMEOUT) {
  380. outerRef.forceKill = true;
  381. return Promise.reject(ProcessorErrorFactory.endless_loop_full(cmd.sourceInfo));
  382. }
  383. }
  384. return outerRef.executeCommand(sto, cmd);
  385. });
  386. } else {
  387. outerRef.context.pop();
  388. outerRef.loopTimers.pop();
  389. return store;
  390. }
  391. } else {
  392. return Promise.reject(ProcessorErrorFactory.loop_condition_type_full(cmd.expression.toString(), cmd.sourceInfo));
  393. }
  394. })
  395. } catch (error) {
  396. return Promise.reject(error);
  397. }
  398. }
  399. executeIfThenElse (store, cmd) {
  400. try {
  401. const $value = this.evaluateExpression(store, cmd.condition);
  402. return $value.then(vl => {
  403. if(vl.type.isCompatible(Types.BOOLEAN)) {
  404. if(vl.get()) {
  405. return this.executeCommands(store, cmd.ifTrue.commands);
  406. } else if( cmd.ifFalse !== null){
  407. if(cmd.ifFalse instanceof Commands.IfThenElse) {
  408. return this.executeCommand(store, cmd.ifFalse);
  409. } else {
  410. return this.executeCommands(store, cmd.ifFalse.commands);
  411. }
  412. } else {
  413. return Promise.resolve(store);
  414. }
  415. } else {
  416. return Promise.reject(ProcessorErrorFactory.if_condition_type_full(cmd.condition.toString(), cmd.sourceInfo));
  417. }
  418. });
  419. } catch (error) {
  420. return Promise.reject(error);
  421. }
  422. }
  423. executeReturn (store, cmd) {
  424. try {
  425. const funcType = store.applyStore('$').type;
  426. const $value = this.evaluateExpression(store, cmd.expression);
  427. const funcName = store.name === IVProgProcessor.MAIN_INTERNAL_ID ?
  428. LanguageDefinedFunction.getMainFunctionName() : store.name;
  429. return $value.then(vl => {
  430. if(vl === null && funcType.isCompatible(Types.VOID)) {
  431. store.mode = Modes.RETURN;
  432. return Promise.resolve(store);
  433. }
  434. if (vl === null || !funcType.isCompatible(vl.type)) {
  435. const stringInfo = funcType.stringInfo();
  436. const info = stringInfo[0];
  437. return Promise.reject(ProcessorErrorFactory.invalid_return_type_full(funcName, info.type, info.dim, cmd.sourceInfo));
  438. } else {
  439. const realValue = this.parseStoreObjectValue(vl);
  440. store.updateStore('$', realValue);
  441. store.mode = Modes.RETURN;
  442. return Promise.resolve(store);
  443. }
  444. });
  445. } catch (error) {
  446. return Promise.reject(error);
  447. }
  448. }
  449. executeBreak (store, cmd) {
  450. if(this.checkContext(Context.BREAKABLE)) {
  451. store.mode = Modes.BREAK;
  452. return Promise.resolve(store);
  453. } else {
  454. return Promise.reject(ProcessorErrorFactory.unexpected_break_command_full(cmd.sourceInfo));
  455. }
  456. }
  457. executeAssign (store, cmd) {
  458. try {
  459. const inStore = store.applyStore(cmd.id);
  460. const $value = this.evaluateExpression(store, cmd.expression);
  461. return $value.then( vl => {
  462. let realValue = this.parseStoreObjectValue(vl);
  463. if(!inStore.type.isCompatible(realValue.type)) {
  464. if(Config.enable_type_casting && Store.canImplicitTypeCast(inStore.type, vl.type)) {
  465. realValue = Store.doImplicitCasting(inStore.type, realValue);
  466. } else {
  467. const stringInfo = inStore.type.stringInfo()
  468. const info = stringInfo[0]
  469. return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo));
  470. }
  471. }
  472. store.updateStore(cmd.id, realValue)
  473. return store;
  474. });
  475. } catch (error) {
  476. return Promise.reject(error);
  477. }
  478. }
  479. executeArrayIndexAssign (store, cmd) {
  480. const mustBeArray = store.applyStore(cmd.id);
  481. if(!(mustBeArray.type instanceof ArrayType)) {
  482. return Promise.reject(ProcessorErrorFactory.invalid_array_access_full(cmd.id, cmd.sourceInfo));
  483. }
  484. const line$ = this.evaluateExpression(store, cmd.line);
  485. const column$ = this.evaluateExpression(store, cmd.column);
  486. const value$ = this.evaluateExpression(store, cmd.expression);
  487. return Promise.all([line$, column$, value$]).then(results => {
  488. const lineSO = results[0];
  489. if(!Types.INTEGER.isCompatible(lineSO.type)) {
  490. return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo));
  491. }
  492. const line = lineSO.get();
  493. const columnSO = results[1];
  494. let column = null
  495. if (columnSO !== null) {
  496. if(!Types.INTEGER.isCompatible(columnSO.type)) {
  497. return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo));
  498. }
  499. column = columnSO.get();
  500. }
  501. const value = this.parseStoreObjectValue(results[2]);
  502. let actualValue = value;
  503. if (line >= mustBeArray.lines) {
  504. if(mustBeArray.isVector) {
  505. return Promise.reject(ProcessorErrorFactory.vector_line_outbounds_full(cmd.id, line, mustBeArray.lines, cmd.sourceInfo));
  506. } else {
  507. return Promise.reject(ProcessorErrorFactory.matrix_line_outbounds_full(cmd.id, line, mustBeArray.lines, cmd.sourceInfo));
  508. }
  509. } else if (line < 0) {
  510. throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
  511. }
  512. if (column !== null && mustBeArray.columns === null ){
  513. return Promise.reject(ProcessorErrorFactory.vector_not_matrix_full(cmd.id, cmd.sourceInfo));
  514. }
  515. if(column !== null ) {
  516. if (column >= mustBeArray.columns) {
  517. return Promise.reject(ProcessorErrorFactory.matrix_column_outbounds_full(cmd.id, column,mustBeArray.columns, cmd.sourceInfo));
  518. } else if (column < 0) {
  519. throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
  520. }
  521. }
  522. const newArray = Object.assign(new StoreObjectArray(null,null,null), mustBeArray);
  523. if (column !== null) {
  524. if (!newArray.type.canAccept(value.type)) {
  525. if(!Config.enable_type_casting || !Store.canImplicitTypeCast(mustBeArray.type.innerType, value.type)) {
  526. const type = mustBeArray.type.innerType;
  527. const stringInfo = type.stringInfo();
  528. const info = stringInfo[0];
  529. // const exp = cmd.expression.toString();
  530. return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo));
  531. }
  532. actualValue = Store.doImplicitCasting(mustBeArray.type.innerType, value);
  533. }
  534. newArray.value[line].value[column] = actualValue;
  535. store.updateStore(cmd.id, newArray);
  536. } else {
  537. if(!newArray.type.canAccept(value.type)) {
  538. if(!Config.enable_type_casting || !Store.canImplicitTypeCast(mustBeArray.type.innerType, value.type)) {
  539. const type = mustBeArray.type;
  540. const stringInfo = type.stringInfo();
  541. const info = stringInfo[0];
  542. const exp = cmd.expression.toString();
  543. return Promise.reject(ProcessorErrorFactory.incompatible_types_array_full(exp,info.type, info.dim-1, cmd.sourceInfo));
  544. }
  545. actualValue = Store.doImplicitCasting(mustBeArray.type.innerType, value);
  546. }
  547. newArray.value[line] = actualValue;
  548. store.updateStore(cmd.id, newArray);
  549. }
  550. return store;
  551. });
  552. }
  553. /**
  554. *
  555. * @param {Store} store
  556. * @param {Commands.Declaration} cmd
  557. */
  558. executeDeclaration (store, cmd) {
  559. try {
  560. let $value = Promise.resolve(null);
  561. if(cmd instanceof Commands.ArrayDeclaration) {
  562. return this.executeArrayDeclaration(store, cmd);
  563. } else {
  564. if(cmd.initial !== null) {
  565. $value = this.evaluateExpression(store, cmd.initial);
  566. }
  567. return $value.then(vl => {
  568. let realValue = vl;
  569. let temp = null;
  570. if (vl !== null) {
  571. if(!vl.type.isCompatible(cmd.type)) {
  572. if(Config.enable_type_casting && Store.canImplicitTypeCast(cmd.type, vl.type)) {
  573. realValue = Store.doImplicitCasting(cmd.type, realValue);
  574. } else {
  575. const stringInfo = vl.type.stringInfo();
  576. const info = stringInfo[0];
  577. return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo));
  578. }
  579. }
  580. temp = new StoreValue(cmd.type, realValue.get(), null, cmd.isConst);
  581. } else {
  582. temp = new StoreValue(cmd.type, null, null, cmd.isConst);
  583. }
  584. store.insertStore(cmd.id, temp);
  585. return store;
  586. });
  587. }
  588. } catch (e) {
  589. return Promise.reject(e);
  590. }
  591. }
  592. /**
  593. *
  594. * @param {Store} store
  595. * @param {Commands.ArrayDeclaration} cmd
  596. */
  597. executeArrayDeclaration (store, cmd) {
  598. const $lines = this.evaluateExpression(store, cmd.lines);
  599. const $columns = cmd.columns === null ? null: this.evaluateExpression(store, cmd.columns);
  600. return Promise.all([$lines, $columns]).then(([line_sv, column_sv]) => {
  601. if(!Types.INTEGER.isCompatible(line_sv.type)) {
  602. return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo));
  603. }
  604. const line = line_sv.get().toNumber();
  605. if(line < 0) {
  606. throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
  607. }
  608. let column = null
  609. if (column_sv !== null) {
  610. if(!Types.INTEGER.isCompatible(column_sv.type)) {
  611. return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo));
  612. }
  613. column = column_sv.get().toNumber();
  614. if(column < 0) {
  615. throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
  616. }
  617. }
  618. let $value = Promise.resolve(null);
  619. if(cmd.initial !== null) {
  620. // array can only be initialized by a literal....
  621. $value = this.evaluateArrayLiteral(store, cmd.initial, cmd.type, line, column);
  622. }
  623. return $value.then(vector_list => {
  624. let temp = null;
  625. if (vector_list !== null) {
  626. temp = new ArrayStoreValue(cmd.type, vector_list, line, column, null, cmd.isConst);
  627. } else {
  628. temp = new ArrayStoreValue(cmd.type, [], line, column, null, cmd.isConst);
  629. }
  630. store.insertStore(cmd.id, temp);
  631. return store;
  632. })
  633. });
  634. }
  635. evaluateExpression (store, exp) {
  636. if (exp instanceof Expressions.UnaryApp) {
  637. return this.evaluateUnaryApp(store, exp);
  638. } else if (exp instanceof Expressions.InfixApp) {
  639. return this.evaluateInfixApp(store, exp);
  640. } else if (exp instanceof Expressions.ArrayAccess) {
  641. return this.evaluateArrayAccess(store, exp);
  642. } else if (exp instanceof Expressions.VariableLiteral) {
  643. return this.evaluateVariableLiteral(store, exp);
  644. } else if (exp instanceof Expressions.IntLiteral) {
  645. return this.evaluateLiteral(store, exp);
  646. } else if (exp instanceof Expressions.RealLiteral) {
  647. return this.evaluateLiteral(store, exp);
  648. } else if (exp instanceof Expressions.BoolLiteral) {
  649. return this.evaluateLiteral(store, exp);
  650. } else if (exp instanceof Expressions.StringLiteral) {
  651. return this.evaluateLiteral(store, exp);
  652. } else if (exp instanceof Expressions.ArrayLiteral) {
  653. return Promise.reject(new Error("Internal Error: The system should not eval an array literal."))
  654. } else if (exp instanceof Expressions.FunctionCall) {
  655. return this.evaluateFunctionCall(store, exp);
  656. }
  657. return Promise.resolve(null);
  658. }
  659. evaluateFunctionCall (store, exp) {
  660. if(exp.isMainCall) {
  661. return Promise.reject(ProcessorErrorFactory.void_in_expression_full(LanguageDefinedFunction.getMainFunctionName(), exp.sourceInfo));
  662. }
  663. const func = this.findFunction(exp.id);
  664. if(Types.VOID.isCompatible(func.returnType)) {
  665. return Promise.reject(ProcessorErrorFactory.void_in_expression_full(exp.id, exp.sourceInfo));
  666. }
  667. const $newStore = this.runFunction(func, exp.actualParameters, store);
  668. return $newStore.then( sto => {
  669. if(sto.mode !== Modes.RETURN) {
  670. return Promise.reject(new Error("The function that was called did not have a return command: "+exp.id));
  671. }
  672. const val = sto.applyStore('$');
  673. sto.destroy();
  674. if (val instanceof StoreObjectArray) {
  675. return Promise.resolve(Object.assign(new StoreObjectArray(null,null,null,null,null), val));
  676. } else {
  677. return val;
  678. }
  679. });
  680. }
  681. /**
  682. *
  683. * @param {Store} store
  684. * @param {Expressions.ArrayLiteral} exp
  685. * @param {ArrayType} type
  686. */
  687. evaluateArrayLiteral (store, exp, type, lines, columns) {
  688. if(!exp.isVector) {
  689. if(columns == null) {
  690. throw new Error("Vector cannot be initialized by a matrix");
  691. }
  692. const $matrix = this.evaluateMatrix(store, exp, type, lines, columns);
  693. return Promise.all($matrix).then(vectorList => {
  694. const values = vectorList.reduce((prev, next) => prev.concat(next), []);
  695. return Promise.resolve(values);
  696. });
  697. } else {
  698. if(columns != null) {
  699. throw new Error("Matrix cannot be initialized by a vector");
  700. }
  701. return this.evaluateVector(store, exp, type, lines).then(list => {
  702. return Promise.resolve(list);
  703. });
  704. }
  705. }
  706. /**
  707. * Evalautes a list of literals and expression composing the vector
  708. * @param {Store} store
  709. * @param {Expressions.ArrayLiteral} exps
  710. * @param {ArrayType} type
  711. * @param {number} n_elements
  712. * @returns {Promise<StoreValue[]>} store object list
  713. */
  714. evaluateVector (store, exps, type, n_elements) {
  715. const values = exps.value;
  716. if(n_elements !== values.length) {
  717. throw new Error("invalid number of elements to array literal...");
  718. }
  719. const actual_values = Promise.all(values.map( exp => this.evaluateExpression(store, exp)));
  720. return actual_values.then( values => {
  721. return values.map((v, index) => {
  722. if(!type.canAccept(v.type)) {
  723. if (!Config.enable_type_casting || !Store.canImplicitTypeCast(type.innerType, v.type)) {
  724. // const stringInfo = v.type.stringInfo();
  725. // const info = stringInfo[0];
  726. const exp_str = values[index].toString();
  727. // TODO - fix error message
  728. throw ProcessorErrorFactory.invalid_array_literal_type_full(exp_str, values[index].sourceInfo);
  729. }
  730. const new_value = Store.doImplicitCasting(type.innerType, v);
  731. return new_value;
  732. }
  733. return v;
  734. });
  735. });
  736. }
  737. /**
  738. * Evaluates a list of array literals composing the matrix
  739. * @param {Store} store
  740. * @param {Expressions.ArrayLiteral} exps
  741. * @param {ArrayType} type
  742. * @returns {Promise<StoreValue[]>[]}
  743. */
  744. evaluateMatrix (store, exps, type, lines, columns) {
  745. const values = exps.value;
  746. if(values.length !== lines) {
  747. throw new Error("Invalid number of lines to matrix literal...");
  748. }
  749. return values.map( vector => {
  750. const vec_type = new ArrayType(type.innerType, 1);
  751. return this.evaluateVector(store, vector, vec_type, columns);
  752. });
  753. }
  754. evaluateLiteral (_, exp) {
  755. return Promise.resolve(new StoreValue(exp.type, exp.value));
  756. }
  757. evaluateVariableLiteral (store, exp) {
  758. try {
  759. const val = store.applyStore(exp.id);
  760. return Promise.resolve(val);
  761. // if (val instanceof StoreObjectArray) {
  762. // return Promise.resolve(Object.assign(new StoreObjectArray(null,null,null,null), val));
  763. // } else {
  764. // return Promise.resolve(val);
  765. // }
  766. } catch (error) {
  767. return Promise.reject(error);
  768. }
  769. }
  770. evaluateArrayAccess (store, exp) {
  771. const mustBeArray = store.getStoreObject(exp.id);
  772. if (!(mustBeArray.type instanceof ArrayType)) {
  773. return Promise.reject(ProcessorErrorFactory.invalid_array_access_full(exp.id, exp.sourceInfo));
  774. }
  775. const $line = this.evaluateExpression(store, exp.line);
  776. const $column = this.evaluateExpression(store, exp.column);
  777. return Promise.all([$line, $column]).then(([line_sv, column_sv]) => {
  778. if(!Types.INTEGER.isCompatible(line_sv.type)) {
  779. return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(exp.sourceInfo));
  780. }
  781. const line = line_sv.get().toNumber();
  782. let column = null;
  783. if(column_sv !== null) {
  784. if(!Types.INTEGER.isCompatible(column_sv.type)) {
  785. return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(exp.sourceInfo));
  786. }
  787. column = column_sv.get().toNumber();
  788. }
  789. if (line >= mustBeArray.lines) {
  790. if(mustBeArray.isVector) {
  791. return Promise.reject(ProcessorErrorFactory.vector_line_outbounds_full(exp.id, line, mustBeArray.lines, exp.sourceInfo));
  792. } else {
  793. return Promise.reject(ProcessorErrorFactory.matrix_line_outbounds_full(exp.id, line, mustBeArray.lines, exp.sourceInfo));
  794. }
  795. } else if (line < 0) {
  796. throw ProcessorErrorFactory.array_dimension_not_positive_full(exp.sourceInfo);
  797. }
  798. if (column !== null && mustBeArray.columns === 0 ){
  799. return Promise.reject(ProcessorErrorFactory.vector_not_matrix_full(exp.id, exp.sourceInfo));
  800. }
  801. if(column !== null ) {
  802. if (column >= mustBeArray.columns) {
  803. return Promise.reject(ProcessorErrorFactory.matrix_column_outbounds_full(exp.id, column,mustBeArray.columns, exp.sourceInfo));
  804. } else if (column < 0) {
  805. throw ProcessorErrorFactory.array_dimension_not_positive_full(exp.sourceInfo);
  806. }
  807. }
  808. const result = mustBeArray.getAt(line, column);
  809. const type = mustBeArray.type.innerType;
  810. if(Array.isArray(result)) {
  811. let l = 0;
  812. const values = result.map(v => {
  813. if(!Array.isArray(v)) {
  814. return new StoreValueAddress(type.innerType, v, l++, undefined, mustBeArray.id, mustBeArray.readOnly);
  815. } else {
  816. throw new Error("Indexing 3D structure....");
  817. }
  818. });
  819. return Promise.resolve(new ArrayStoreValue(new ArrayType(type, 1),
  820. values, mustBeArray.columns, null, mustBeArray.id, mustBeArray.readOnly))
  821. } else {
  822. return Promise.resolve(new StoreValueAddress(type, result, line, column, mustBeArray.id, mustBeArray.readOnly));
  823. }
  824. //return Promise.resolve(mustBeArray.getAt(line, column));
  825. });
  826. }
  827. evaluateUnaryApp (store, unaryApp) {
  828. const $left = this.evaluateExpression(store, unaryApp.left);
  829. return $left.then( left => {
  830. const resultType = resultTypeAfterUnaryOp(unaryApp.op, left.type);
  831. if (Types.UNDEFINED.isCompatible(resultType)) {
  832. const stringInfo = left.type.stringInfo();
  833. const info = stringInfo[0];
  834. return Promise.reject(ProcessorErrorFactory.invalid_unary_op_full(unaryApp.op, info.type, info.dim, unaryApp.sourceInfo));
  835. }
  836. switch (unaryApp.op.ord) {
  837. case Operators.ADD.ord:
  838. return new StoreValue(resultType, left.get());
  839. case Operators.SUB.ord:
  840. return new StoreValue(resultType, left.get().negated());
  841. case Operators.NOT.ord:
  842. return new StoreValue(resultType, !left.get());
  843. default:
  844. return Promise.reject(new RuntimeError('!!!Critical Invalid UnaryApp '+ unaryApp.op));
  845. }
  846. });
  847. }
  848. evaluateInfixApp (store, infixApp) {
  849. const $left = this.evaluateExpression(store, infixApp.left);
  850. const $right = this.evaluateExpression(store, infixApp.right);
  851. return Promise.all([$left, $right]).then(values => {
  852. let shouldImplicitCast = false;
  853. const left = values[0];
  854. const right = values[1];
  855. let resultType = resultTypeAfterInfixOp(infixApp.op, left.type, right.type);
  856. if (Types.UNDEFINED.isCompatible(resultType)) {
  857. if (Config.enable_type_casting && Store.canImplicitTypeCast(left.type, right.type)) {
  858. shouldImplicitCast = true;
  859. } else {
  860. const stringInfoLeft = left.type.stringInfo();
  861. const infoLeft = stringInfoLeft[0];
  862. const stringInfoRight = right.type.stringInfo();
  863. const infoRight = stringInfoRight[0];
  864. return Promise.reject(ProcessorErrorFactory.invalid_infix_op_full(infixApp.op, infoLeft.type, infoLeft.dim,
  865. infoRight.type,infoRight.dim,infixApp.sourceInfo));
  866. }
  867. }
  868. let result = null;
  869. switch (infixApp.op.ord) {
  870. case Operators.ADD.ord: {
  871. if(Types.STRING.isCompatible(left.type)) {
  872. const rightStr = convertToString(right.get(), right.type);
  873. return new StoreValue(resultType, (left.get() + rightStr));
  874. } else if (Types.STRING.isCompatible(right.type)) {
  875. const leftStr = convertToString(left.get(), left.type);
  876. return new StoreValue(resultType, (leftStr + right.get()));
  877. } else {
  878. return new StoreValue(resultType, (left.get().plus(right.get())));
  879. }
  880. }
  881. case Operators.SUB.ord:
  882. return new StoreValue(resultType, (left.get().minus(right.get())));
  883. case Operators.MULT.ord: {
  884. result = left.get().times(right.get());
  885. // if(result.dp() > Config.decimalPlaces) {
  886. // result = new Decimal(result.toFixed(Config.decimalPlaces));
  887. // }
  888. return new StoreValue(resultType, result);
  889. }
  890. case Operators.DIV.ord: {
  891. if (Types.INTEGER.isCompatible(resultType))
  892. result = left.get().divToInt(right.get());
  893. else
  894. result = left.get().div(right.get());
  895. // if(result.dp() > Config.decimalPlaces) {
  896. // result = new Decimal(result.toFixed(Config.decimalPlaces));
  897. // }
  898. return new StoreValue(resultType, (result));
  899. }
  900. case Operators.MOD.ord: {
  901. let leftValue = left.get();
  902. let rightValue = right.get();
  903. if(shouldImplicitCast) {
  904. resultType = Types.INTEGER;
  905. leftValue = leftValue.trunc();
  906. rightValue = rightValue.trunc();
  907. }
  908. result = leftValue.modulo(rightValue);
  909. // if(result.dp() > Config.decimalPlaces) {
  910. // result = new Decimal(result.toFixed(Config.decimalPlaces));
  911. // }
  912. return new StoreValue(resultType, (result));
  913. }
  914. case Operators.GT.ord: {
  915. let leftValue = left.get();
  916. let rightValue = right.get();
  917. if (Types.STRING.isCompatible(left.type)) {
  918. result = leftValue.length > rightValue.length;
  919. } else {
  920. if (shouldImplicitCast) {
  921. resultType = Types.BOOLEAN;
  922. leftValue = leftValue.trunc();
  923. rightValue = rightValue.trunc();
  924. }
  925. result = leftValue.gt(rightValue);
  926. }
  927. return new StoreValue(resultType, result);
  928. }
  929. case Operators.GE.ord: {
  930. let leftValue = left.get();
  931. let rightValue = right.get();
  932. if (Types.STRING.isCompatible(left.type)) {
  933. result = leftValue.length >= rightValue.length;
  934. } else {
  935. if (shouldImplicitCast) {
  936. resultType = Types.BOOLEAN;
  937. leftValue = leftValue.trunc();
  938. rightValue = rightValue.trunc();
  939. }
  940. result = leftValue.gte(rightValue);
  941. }
  942. return new StoreValue(resultType, result);
  943. }
  944. case Operators.LT.ord: {
  945. let leftValue = left.get();
  946. let rightValue = right.get();
  947. if (Types.STRING.isCompatible(left.type)) {
  948. result = leftValue.length < rightValue.length;
  949. } else {
  950. if (shouldImplicitCast) {
  951. resultType = Types.BOOLEAN;
  952. leftValue = leftValue.trunc();
  953. rightValue = rightValue.trunc();
  954. }
  955. result = leftValue.lt(rightValue);
  956. }
  957. return new StoreValue(resultType, (result));
  958. }
  959. case Operators.LE.ord: {
  960. let leftValue = left.get();
  961. let rightValue = right.get();
  962. if (Types.STRING.isCompatible(left.type)) {
  963. result = leftValue.length <= rightValue.length;
  964. } else {
  965. if (shouldImplicitCast) {
  966. resultType = Types.BOOLEAN;
  967. leftValue = leftValue.trunc();
  968. rightValue = rightValue.trunc();
  969. }
  970. result = leftValue.lte(rightValue);
  971. }
  972. return new StoreValue(resultType, result);
  973. }
  974. case Operators.EQ.ord: {
  975. let leftValue = left.get();
  976. let rightValue = right.get();
  977. if (Types.INTEGER.isCompatible(left.type) || Types.REAL.isCompatible(left.type)) {
  978. if (shouldImplicitCast) {
  979. resultType = Types.BOOLEAN;
  980. leftValue = leftValue.trunc();
  981. rightValue = rightValue.trunc();
  982. }
  983. result = leftValue.eq(rightValue);
  984. } else {
  985. result = leftValue === rightValue;
  986. }
  987. return new StoreValue(resultType, result);
  988. }
  989. case Operators.NEQ.ord: {
  990. let leftValue = left.get();
  991. let rightValue = right.get();
  992. if (Types.INTEGER.isCompatible(left.type) || Types.REAL.isCompatible(left.type)) {
  993. if (shouldImplicitCast) {
  994. resultType = Types.BOOLEAN;
  995. leftValue = leftValue.trunc();
  996. rightValue = rightValue.trunc();
  997. }
  998. result = !leftValue.eq(rightValue);
  999. } else {
  1000. result = leftValue !== rightValue;
  1001. }
  1002. return new StoreValue(resultType, result);
  1003. }
  1004. case Operators.AND.ord:
  1005. return new StoreValue(resultType, (left.get() && right.get()));
  1006. case Operators.OR.ord:
  1007. return new StoreValue(resultType, (left.get() || right.get()));
  1008. default:
  1009. return Promise.reject(new RuntimeError('!!!Critical Invalid InfixApp '+ infixApp.op));
  1010. }
  1011. });
  1012. }
  1013. parseStoreObjectValue (vl) {
  1014. let realValue = vl;
  1015. if(vl instanceof StoreObjectArrayAddress) {
  1016. if(vl.type instanceof ArrayType) {
  1017. switch(vl.type.dimensions) {
  1018. case 1: {
  1019. realValue = new StoreObjectArray(vl.type, vl.get().length, null, vl.get());
  1020. break;
  1021. }
  1022. default: {
  1023. throw new RuntimeError("Three dimensional array address...");
  1024. }
  1025. }
  1026. } else {
  1027. realValue = new StoreValue(vl.type, vl.get());
  1028. }
  1029. }
  1030. return realValue;
  1031. }
  1032. }