semanticAnalyser.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  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. if (exp_type instanceof MultiType) {
  558. let type = access_type;
  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 (
  573. !Config.enable_type_casting ||
  574. !Store.canImplicitTypeCast(access_type, exp_type)
  575. ) {
  576. const access_type_string_info = access_type.stringInfo();
  577. const access_type_info = access_type_string_info[0];
  578. const exp_type_string_info = exp_type.stringInfo();
  579. const exp_type_info = exp_type_string_info[0];
  580. throw ProcessorErrorFactory.incompatible_types_full(
  581. access_type_info.type,
  582. access_type_info.dim - used_dims,
  583. exp_type_info.type,
  584. exp_type_info.dim,
  585. exp.toString(),
  586. cmd.sourceInfo
  587. );
  588. }
  589. }
  590. return optional;
  591. } else if (cmd instanceof Assign) {
  592. // TODO - rework since there is no literal array assignment
  593. const typeInfo = this.findSymbol(cmd.id, this.symbolMap);
  594. if (typeInfo === null) {
  595. throw ProcessorErrorFactory.symbol_not_found_full(
  596. cmd.id,
  597. cmd.sourceInfo
  598. );
  599. }
  600. if (typeInfo.isConst) {
  601. throw ProcessorErrorFactory.invalid_const_assignment_full(
  602. cmd.id,
  603. cmd.sourceInfo
  604. );
  605. }
  606. const exp = cmd.expression;
  607. const exp_type = this.evaluateExpressionType(exp);
  608. if (exp_type instanceof ArrayType) {
  609. if (!(typeInfo.type instanceof ArrayType)) {
  610. // TODO better error message
  611. throw new Error("Cannot assign an array to a non-array variable ");
  612. }
  613. // Both are arrays...
  614. // if both don't have same dimensions and type, cannot perform assignment
  615. if (!exp_type.isCompatible(typeInfo.type)) {
  616. if (
  617. exp_type.dimensions === typeInfo.type.dimensions &&
  618. !exp_type.innerType.isCompatible(typeInfo.type.innerType)
  619. ) {
  620. if (
  621. !Config.enable_type_casting ||
  622. !Store.canImplicitTypeCast(
  623. typeInfo.type.innerType,
  624. exp_type.innerType
  625. )
  626. ) {
  627. const stringInfo = typeInfo.type.stringInfo();
  628. const info = stringInfo[0];
  629. const exp_type_string_info = exp_type.stringInfo();
  630. const exp_type_info = exp_type_string_info[0];
  631. throw ProcessorErrorFactory.incompatible_types_full(
  632. info.type,
  633. info.dim,
  634. exp_type_info.type,
  635. exp_type_info.dim,
  636. exp.toString(),
  637. cmd.sourceInfo
  638. );
  639. }
  640. } else {
  641. switch (exp_type.dimensions) {
  642. case 1: {
  643. throw ProcessorErrorFactory.vector_to_matrix_attr(
  644. cmd.id,
  645. exp.toString(),
  646. cmd.sourceInfo
  647. );
  648. }
  649. case 2: {
  650. throw ProcessorErrorFactory.matrix_to_vector_attr(
  651. cmd.id,
  652. exp.toString(),
  653. cmd.sourceInfo
  654. );
  655. }
  656. }
  657. }
  658. }
  659. } else if (!exp_type.isCompatible(typeInfo.type)) {
  660. if (
  661. !Config.enable_type_casting ||
  662. !Store.canImplicitTypeCast(typeInfo.type, exp_type)
  663. ) {
  664. const stringInfo = typeInfo.type.stringInfo();
  665. const info = stringInfo[0];
  666. const exp_type_string_info = exp_type.stringInfo();
  667. const exp_type_info = exp_type_string_info[0];
  668. throw ProcessorErrorFactory.incompatible_types_full(
  669. info.type,
  670. info.dim,
  671. exp_type_info.type,
  672. exp_type_info.dim,
  673. exp.toString(),
  674. cmd.sourceInfo
  675. );
  676. }
  677. }
  678. return optional;
  679. } else if (cmd instanceof Break) {
  680. return optional;
  681. } else if (cmd instanceof IfThenElse) {
  682. const resultType = this.evaluateExpressionType(cmd.condition);
  683. if (!resultType.isCompatible(Types.BOOLEAN)) {
  684. throw ProcessorErrorFactory.if_condition_type_full(
  685. cmd.condition.toString(),
  686. cmd.sourceInfo
  687. );
  688. }
  689. if (cmd.ifFalse instanceof IfThenElse) {
  690. return (
  691. this.checkCommands(type, cmd.ifTrue.commands, optional) &&
  692. this.checkCommand(type, cmd.ifFalse, optional)
  693. );
  694. } else if (cmd.ifFalse != null) {
  695. return (
  696. this.checkCommands(type, cmd.ifTrue.commands, optional) &&
  697. this.checkCommands(type, cmd.ifFalse.commands, optional)
  698. );
  699. } else {
  700. return this.checkCommands(type, cmd.ifTrue.commands, optional);
  701. }
  702. } else if (cmd instanceof FunctionCall) {
  703. let fun = null;
  704. if (cmd.isMainCall) {
  705. fun = this.getMainFunction();
  706. } else {
  707. fun = this.findFunction(cmd.id);
  708. }
  709. if (fun === null) {
  710. throw ProcessorErrorFactory.function_missing_full(
  711. cmd.id,
  712. cmd.sourceInfo
  713. );
  714. }
  715. this.assertParameters(fun, cmd.actualParameters);
  716. return optional;
  717. } else if (cmd instanceof Return) {
  718. const funcName = this.currentFunction.isMain
  719. ? LanguageDefinedFunction.getMainFunctionName()
  720. : this.currentFunction.name;
  721. if (cmd.expression === null && !type.isCompatible(Types.VOID)) {
  722. const stringInfo = type.stringInfo();
  723. const info = stringInfo[0];
  724. throw ProcessorErrorFactory.invalid_void_return_full(
  725. funcName,
  726. info.type,
  727. info.dim,
  728. cmd.sourceInfo
  729. );
  730. } else if (cmd.expression !== null) {
  731. const resultType = this.evaluateExpressionType(cmd.expression);
  732. if (!type.isCompatible(resultType)) {
  733. if (
  734. !Config.enable_type_casting ||
  735. !Store.canImplicitTypeCast(type, resultType)
  736. ) {
  737. const stringInfo = type.stringInfo();
  738. const info = stringInfo[0];
  739. throw ProcessorErrorFactory.invalid_return_type_full(
  740. funcName,
  741. info.type,
  742. info.dim,
  743. cmd.sourceInfo
  744. );
  745. }
  746. }
  747. return true;
  748. } else {
  749. return true;
  750. }
  751. }
  752. }
  753. checkCommands (type, cmds, optional) {
  754. return cmds.reduce(
  755. (last, next) => this.checkCommand(type, next, optional) || last,
  756. optional
  757. );
  758. }
  759. /**
  760. *
  761. * @param {import('./../../ast/commands/function').Function} fun
  762. * @param {Expression[]} actualParametersList
  763. */
  764. assertParameters (fun, actualParametersList) {
  765. const parameterList = fun.formalParameters;
  766. if (
  767. parameterList.length > actualParametersList.length ||
  768. (parameterList.length !== actualParametersList.length &&
  769. !fun.hasVariadic())
  770. ) {
  771. throw ProcessorErrorFactory.invalid_parameters_size_full(
  772. fun.name,
  773. actualParametersList.length,
  774. fun.formalParameters.length,
  775. null
  776. );
  777. }
  778. for (
  779. let i = 0, j = 0;
  780. i < parameterList.length && j < actualParametersList.length;
  781. i += 1, j += 1
  782. ) {
  783. const formalParam = parameterList[i];
  784. if (formalParam.variadic && i + 1 !== parameterList.length) {
  785. throw "A function variadic parameter must be its last parameter!";
  786. }
  787. if (formalParam.variadic) {
  788. j = this.assertVariadicParameter(
  789. fun,
  790. formalParam,
  791. j,
  792. actualParametersList
  793. );
  794. } else {
  795. const param = actualParametersList[j];
  796. this.assertParameter(fun, formalParam, param);
  797. }
  798. }
  799. }
  800. evaluateVectorLiteralType (literal, type) {
  801. // console.log(literal);
  802. for (let i = 0; i < literal.value.length; i += 1) {
  803. const exp = literal.value[i];
  804. const expType = this.evaluateExpressionType(exp);
  805. let compatible = false;
  806. if (expType instanceof MultiType) {
  807. compatible = expType.isCompatible(type.innerType);
  808. } else {
  809. compatible = type.canAccept(expType, 1);
  810. }
  811. if (!compatible) {
  812. if (
  813. !Config.enable_type_casting ||
  814. !Store.canImplicitTypeCast(type.innerType, expType)
  815. ) {
  816. const stringInfo = type.stringInfo();
  817. const info = stringInfo[0];
  818. const result_string_info = expType.stringInfo();
  819. const result_info = result_string_info[0];
  820. throw ProcessorErrorFactory.incompatible_types_full(
  821. info.type,
  822. 0,
  823. result_info.type,
  824. result_info.dim,
  825. exp.toString(),
  826. literal.sourceInfo
  827. );
  828. }
  829. }
  830. }
  831. return type;
  832. }
  833. /**
  834. *
  835. * @param {import('./../../ast/commands/function').Function} fun
  836. * @param {import('./../../ast/commands/formalParameter').FormalParameter} formalParam
  837. * @param {number} index
  838. * @param {Expression[]} actualParametersList
  839. */
  840. assertVariadicParameter (fun, formalParam, index, actualParametersList) {
  841. let i;
  842. for (i = index; i < actualParametersList.length; i += 1) {
  843. this.assertParameter(fun, formalParam, actualParametersList[i]);
  844. }
  845. return i - 1;
  846. }
  847. /**
  848. *
  849. * @param {import('./../../ast/commands/function').Function} fun
  850. * @param {import('./../../ast/commands/formalParameter').FormalParameter} formalParam
  851. * @param {Expression} actualParameter
  852. */
  853. assertParameter (fun, formalParam, actualParameter) {
  854. // const id = formalParam.id;
  855. if (formalParam.byRef) {
  856. if (actualParameter instanceof VariableLiteral) {
  857. const variable = this.findSymbol(actualParameter.id, this.symbolMap);
  858. if (variable.isConst) {
  859. throw ProcessorErrorFactory.invalid_const_ref_full(
  860. fun.name,
  861. actualParameter.toString(),
  862. actualParameter.sourceInfo
  863. );
  864. }
  865. } else if (
  866. !(
  867. actualParameter instanceof VariableLiteral ||
  868. actualParameter instanceof ArrayAccess
  869. )
  870. ) {
  871. throw ProcessorErrorFactory.invalid_parameter_type_full(
  872. fun.name,
  873. actualParameter.toString(),
  874. actualParameter.sourceInfo
  875. );
  876. }
  877. }
  878. const resultType = this.evaluateExpressionType(actualParameter);
  879. if (
  880. resultType instanceof MultiType &&
  881. formalParam.type instanceof MultiType
  882. ) {
  883. let shared = 0;
  884. for (let j = 0; j < resultType.types.length; ++j) {
  885. const element = resultType.types[j];
  886. if (formalParam.type.types.indexOf(element) !== -1) {
  887. shared += 1;
  888. }
  889. }
  890. if (shared <= 0) {
  891. if (Config.enable_type_casting && !formalParam.byRef) {
  892. if (
  893. (!resultType.isCompatible(Types.INTEGER) &&
  894. !resultType.isCompatible(Types.REAL)) ||
  895. formalParam.type.isCompatible(Types.INTEGER) ||
  896. formalParam.type.isCompatible(Types.REAL)
  897. ) {
  898. throw ProcessorErrorFactory.invalid_parameter_type_full(
  899. fun.name,
  900. actualParameter.toString(),
  901. actualParameter.sourceInfo
  902. );
  903. }
  904. }
  905. }
  906. } else if (resultType instanceof MultiType) {
  907. if (!resultType.isCompatible(formalParam.type)) {
  908. if (Config.enable_type_casting && !formalParam.byRef) {
  909. if (
  910. (!resultType.isCompatible(Types.INTEGER) &&
  911. !resultType.isCompatible(Types.REAL)) ||
  912. formalParam.type.isCompatible(Types.INTEGER) ||
  913. formalParam.type.isCompatible(Types.REAL)
  914. ) {
  915. throw ProcessorErrorFactory.invalid_parameter_type_full(
  916. fun.name,
  917. actualParameter.toString(),
  918. actualParameter.sourceInfo
  919. );
  920. }
  921. }
  922. }
  923. } else if (!formalParam.type.isCompatible(resultType)) {
  924. if (Config.enable_type_casting && !formalParam.byRef) {
  925. if (!Store.canImplicitTypeCast(formalParam.type, resultType)) {
  926. throw ProcessorErrorFactory.invalid_parameter_type_full(
  927. fun.name,
  928. actualParameter.toString(),
  929. actualParameter.sourceInfo
  930. );
  931. }
  932. }
  933. }
  934. }
  935. }