semanticAnalyser.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. import { ProcessorErrorFactory } from "./../error/processorErrorFactory";
  2. import { LanguageDefinedFunction } from "./../definedFunctions";
  3. import { LanguageService } from "./../../services/languageService";
  4. import {
  5. ArrayDeclaration,
  6. While,
  7. For,
  8. Switch,
  9. Assign,
  10. Break,
  11. IfThenElse,
  12. Return,
  13. ArrayIndexAssign,
  14. } from "../../ast/commands";
  15. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  16. import { Expression } from "./../../ast/expressions/expression";
  17. import {
  18. InfixApp,
  19. UnaryApp,
  20. FunctionCall,
  21. IntLiteral,
  22. RealLiteral,
  23. StringLiteral,
  24. BoolLiteral,
  25. VariableLiteral,
  26. ArrayAccess,
  27. CharLiteral,
  28. } from "../../ast/expressions";
  29. import { Literal } from "../../ast/expressions/literal";
  30. import {
  31. resultTypeAfterInfixOp,
  32. resultTypeAfterUnaryOp,
  33. } from "../compatibilityTable";
  34. import { Types } from "../../typeSystem/types";
  35. import { ArrayType } from "../../typeSystem/array_type";
  36. import { MultiType } from "../../typeSystem/multiType";
  37. import { Config } from "../../util/config";
  38. import { Store } from "../store/store";
  39. import { IVProgParser } from "../../ast/ivprogParser";
  40. export class SemanticAnalyser {
  41. static analyseFromSource (stringCode) {
  42. const parser = IVProgParser.createParser(stringCode);
  43. const semantic = new SemanticAnalyser(parser.parseTree());
  44. return semantic.analyseTree();
  45. }
  46. constructor (ast) {
  47. this.ast = ast;
  48. this.lexerClass = LanguageService.getCurrentLexer();
  49. const lexer = new this.lexerClass(null);
  50. this.literalNames = lexer.literalNames;
  51. this.symbolMap = null;
  52. this.currentFunction = null;
  53. }
  54. pushMap () {
  55. if (this.symbolMap === null) {
  56. this.symbolMap = { map: {}, next: null };
  57. } else {
  58. const n = { map: {}, next: this.symbolMap };
  59. this.symbolMap = n;
  60. }
  61. }
  62. popMap () {
  63. if (this.symbolMap !== null) {
  64. this.symbolMap = this.symbolMap.next;
  65. }
  66. }
  67. insertSymbol (id, typeInfo) {
  68. this.symbolMap.map[id] = typeInfo;
  69. }
  70. findSymbol (id, symbol_map) {
  71. if (!symbol_map.map[id]) {
  72. if (symbol_map.next) {
  73. return this.findSymbol(id, symbol_map.next);
  74. }
  75. return null;
  76. } else {
  77. return symbol_map.map[id];
  78. }
  79. }
  80. getMainFunction () {
  81. return this.ast.functions.find((v) => v.isMain);
  82. }
  83. findFunction (name) {
  84. if (name.match(/^\$.+$/)) {
  85. const fun = LanguageDefinedFunction.getFunction(name);
  86. if (!fun) {
  87. throw ProcessorErrorFactory.not_implemented(name);
  88. }
  89. return fun;
  90. } else {
  91. const val = this.ast.functions.find((v) => v.name === name);
  92. if (!val) {
  93. return null;
  94. }
  95. return val;
  96. }
  97. }
  98. analyseTree () {
  99. const globalVars = this.ast.global;
  100. this.pushMap();
  101. this.assertDeclarations(globalVars);
  102. const functions = this.ast.functions;
  103. const mainFunc = functions.filter((f) => f.name === null);
  104. if (mainFunc.length <= 0) {
  105. throw ProcessorErrorFactory.main_missing();
  106. }
  107. for (let i = 0; i < functions.length; i++) {
  108. const fun = functions[i];
  109. this.assertFunction(fun);
  110. }
  111. return this.ast;
  112. }
  113. assertDeclarations (list) {
  114. for (let i = 0; i < list.length; i++) {
  115. this.assertDeclaration(list[i]);
  116. }
  117. }
  118. assertDeclaration (declaration) {
  119. if (declaration instanceof ArrayDeclaration) {
  120. this.assertArrayDeclaration(declaration);
  121. this.insertSymbol(declaration.id, {
  122. id: declaration.id,
  123. lines: declaration.lines,
  124. columns: declaration.columns,
  125. type: declaration.type,
  126. isConst: declaration.isConst,
  127. });
  128. } else {
  129. if (declaration.initial === null) {
  130. this.insertSymbol(declaration.id, {
  131. id: declaration.id,
  132. type: declaration.type,
  133. isConst: declaration.isConst,
  134. });
  135. return;
  136. }
  137. const resultType = this.evaluateExpressionType(declaration.initial);
  138. if (resultType instanceof MultiType) {
  139. if (!resultType.isCompatible(declaration.type)) {
  140. const stringInfo = declaration.type.stringInfo();
  141. const info = stringInfo[0];
  142. const result_string_info = resultType.stringInfo();
  143. const result_info = result_string_info[0];
  144. const exp = declaration.initial;
  145. throw ProcessorErrorFactory.incompatible_types_full(
  146. info.type,
  147. info.dim,
  148. result_info.type,
  149. result_info.dim,
  150. exp.toString(),
  151. declaration.sourceInfo
  152. );
  153. }
  154. this.insertSymbol(declaration.id, {
  155. id: declaration.id,
  156. type: declaration.type,
  157. isConst: declaration.isConst,
  158. });
  159. } else if (
  160. (!declaration.type.isCompatible(resultType) &&
  161. !Config.enable_type_casting) ||
  162. (!declaration.type.isCompatible(resultType) &&
  163. Config.enable_type_casting &&
  164. !Store.canImplicitTypeCast(declaration.type, resultType))
  165. ) {
  166. const stringInfo = declaration.type.stringInfo();
  167. const info = stringInfo[0];
  168. const result_string_info = resultType.stringInfo();
  169. const result_info = result_string_info[0];
  170. const exp = declaration.initial;
  171. throw ProcessorErrorFactory.incompatible_types_full(
  172. info.type,
  173. info.dim,
  174. result_info.type,
  175. result_info.dim,
  176. exp.toString(),
  177. declaration.sourceInfo
  178. );
  179. } else {
  180. this.insertSymbol(declaration.id, {
  181. id: declaration.id,
  182. type: declaration.type,
  183. isConst: declaration.isConst,
  184. });
  185. }
  186. }
  187. }
  188. assertArrayDeclaration (declaration) {
  189. if (declaration.initial === null) {
  190. const lineType = this.evaluateExpressionType(declaration.lines);
  191. if (!lineType.isCompatible(Types.INTEGER)) {
  192. throw ProcessorErrorFactory.array_dimension_not_int_full(
  193. declaration.sourceInfo
  194. );
  195. }
  196. if (declaration.columns !== null) {
  197. const columnType = this.evaluateExpressionType(declaration.columns);
  198. if (!columnType.isCompatible(Types.INTEGER)) {
  199. throw ProcessorErrorFactory.array_dimension_not_int_full(
  200. declaration.sourceInfo
  201. );
  202. }
  203. }
  204. } else {
  205. this.evaluateArrayLiteral(declaration);
  206. }
  207. this.insertSymbol(declaration.id, {
  208. id: declaration.id,
  209. lines: declaration.lines,
  210. columns: declaration.columns,
  211. type: declaration.type,
  212. });
  213. return;
  214. }
  215. evaluateExpressionType (expression) {
  216. // TODO: Throw operator error in case type == UNDEFINED
  217. if (expression instanceof UnaryApp) {
  218. const op = expression.op;
  219. const resultType = this.evaluateExpressionType(expression.left);
  220. const finalResult = resultTypeAfterUnaryOp(op, resultType);
  221. if (Types.UNDEFINED.isCompatible(finalResult)) {
  222. const stringInfo = resultType.stringInfo();
  223. const info = stringInfo[0];
  224. const expString = expression.toString();
  225. throw ProcessorErrorFactory.invalid_unary_op_full(
  226. expString,
  227. op,
  228. info.type,
  229. info.dim,
  230. expression.sourceInfo
  231. );
  232. }
  233. return finalResult;
  234. } else if (expression instanceof InfixApp) {
  235. const op = expression.op;
  236. const resultTypeLeft = this.evaluateExpressionType(expression.left);
  237. const resultTypeRight = this.evaluateExpressionType(expression.right);
  238. const finalResult = resultTypeAfterInfixOp(
  239. op,
  240. resultTypeLeft,
  241. resultTypeRight
  242. );
  243. if (Types.UNDEFINED.isCompatible(finalResult)) {
  244. const stringInfoLeft = resultTypeLeft.stringInfo();
  245. const infoLeft = stringInfoLeft[0];
  246. const stringInfoRight = resultTypeRight.stringInfo();
  247. const infoRight = stringInfoRight[0];
  248. const expString = expression.toString();
  249. throw ProcessorErrorFactory.invalid_infix_op_full(
  250. expString,
  251. op,
  252. infoLeft.type,
  253. infoLeft.dim,
  254. infoRight.type,
  255. infoRight.dim,
  256. expression.sourceInfo
  257. );
  258. }
  259. return finalResult;
  260. } else if (expression instanceof Literal) {
  261. return this.evaluateLiteralType(expression);
  262. } else if (expression instanceof FunctionCall) {
  263. if (expression.isMainCall) {
  264. throw ProcessorErrorFactory.void_in_expression_full(
  265. LanguageDefinedFunction.getMainFunctionName(),
  266. expression.sourceInfo
  267. );
  268. }
  269. const fun = this.findFunction(expression.id);
  270. if (fun === null) {
  271. throw ProcessorErrorFactory.function_missing_full(
  272. expression.id,
  273. expression.sourceInfo
  274. );
  275. }
  276. if (fun.returnType.isCompatible(Types.VOID)) {
  277. throw ProcessorErrorFactory.void_in_expression_full(
  278. expression.id,
  279. expression.sourceInfo
  280. );
  281. }
  282. this.assertParameters(fun, expression.actualParameters);
  283. return fun.returnType;
  284. } else if (expression instanceof ArrayAccess) {
  285. const arrayTypeInfo = this.findSymbol(expression.id, this.symbolMap);
  286. if (arrayTypeInfo === null) {
  287. throw ProcessorErrorFactory.symbol_not_found_full(
  288. expression.id,
  289. expression.sourceInfo
  290. );
  291. }
  292. if (!(arrayTypeInfo.type instanceof ArrayType)) {
  293. throw ProcessorErrorFactory.invalid_array_access_full(
  294. expression.id,
  295. expression.sourceInfo
  296. );
  297. }
  298. const lineType = this.evaluateExpressionType(expression.line);
  299. if (!lineType.isCompatible(Types.INTEGER)) {
  300. throw ProcessorErrorFactory.array_dimension_not_int_full(
  301. expression.sourceInfo
  302. );
  303. }
  304. if (expression.column !== null) {
  305. if (arrayTypeInfo.columns === null) {
  306. throw ProcessorErrorFactory.invalid_matrix_access_full(
  307. expression.id,
  308. expression.sourceInfo
  309. );
  310. }
  311. const columnType = this.evaluateExpressionType(expression.column);
  312. if (!columnType.isCompatible(Types.INTEGER)) {
  313. throw ProcessorErrorFactory.array_dimension_not_int_full(
  314. expression.sourceInfo
  315. );
  316. }
  317. }
  318. const arrType = arrayTypeInfo.type;
  319. if (expression.column !== null) {
  320. // indexing matrix
  321. return arrType.innerType;
  322. } else {
  323. if (arrayTypeInfo.columns === null) {
  324. return arrType.innerType;
  325. }
  326. return new ArrayType(arrType.innerType, 1);
  327. }
  328. }
  329. }
  330. evaluateLiteralType (literal) {
  331. if (literal instanceof IntLiteral) {
  332. return literal.type;
  333. } else if (literal instanceof RealLiteral) {
  334. return literal.type;
  335. } else if (literal instanceof StringLiteral) {
  336. return literal.type;
  337. } else if (literal instanceof BoolLiteral) {
  338. return literal.type;
  339. } else if (literal instanceof CharLiteral) {
  340. return literal.type;
  341. } else if (literal instanceof VariableLiteral) {
  342. const typeInfo = this.findSymbol(literal.id, this.symbolMap);
  343. if (typeInfo === null) {
  344. throw ProcessorErrorFactory.symbol_not_found_full(
  345. literal.id,
  346. literal.sourceInfo
  347. );
  348. }
  349. if (typeInfo.type instanceof ArrayType) {
  350. return typeInfo.type;
  351. }
  352. return typeInfo.type;
  353. } else {
  354. // console.warn("Evaluating type only for an array literal...");
  355. let last = null;
  356. if (literal.value.length === 1) {
  357. last = this.evaluateExpressionType(literal.value[0]);
  358. } else {
  359. for (let i = 0; i < literal.value.length; i++) {
  360. const e = this.evaluateExpressionType(literal.value[i]);
  361. if (last === null) {
  362. last = e;
  363. } else if (!last.isCompatible(e)) {
  364. const strInfo = last.stringInfo();
  365. const info = strInfo[0];
  366. const strExp = literal.toString();
  367. throw ProcessorErrorFactory.incompatible_types_array_full(
  368. strExp,
  369. info.type,
  370. info.dim,
  371. literal.sourceInfo
  372. );
  373. }
  374. }
  375. }
  376. if (last instanceof ArrayType) {
  377. return new ArrayType(last.innerType, last.dimensions + 1);
  378. }
  379. return new ArrayType(last, 1);
  380. }
  381. }
  382. evaluateArrayLiteral (arrayDeclaration) {
  383. const type = arrayDeclaration.type;
  384. const literal = arrayDeclaration.initial;
  385. // console.log(arrayDeclaration);
  386. if (arrayDeclaration.isVector) {
  387. this.evaluateVectorLiteralType(literal, type);
  388. } else {
  389. // TODO matrix type check
  390. for (let i = 0; i < literal.lines; ++i) {
  391. const line_literal = literal.value[i];
  392. this.evaluateVectorLiteralType(
  393. line_literal,
  394. new ArrayType(type.innerType, 1)
  395. );
  396. }
  397. }
  398. return true;
  399. }
  400. assertFunction (fun) {
  401. this.pushMap();
  402. this.currentFunction = fun;
  403. fun.formalParameters.forEach((formalParam) => {
  404. if (formalParam.type instanceof ArrayType) {
  405. if (formalParam.type.dimensions > 1) {
  406. this.insertSymbol(formalParam.id, {
  407. id: formalParam.id,
  408. lines: -1,
  409. columns: -1,
  410. type: formalParam.type,
  411. });
  412. } else {
  413. this.insertSymbol(formalParam.id, {
  414. id: formalParam.id,
  415. lines: -1,
  416. columns: null,
  417. type: formalParam.type,
  418. });
  419. }
  420. } else {
  421. this.insertSymbol(formalParam.id, {
  422. id: formalParam.id,
  423. type: formalParam.type,
  424. });
  425. }
  426. });
  427. this.assertDeclarations(fun.variablesDeclarations);
  428. const optional = fun.returnType.isCompatible(Types.VOID);
  429. const valid = this.assertReturn(fun, optional);
  430. if (!valid) {
  431. throw ProcessorErrorFactory.function_no_return(fun.name);
  432. }
  433. this.popMap();
  434. }
  435. assertReturn (fun, optional) {
  436. return fun.commands.reduce(
  437. (last, next) => this.checkCommand(fun.returnType, next, optional) || last,
  438. optional
  439. );
  440. }
  441. checkCommand (type, cmd, optional) {
  442. if (cmd instanceof While) {
  443. const resultType = this.evaluateExpressionType(cmd.expression);
  444. if (!resultType.isCompatible(Types.BOOLEAN)) {
  445. throw ProcessorErrorFactory.loop_condition_type_full(
  446. cmd.expression.toString(),
  447. cmd.sourceInfo
  448. );
  449. }
  450. this.checkCommands(type, cmd.commands, optional);
  451. return false;
  452. } else if (cmd instanceof For) {
  453. const var_type = this.evaluateExpressionType(cmd.for_id);
  454. if (!var_type.isCompatible(Types.INTEGER)) {
  455. throw ProcessorErrorFactory.invalid_for_variable(
  456. cmd.for_id,
  457. cmd.sourceInfo
  458. );
  459. }
  460. const from_type = this.evaluateExpressionType(cmd.for_from);
  461. if (!from_type.isCompatible(Types.INTEGER)) {
  462. throw ProcessorErrorFactory.invalid_for_from(
  463. cmd.for_from,
  464. cmd.sourceInfo
  465. );
  466. }
  467. const to_type = this.evaluateExpressionType(cmd.for_to);
  468. if (!to_type.isCompatible(Types.INTEGER)) {
  469. throw ProcessorErrorFactory.invalid_for_to(cmd.for_to, cmd.sourceInfo);
  470. }
  471. if (cmd.for_pass != null) {
  472. const pass_type = this.evaluateExpressionType(cmd.for_pass);
  473. if (!pass_type.isCompatible(Types.INTEGER)) {
  474. throw ProcessorErrorFactory.invalid_for_pass(
  475. cmd.for_pass,
  476. cmd.sourceInfo
  477. );
  478. }
  479. }
  480. this.checkCommands(type, cmd.commands, optional);
  481. return false;
  482. } else if (cmd instanceof Switch) {
  483. const sType = this.evaluateExpressionType(cmd.expression);
  484. let result = optional;
  485. let hasDefault = false;
  486. for (let i = 0; i < cmd.cases.length; i++) {
  487. const aCase = cmd.cases[i];
  488. if (aCase.expression !== null) {
  489. const caseType = this.evaluateExpressionType(aCase.expression);
  490. if (!sType.isCompatible(caseType)) {
  491. const strInfo = sType.stringInfo();
  492. const info = strInfo[0];
  493. const strExp = aCase.expression.toString();
  494. throw ProcessorErrorFactory.invalid_case_type_full(
  495. strExp,
  496. info.type,
  497. info.dim,
  498. aCase.sourceInfo
  499. );
  500. }
  501. } else {
  502. hasDefault = true;
  503. }
  504. result = result && this.checkCommands(type, aCase.commands, result);
  505. }
  506. return result && hasDefault;
  507. } else if (cmd instanceof ArrayIndexAssign) {
  508. // TODO - rework!!!!!
  509. let used_dims = 0;
  510. const typeInfo = this.findSymbol(cmd.id, this.symbolMap);
  511. if (typeInfo === null) {
  512. throw ProcessorErrorFactory.symbol_not_found_full(
  513. cmd.id,
  514. cmd.sourceInfo
  515. );
  516. }
  517. if (typeInfo.isConst) {
  518. throw ProcessorErrorFactory.invalid_const_assignment_full(
  519. cmd.id,
  520. cmd.sourceInfo
  521. );
  522. }
  523. if (!(typeInfo.type instanceof ArrayType)) {
  524. throw ProcessorErrorFactory.invalid_array_access_full(
  525. cmd.id,
  526. cmd.sourceInfo
  527. );
  528. }
  529. const exp = cmd.expression;
  530. const lineExp = cmd.line;
  531. const lineType = this.evaluateExpressionType(lineExp);
  532. if (!lineType.isCompatible(Types.INTEGER)) {
  533. throw ProcessorErrorFactory.array_dimension_not_int_full(
  534. cmd.sourceInfo
  535. );
  536. }
  537. used_dims += 1;
  538. const columnExp = cmd.column;
  539. if (typeInfo.columns === null && columnExp !== null) {
  540. throw ProcessorErrorFactory.invalid_matrix_access_full(
  541. cmd.id,
  542. cmd.sourceInfo
  543. );
  544. } else if (columnExp !== null) {
  545. const columnType = this.evaluateExpressionType(columnExp);
  546. if (!columnType.isCompatible(Types.INTEGER)) {
  547. throw ProcessorErrorFactory.array_dimension_not_int_full(
  548. cmd.sourceInfo
  549. );
  550. }
  551. used_dims += 1;
  552. }
  553. // exp a single value exp or an array access
  554. const exp_type = this.evaluateExpressionType(exp);
  555. const access_type = typeInfo.type;
  556. let compatible = false;
  557. let type = access_type;
  558. if (exp_type instanceof MultiType) {
  559. if (access_type.dimensions - used_dims == 0) {
  560. type = access_type.innerType;
  561. } else {
  562. type = new ArrayType(
  563. access_type.innerType,
  564. Math.max(0, access_type.dimensions - used_dims)
  565. );
  566. }
  567. compatible = exp_type.isCompatible(type);
  568. } else {
  569. compatible = access_type.canAccept(exp_type, used_dims);
  570. }
  571. if (!compatible) {
  572. if (0 === access_type.dimensions - used_dims) {
  573. type = access_type.innerType; // enable a valid attempt to cast real <--> integer
  574. }
  575. if (
  576. !Config.enable_type_casting ||
  577. !Store.canImplicitTypeCast(type, exp_type)
  578. ) {
  579. const access_type_string_info = access_type.stringInfo();
  580. const access_type_info = access_type_string_info[0];
  581. const exp_type_string_info = exp_type.stringInfo();
  582. const exp_type_info = exp_type_string_info[0];
  583. throw ProcessorErrorFactory.incompatible_types_full(
  584. access_type_info.type,
  585. access_type_info.dim - used_dims,
  586. exp_type_info.type,
  587. exp_type_info.dim,
  588. exp.toString(),
  589. cmd.sourceInfo
  590. );
  591. }
  592. }
  593. return optional;
  594. } else if (cmd instanceof Assign) {
  595. // TODO - rework since there is no literal array assignment
  596. const typeInfo = this.findSymbol(cmd.id, this.symbolMap);
  597. if (typeInfo === null) {
  598. throw ProcessorErrorFactory.symbol_not_found_full(
  599. cmd.id,
  600. cmd.sourceInfo
  601. );
  602. }
  603. if (typeInfo.isConst) {
  604. throw ProcessorErrorFactory.invalid_const_assignment_full(
  605. cmd.id,
  606. cmd.sourceInfo
  607. );
  608. }
  609. const exp = cmd.expression;
  610. const exp_type = this.evaluateExpressionType(exp);
  611. if (exp_type instanceof ArrayType) {
  612. if (!(typeInfo.type instanceof ArrayType)) {
  613. // TODO better error message
  614. throw new Error("Cannot assign an array to a non-array variable ");
  615. }
  616. // Both are arrays...
  617. // if both don't have same dimensions and type, cannot perform assignment
  618. if (!exp_type.isCompatible(typeInfo.type)) {
  619. if (
  620. exp_type.dimensions === typeInfo.type.dimensions &&
  621. !exp_type.innerType.isCompatible(typeInfo.type.innerType)
  622. ) {
  623. if (
  624. !Config.enable_type_casting ||
  625. !Store.canImplicitTypeCast(
  626. typeInfo.type.innerType,
  627. exp_type.innerType
  628. )
  629. ) {
  630. const stringInfo = typeInfo.type.stringInfo();
  631. const info = stringInfo[0];
  632. const exp_type_string_info = exp_type.stringInfo();
  633. const exp_type_info = exp_type_string_info[0];
  634. throw ProcessorErrorFactory.incompatible_types_full(
  635. info.type,
  636. info.dim,
  637. exp_type_info.type,
  638. exp_type_info.dim,
  639. exp.toString(),
  640. cmd.sourceInfo
  641. );
  642. }
  643. } else {
  644. switch (exp_type.dimensions) {
  645. case 1: {
  646. throw ProcessorErrorFactory.vector_to_matrix_attr(
  647. cmd.id,
  648. exp.toString(),
  649. cmd.sourceInfo
  650. );
  651. }
  652. case 2: {
  653. throw ProcessorErrorFactory.matrix_to_vector_attr(
  654. cmd.id,
  655. exp.toString(),
  656. cmd.sourceInfo
  657. );
  658. }
  659. }
  660. }
  661. }
  662. } else if (!exp_type.isCompatible(typeInfo.type)) {
  663. if (
  664. !Config.enable_type_casting ||
  665. !Store.canImplicitTypeCast(typeInfo.type, exp_type)
  666. ) {
  667. const stringInfo = typeInfo.type.stringInfo();
  668. const info = stringInfo[0];
  669. const exp_type_string_info = exp_type.stringInfo();
  670. const exp_type_info = exp_type_string_info[0];
  671. throw ProcessorErrorFactory.incompatible_types_full(
  672. info.type,
  673. info.dim,
  674. exp_type_info.type,
  675. exp_type_info.dim,
  676. exp.toString(),
  677. cmd.sourceInfo
  678. );
  679. }
  680. }
  681. return optional;
  682. } else if (cmd instanceof Break) {
  683. return optional;
  684. } else if (cmd instanceof IfThenElse) {
  685. const resultType = this.evaluateExpressionType(cmd.condition);
  686. if (!resultType.isCompatible(Types.BOOLEAN)) {
  687. throw ProcessorErrorFactory.if_condition_type_full(
  688. cmd.condition.toString(),
  689. cmd.sourceInfo
  690. );
  691. }
  692. if (cmd.ifFalse instanceof IfThenElse) {
  693. return (
  694. this.checkCommands(type, cmd.ifTrue.commands, optional) &&
  695. this.checkCommand(type, cmd.ifFalse, optional)
  696. );
  697. } else if (cmd.ifFalse != null) {
  698. return (
  699. this.checkCommands(type, cmd.ifTrue.commands, optional) &&
  700. this.checkCommands(type, cmd.ifFalse.commands, optional)
  701. );
  702. } else {
  703. return this.checkCommands(type, cmd.ifTrue.commands, optional);
  704. }
  705. } else if (cmd instanceof FunctionCall) {
  706. let fun = null;
  707. if (cmd.isMainCall) {
  708. fun = this.getMainFunction();
  709. } else {
  710. fun = this.findFunction(cmd.id);
  711. }
  712. if (fun === null) {
  713. throw ProcessorErrorFactory.function_missing_full(
  714. cmd.id,
  715. cmd.sourceInfo
  716. );
  717. }
  718. this.assertParameters(fun, cmd.actualParameters);
  719. return optional;
  720. } else if (cmd instanceof Return) {
  721. const funcName = this.currentFunction.isMain
  722. ? LanguageDefinedFunction.getMainFunctionName()
  723. : this.currentFunction.name;
  724. if (cmd.expression === null && !type.isCompatible(Types.VOID)) {
  725. const stringInfo = type.stringInfo();
  726. const info = stringInfo[0];
  727. throw ProcessorErrorFactory.invalid_void_return_full(
  728. funcName,
  729. info.type,
  730. info.dim,
  731. cmd.sourceInfo
  732. );
  733. } else if (cmd.expression !== null) {
  734. const resultType = this.evaluateExpressionType(cmd.expression);
  735. if (!type.isCompatible(resultType)) {
  736. if (
  737. !Config.enable_type_casting ||
  738. !Store.canImplicitTypeCast(type, resultType)
  739. ) {
  740. const stringInfo = type.stringInfo();
  741. const info = stringInfo[0];
  742. throw ProcessorErrorFactory.invalid_return_type_full(
  743. funcName,
  744. info.type,
  745. info.dim,
  746. cmd.sourceInfo
  747. );
  748. }
  749. }
  750. return true;
  751. } else {
  752. return true;
  753. }
  754. }
  755. }
  756. checkCommands (type, cmds, optional) {
  757. return cmds.reduce(
  758. (last, next) => this.checkCommand(type, next, optional) || last,
  759. optional
  760. );
  761. }
  762. /**
  763. *
  764. * @param {import('./../../ast/commands/function').Function} fun
  765. * @param {Expression[]} actualParametersList
  766. */
  767. assertParameters (fun, actualParametersList) {
  768. const parameterList = fun.formalParameters;
  769. if (
  770. parameterList.length > actualParametersList.length ||
  771. (parameterList.length !== actualParametersList.length &&
  772. !fun.hasVariadic())
  773. ) {
  774. throw ProcessorErrorFactory.invalid_parameters_size_full(
  775. fun.name,
  776. actualParametersList.length,
  777. fun.formalParameters.length,
  778. null
  779. );
  780. }
  781. for (
  782. let i = 0, j = 0;
  783. i < parameterList.length && j < actualParametersList.length;
  784. i += 1, j += 1
  785. ) {
  786. const formalParam = parameterList[i];
  787. if (formalParam.variadic && i + 1 !== parameterList.length) {
  788. throw "A function variadic parameter must be its last parameter!";
  789. }
  790. if (formalParam.variadic) {
  791. j = this.assertVariadicParameter(
  792. fun,
  793. formalParam,
  794. j,
  795. actualParametersList
  796. );
  797. } else {
  798. const param = actualParametersList[j];
  799. this.assertParameter(fun, formalParam, param);
  800. }
  801. }
  802. }
  803. evaluateVectorLiteralType (literal, type) {
  804. // console.log(literal);
  805. for (let i = 0; i < literal.value.length; i += 1) {
  806. const exp = literal.value[i];
  807. const expType = this.evaluateExpressionType(exp);
  808. let compatible = false;
  809. if (expType instanceof MultiType) {
  810. compatible = expType.isCompatible(type.innerType);
  811. } else {
  812. compatible = type.canAccept(expType, 1);
  813. }
  814. if (!compatible) {
  815. if (
  816. !Config.enable_type_casting ||
  817. !Store.canImplicitTypeCast(type.innerType, expType)
  818. ) {
  819. const stringInfo = type.stringInfo();
  820. const info = stringInfo[0];
  821. const result_string_info = expType.stringInfo();
  822. const result_info = result_string_info[0];
  823. throw ProcessorErrorFactory.incompatible_types_full(
  824. info.type,
  825. 0,
  826. result_info.type,
  827. result_info.dim,
  828. exp.toString(),
  829. literal.sourceInfo
  830. );
  831. }
  832. }
  833. }
  834. return type;
  835. }
  836. /**
  837. *
  838. * @param {import('./../../ast/commands/function').Function} fun
  839. * @param {import('./../../ast/commands/formalParameter').FormalParameter} formalParam
  840. * @param {number} index
  841. * @param {Expression[]} actualParametersList
  842. */
  843. assertVariadicParameter (fun, formalParam, index, actualParametersList) {
  844. let i;
  845. for (i = index; i < actualParametersList.length; i += 1) {
  846. this.assertParameter(fun, formalParam, actualParametersList[i]);
  847. }
  848. return i - 1;
  849. }
  850. /**
  851. *
  852. * @param {import('./../../ast/commands/function').Function} fun
  853. * @param {import('./../../ast/commands/formalParameter').FormalParameter} formalParam
  854. * @param {Expression} actualParameter
  855. */
  856. assertParameter (fun, formalParam, actualParameter) {
  857. // const id = formalParam.id;
  858. if (formalParam.byRef) {
  859. if (actualParameter instanceof VariableLiteral) {
  860. const variable = this.findSymbol(actualParameter.id, this.symbolMap);
  861. if (variable.isConst) {
  862. throw ProcessorErrorFactory.invalid_const_ref_full(
  863. fun.name,
  864. actualParameter.toString(),
  865. actualParameter.sourceInfo
  866. );
  867. }
  868. } else if (
  869. !(
  870. actualParameter instanceof VariableLiteral ||
  871. actualParameter instanceof ArrayAccess
  872. )
  873. ) {
  874. throw ProcessorErrorFactory.invalid_parameter_type_full(
  875. fun.name,
  876. actualParameter.toString(),
  877. actualParameter.sourceInfo
  878. );
  879. }
  880. }
  881. const resultType = this.evaluateExpressionType(actualParameter);
  882. if (
  883. resultType instanceof MultiType &&
  884. formalParam.type instanceof MultiType
  885. ) {
  886. let shared = 0;
  887. for (let j = 0; j < resultType.types.length; ++j) {
  888. const element = resultType.types[j];
  889. if (formalParam.type.types.indexOf(element) !== -1) {
  890. shared += 1;
  891. }
  892. }
  893. if (shared <= 0) {
  894. if (Config.enable_type_casting && !formalParam.byRef) {
  895. if (
  896. (!resultType.isCompatible(Types.INTEGER) &&
  897. !resultType.isCompatible(Types.REAL)) ||
  898. formalParam.type.isCompatible(Types.INTEGER) ||
  899. formalParam.type.isCompatible(Types.REAL)
  900. ) {
  901. throw ProcessorErrorFactory.invalid_parameter_type_full(
  902. fun.name,
  903. actualParameter.toString(),
  904. actualParameter.sourceInfo
  905. );
  906. }
  907. }
  908. }
  909. } else if (resultType instanceof MultiType) {
  910. if (!resultType.isCompatible(formalParam.type)) {
  911. if (Config.enable_type_casting && !formalParam.byRef) {
  912. if (
  913. (!resultType.isCompatible(Types.INTEGER) &&
  914. !resultType.isCompatible(Types.REAL)) ||
  915. formalParam.type.isCompatible(Types.INTEGER) ||
  916. formalParam.type.isCompatible(Types.REAL)
  917. ) {
  918. throw ProcessorErrorFactory.invalid_parameter_type_full(
  919. fun.name,
  920. actualParameter.toString(),
  921. actualParameter.sourceInfo
  922. );
  923. }
  924. }
  925. }
  926. } else if (!formalParam.type.isCompatible(resultType)) {
  927. if (Config.enable_type_casting && !formalParam.byRef) {
  928. if (!Store.canImplicitTypeCast(formalParam.type, resultType)) {
  929. throw ProcessorErrorFactory.invalid_parameter_type_full(
  930. fun.name,
  931. actualParameter.toString(),
  932. actualParameter.sourceInfo
  933. );
  934. }
  935. }
  936. }
  937. }
  938. }