import { FunctionCall, Literal, UnaryApp, InfixApp, IntLiteral, RealLiteral, StringLiteral, VariableLiteral, ArrayAccess, BoolLiteral } from "./../ast/expressions"; import { Types } from "./../typeSystem/types"; import { ArrayType } from "./../typeSystem/array_type"; import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from "./../processor/compatibilityTable"; import { LanguageDefinedFunction } from "./../processor/definedFunctions"; export class BaseConverter { constructor (ivprogAST) { this.ivprogAST = ivprogAST; this.globalMap = new Map(); this.symbolMap = []; this.symbolMap.push(this.globalMap); } popContext () { if (this.symbolMap.length > 1) { this.symbolMap.pop(); } } pushContext (map) { this.symbolMap.push(map); } findFunction (name) { if (name.match(/^\$.+$/)) { const fun = LanguageDefinedFunction.getFunction(name); return fun; } else { const val = this.ivprogAST.functions.find(v => v.name === name); return val; } } findSymbol (id) { for (let i = this.symbolMap.length - 1; i >= 0; i -= 1) { const map = this.symbolMap[i]; if (map.has(id)) { return map.get(id); } } return null; } insertGlobalSymbol (id, declaration) { this.globalMap.set(id, { id: id, type: declaration.type, global: true }); } insertSymbol (id, declaration) { const map = this.symbolMap.slice(-1)[0]; map.set(id, { id: id, type: declaration.type, global: false }); } evaluateExpressionType (expression) { if (expression instanceof UnaryApp) { const op = expression.op; const resultType = this.evaluateExpressionType(expression.left); const finalResult = resultTypeAfterUnaryOp(op, resultType); return finalResult; } else if (expression instanceof InfixApp) { const op = expression.op; const resultTypeLeft = this.evaluateExpressionType(expression.left); const resultTypeRight = this.evaluateExpressionType(expression.right); const finalResult = resultTypeAfterInfixOp( op, resultTypeLeft, resultTypeRight ); return finalResult; } else if (expression instanceof Literal) { return this.evaluateLiteralType(expression); } else if (expression instanceof FunctionCall) { const fun = this.findFunction(expression.id); return fun.returnType; } else if (expression instanceof ArrayAccess) { const arrayTypeInfo = this.findSymbol(expression.id); const arrType = arrayTypeInfo.type; if (expression.column !== null) { // indexing matrix return arrType.innerType; } else { if (arrayTypeInfo.columns === null) { return arrType.innerType; } return new ArrayType(arrType.innerType, 1); } } } evaluateLiteralType (literal) { if (literal instanceof IntLiteral) { return literal.type; } else if (literal instanceof RealLiteral) { return literal.type; } else if (literal instanceof StringLiteral) { return literal.type; } else if (literal instanceof BoolLiteral) { return literal.type; } else if (literal instanceof VariableLiteral) { const typeInfo = this.findSymbol(literal.id); return typeInfo.type; } else { console.warn("Evaluating type only for an array literal..."); // This should never happen in this context and there is no use throwing execeptions! return new ArrayType(Types.INTEGER, 1); } } }