|
@@ -2,11 +2,11 @@ import { ProcessorErrorFactory } from './../error/processorErrorFactory';
|
|
|
import { LanguageDefinedFunction } from './../definedFunctions';
|
|
|
import { LanguageService } from './../../services/languageService';
|
|
|
import { ArrayDeclaration, While, For, Switch, Assign, Break, IfThenElse, Return, ArrayIndexAssign } from '../../ast/commands';
|
|
|
-import { InfixApp, UnaryApp, FunctionCall, IntLiteral, RealLiteral, StringLiteral, BoolLiteral, VariableLiteral, ArrayLiteral, ArrayAccess } from '../../ast/expressions';
|
|
|
+import { InfixApp, UnaryApp, FunctionCall, IntLiteral, RealLiteral, StringLiteral, BoolLiteral, VariableLiteral, ArrayAccess } from '../../ast/expressions';
|
|
|
import { Literal } from '../../ast/expressions/literal';
|
|
|
import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from '../compatibilityTable';
|
|
|
import { Types } from '../../typeSystem/types';
|
|
|
-import { CompoundType } from '../../typeSystem/compoundType';
|
|
|
+import { ArrayType } from '../../typeSystem/array_type';
|
|
|
import { MultiType } from '../../typeSystem/multiType';
|
|
|
import { Config } from '../../util/config';
|
|
|
import { Store } from '../store/store';
|
|
@@ -103,22 +103,8 @@ export class SemanticAnalyser {
|
|
|
|
|
|
assertDeclaration (declaration) {
|
|
|
if (declaration instanceof ArrayDeclaration) {
|
|
|
- if(declaration.initial === null) {
|
|
|
- const lineType = this.evaluateExpressionType(declaration.lines);
|
|
|
- if (!lineType.isCompatible(Types.INTEGER)) {
|
|
|
- throw ProcessorErrorFactory.array_dimension_not_int_full(declaration.sourceInfo);
|
|
|
- }
|
|
|
- if (declaration.columns !== null) {
|
|
|
- const columnType = this.evaluateExpressionType(declaration.columns);
|
|
|
- if (!columnType.isCompatible(Types.INTEGER)) {
|
|
|
- throw ProcessorErrorFactory.array_dimension_not_int_full(declaration.sourceInfo);
|
|
|
- }
|
|
|
- }
|
|
|
- this.insertSymbol(declaration.id, {id: declaration.id, lines: declaration.lines, columns: declaration.columns, type: declaration.type, isConst: declaration.isConst});
|
|
|
- return;
|
|
|
- }
|
|
|
- this.evaluateArrayLiteral(declaration.id, declaration.lines, declaration.columns, declaration.type, declaration.initial);
|
|
|
- this.insertSymbol(declaration.id, {id: declaration.id, lines: declaration.lines, columns: declaration.columns, type: declaration.type, isConst: declaration.isConst});
|
|
|
+ this.assertArrayDeclaration(declaration);
|
|
|
+ this.insertSymbol(declaration.id, {id: declaration.id, lines: declaration.lines, columns: declaration.columns, type: declaration.type});
|
|
|
|
|
|
} else {
|
|
|
if(declaration.initial === null) {
|
|
@@ -145,6 +131,25 @@ export class SemanticAnalyser {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ assertArrayDeclaration (declaration) {
|
|
|
+ if(declaration.initial === null) {
|
|
|
+ const lineType = this.evaluateExpressionType(declaration.lines);
|
|
|
+ if (!lineType.isCompatible(Types.INTEGER)) {
|
|
|
+ throw ProcessorErrorFactory.array_dimension_not_int_full(declaration.sourceInfo);
|
|
|
+ }
|
|
|
+ if (declaration.columns !== null) {
|
|
|
+ const columnType = this.evaluateExpressionType(declaration.columns);
|
|
|
+ if (!columnType.isCompatible(Types.INTEGER)) {
|
|
|
+ throw ProcessorErrorFactory.array_dimension_not_int_full(declaration.sourceInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.evaluateArrayLiteral(declaration);
|
|
|
+ }
|
|
|
+ this.insertSymbol(declaration.id, {id: declaration.id, lines: declaration.lines, columns: declaration.columns, type: declaration.type});
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
evaluateExpressionType (expression) {
|
|
|
// TODO: Throw operator error in case type == UNDEFINED
|
|
|
if(expression instanceof UnaryApp) {
|
|
@@ -192,7 +197,7 @@ export class SemanticAnalyser {
|
|
|
if(arrayTypeInfo === null) {
|
|
|
throw ProcessorErrorFactory.symbol_not_found_full(expression.id, expression.sourceInfo);
|
|
|
}
|
|
|
- if (!(arrayTypeInfo.type instanceof CompoundType)) {
|
|
|
+ if (!(arrayTypeInfo.type instanceof ArrayType)) {
|
|
|
throw ProcessorErrorFactory.invalid_array_access_full(expression.id, expression.sourceInfo);
|
|
|
}
|
|
|
const lineType = this.evaluateExpressionType(expression.line);
|
|
@@ -216,7 +221,7 @@ export class SemanticAnalyser {
|
|
|
if(arrayTypeInfo.columns === null) {
|
|
|
return arrType.innerType;
|
|
|
}
|
|
|
- return new CompoundType(arrType.innerType, 1);
|
|
|
+ return new ArrayType(arrType.innerType, 1);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -235,7 +240,7 @@ export class SemanticAnalyser {
|
|
|
if(typeInfo === null) {
|
|
|
throw ProcessorErrorFactory.symbol_not_found_full(literal.id, literal.sourceInfo);
|
|
|
}
|
|
|
- if (typeInfo.type instanceof CompoundType) {
|
|
|
+ if (typeInfo.type instanceof ArrayType) {
|
|
|
return typeInfo.type;
|
|
|
}
|
|
|
return typeInfo.type;
|
|
@@ -257,83 +262,25 @@ export class SemanticAnalyser {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- if(last instanceof CompoundType) {
|
|
|
- return new CompoundType(last.innerType, last.dimensions + 1);
|
|
|
+ if(last instanceof ArrayType) {
|
|
|
+ return new ArrayType(last.innerType, last.dimensions + 1);
|
|
|
}
|
|
|
- return new CompoundType(last, 1);
|
|
|
+ return new ArrayType(last, 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- evaluateArrayLiteral (/*id, lines, columns, type, literal*/) {
|
|
|
- /* if (literal instanceof ArrayLiteral) {
|
|
|
- const dimType = this.evaluateExpressionType(lines);
|
|
|
- if (!dimType.isCompatible(Types.INTEGER)) {
|
|
|
- throw ProcessorErrorFactory.array_dimension_not_int_full(literal.sourceInfo);
|
|
|
- }
|
|
|
- if ((lines instanceof IntLiteral)) {
|
|
|
- if (!lines.value.eq(literal.value.length)) {
|
|
|
- if(type.dimensions > 1) {
|
|
|
- throw ProcessorErrorFactory.matrix_line_outbounds_full(id, literal.value.length, lines.value.toNumber(), literal.sourceInfo)
|
|
|
- } else {
|
|
|
- throw ProcessorErrorFactory.vector_line_outbounds_full(id, literal.value.length, lines.value.toNumber(), literal.sourceInfo)
|
|
|
- }
|
|
|
- } else if (lines.value.isNeg()) {
|
|
|
- throw ProcessorErrorFactory.array_dimension_not_positive_full(literal.sourceInfo);
|
|
|
- }
|
|
|
- }
|
|
|
- if (columns === null) {
|
|
|
- // it's a vector...
|
|
|
- literal.value.reduce((last, next) => {
|
|
|
- const eType = this.evaluateExpressionType(next);
|
|
|
- if (!last.canAccept(eType)) {
|
|
|
- const strInfo = last.stringInfo();
|
|
|
- const info = strInfo[0];
|
|
|
- const strExp = literal.toString();
|
|
|
- throw ProcessorErrorFactory.incompatible_types_array_full(strExp,info.type, info.dim, literal.sourceInfo);
|
|
|
- }
|
|
|
- return last;
|
|
|
- }, type);
|
|
|
- return true;
|
|
|
- } else {
|
|
|
- const dimType = this.evaluateExpressionType(columns);
|
|
|
- if (!dimType.isCompatible(Types.INTEGER)) {
|
|
|
- throw ProcessorErrorFactory.array_dimension_not_int_full(literal.sourceInfo);
|
|
|
- }
|
|
|
- if ((columns instanceof IntLiteral)) {
|
|
|
- const columnValue = literal.value[0].value.length;
|
|
|
- if (!columns.value.eq(columnValue)) {
|
|
|
- if(type.dimensions > 1) {
|
|
|
- throw ProcessorErrorFactory.matrix_column_outbounds_full(id, literal.value.length, columns.value.toNumber(), literal.sourceInfo)
|
|
|
- } else {
|
|
|
- throw ProcessorErrorFactory.invalid_matrix_access_full(id, literal.sourceInfo);
|
|
|
- }
|
|
|
- } else if (columns.value.isNeg()) {
|
|
|
- throw ProcessorErrorFactory.array_dimension_not_positive_full(literal.sourceInfo);
|
|
|
- }
|
|
|
- for (let i = 0; i < columns; i++) {
|
|
|
- const anotherArray = literal.value[i];
|
|
|
- this.evaluateArrayLiteral(id, columns, null, type, anotherArray)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
+ evaluateArrayLiteral (arrayDeclaration) {
|
|
|
+ const type = arrayDeclaration.type;
|
|
|
+ const literal = arrayDeclaration.initial;
|
|
|
+ if(arrayDeclaration.isVector) {
|
|
|
+ this.evaluateVectorLiteralType(literal, type);
|
|
|
} else {
|
|
|
-
|
|
|
- const resultType = this.evaluateExpressionType(literal);
|
|
|
- if (!(resultType instanceof CompoundType)) {
|
|
|
- const strInfo = type.stringInfo();
|
|
|
- const info = strInfo[0];
|
|
|
- const strExp = literal.toString();
|
|
|
- throw ProcessorErrorFactory.incompatible_types_array_full(strExp,info.type, info.dim, literal.sourceInfo);
|
|
|
- }
|
|
|
- if (!type.isCompatible(resultType)) {
|
|
|
- const strInfo = type.stringInfo();
|
|
|
- const info = strInfo[0];
|
|
|
- const strExp = literal.toString();
|
|
|
- throw ProcessorErrorFactory.incompatible_types_array_full(strExp,info.type, info.dim, literal.sourceInfo);
|
|
|
- }
|
|
|
- return true;
|
|
|
- } */
|
|
|
+ // TODO matrix type check
|
|
|
+ for(let i = 0; i < literal.lines; ++i) {
|
|
|
+ const line_literal = literal.value[i];
|
|
|
+ this.evaluateVectorLiteralType(line_literal, new ArrayType(type.innerType, 1));
|
|
|
+ }
|
|
|
+ }
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -341,7 +288,7 @@ export class SemanticAnalyser {
|
|
|
this.pushMap();
|
|
|
this.currentFunction = fun;
|
|
|
fun.formalParameters.forEach(formalParam => {
|
|
|
- if(formalParam.type instanceof CompoundType) {
|
|
|
+ if(formalParam.type instanceof ArrayType) {
|
|
|
if(formalParam.type.dimensions > 1) {
|
|
|
this.insertSymbol(formalParam.id, {id: formalParam.id, lines: -1, columns: -1, type: formalParam.type});
|
|
|
} else {
|
|
@@ -405,11 +352,12 @@ export class SemanticAnalyser {
|
|
|
return result && hasDefault;
|
|
|
|
|
|
} else if (cmd instanceof ArrayIndexAssign) {
|
|
|
+ // TODO - rework!!!!!
|
|
|
const typeInfo = this.findSymbol(cmd.id, this.symbolMap);
|
|
|
if(typeInfo === null) {
|
|
|
throw ProcessorErrorFactory.symbol_not_found_full(cmd.id, cmd.sourceInfo);
|
|
|
}
|
|
|
- if(!(typeInfo.type instanceof CompoundType)) {
|
|
|
+ if(!(typeInfo.type instanceof ArrayType)) {
|
|
|
throw ProcessorErrorFactory.invalid_array_access_full(cmd.id, cmd.sourceInfo);
|
|
|
}
|
|
|
const exp = cmd.expression;
|
|
@@ -421,37 +369,61 @@ export class SemanticAnalyser {
|
|
|
const columnExp = cmd.column;
|
|
|
if (typeInfo.columns === null && columnExp !== null) {
|
|
|
throw ProcessorErrorFactory.invalid_matrix_access_full(cmd.id, cmd.sourceInfo);
|
|
|
+ } else if (!typeInfo.type.isVector && columnExp == null) {
|
|
|
+ throw new Error("Cannot assign to matrix line");
|
|
|
} else if (columnExp !== null) {
|
|
|
const columnType = this.evaluateExpressionType(columnExp);
|
|
|
if (!columnType.isCompatible(Types.INTEGER)) {
|
|
|
throw ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo);
|
|
|
}
|
|
|
}
|
|
|
- // exp can be a arrayLiteral, a single value exp or an array access
|
|
|
- if(exp instanceof ArrayLiteral) {
|
|
|
- this.evaluateArrayLiteral(cmd.id, typeInfo.lines, (columnExp ? typeInfo.columns : null), typeInfo.type, exp);
|
|
|
+ // exp a single value exp or an array access
|
|
|
+ const exp_type = this.evaluateExpressionType(exp);
|
|
|
+ if(exp_type instanceof ArrayType) {
|
|
|
+ // TODO better error message
|
|
|
+ throw new Error("Cannot assign a matrix/vector");
|
|
|
+ }
|
|
|
+ let compatible = false;
|
|
|
+ if(exp_type instanceof MultiType) {
|
|
|
+ compatible = exp_type.isCompatible(typeInfo.type.innerType);
|
|
|
} else {
|
|
|
- // cannot properly evaluate since type system is poorly constructed
|
|
|
+ compatible = typeInfo.type.canAccept(exp_type);
|
|
|
+ }
|
|
|
+ if(!compatible) {
|
|
|
+ if(!Config.enable_type_casting || !Store.canImplicitTypeCast(typeInfo.type.innerType, exp_type)) {
|
|
|
+ throw new Error("invalid vector element type");
|
|
|
+ }
|
|
|
}
|
|
|
return optional;
|
|
|
} else if (cmd instanceof Assign) {
|
|
|
+ // TODO - rework since there is no literal array assignment
|
|
|
const typeInfo = this.findSymbol(cmd.id, this.symbolMap);
|
|
|
if(typeInfo === null) {
|
|
|
throw ProcessorErrorFactory.symbol_not_found_full(cmd.id, cmd.sourceInfo);
|
|
|
}
|
|
|
const exp = cmd.expression;
|
|
|
- if(exp instanceof ArrayLiteral) {
|
|
|
- if(!(typeInfo.type instanceof CompoundType)) {
|
|
|
- const stringInfo = typeInfo.type.stringInfo();
|
|
|
- const info = stringInfo[0];
|
|
|
- throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo);
|
|
|
+ const exp_type = this.evaluateExpressionType(exp);
|
|
|
+ if(exp_type instanceof ArrayType) {
|
|
|
+ if(!(typeInfo.type instanceof ArrayType)) {
|
|
|
+ // TODO better error message
|
|
|
+ throw new Error("Cannot assign an array to a non-array variable ");
|
|
|
+ }
|
|
|
+ // Both are arrays...
|
|
|
+ // if both don't have same dimensions and type, cannot perform assignment
|
|
|
+ if(!exp_type.isCompatible(typeInfo.type)) {
|
|
|
+ if(exp_type.dimensions === typeInfo.type.dimensions && !exp_type.innerType.isCompatible(typeInfo.type.innerType)) {
|
|
|
+ if(!Config.enable_type_casting || !Store.canImplicitTypeCast(typeInfo.type.innerType, exp_type.innerType)) {
|
|
|
+ const stringInfo = typeInfo.type.stringInfo();
|
|
|
+ const info = stringInfo[0];
|
|
|
+ throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // TODO better error message
|
|
|
+ throw new Error("Cannot assign a vector to matrix or matrix to vector");
|
|
|
+ }
|
|
|
}
|
|
|
- this.evaluateArrayLiteral(cmd.id, typeInfo.lines, typeInfo.columns, typeInfo.type, exp);
|
|
|
- } else {
|
|
|
- const resultType = this.evaluateExpressionType(exp);
|
|
|
- if((!resultType.isCompatible(typeInfo.type) && !Config.enable_type_casting)
|
|
|
- || (!resultType.isCompatible(typeInfo.type) && Config.enable_type_casting
|
|
|
- && !Store.canImplicitTypeCast(typeInfo.type, resultType))) {
|
|
|
+ } else if(!exp_type.isCompatible(typeInfo.type)) {
|
|
|
+ if(!Config.enable_type_casting || !Store.canImplicitTypeCast(typeInfo.type, exp_type)) {
|
|
|
const stringInfo = typeInfo.type.stringInfo();
|
|
|
const info = stringInfo[0];
|
|
|
throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo);
|
|
@@ -536,7 +508,7 @@ export class SemanticAnalyser {
|
|
|
for (let j = 0; j < resultType.types.length; ++j) {
|
|
|
const element = resultType.types[j];
|
|
|
if(formalParam.type.types.indexOf(element) !== -1) {
|
|
|
- shared++;
|
|
|
+ shared += 1;
|
|
|
}
|
|
|
}
|
|
|
if(shared <= 0) {
|
|
@@ -571,4 +543,25 @@ export class SemanticAnalyser {
|
|
|
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ evaluateVectorLiteralType (literal, type) {
|
|
|
+ for(let i = 0; i < literal.value.length; i+=1) {
|
|
|
+ const exp = literal.value[i];
|
|
|
+ const expType = this.evaluateExpressionType(exp);
|
|
|
+ let compatible = false;
|
|
|
+ if(expType instanceof MultiType) {
|
|
|
+ compatible = expType.isCompatible(type.innerType);
|
|
|
+ } else {
|
|
|
+ compatible = type.canAccept(expType);
|
|
|
+ }
|
|
|
+ if(!compatible) {
|
|
|
+ // vector wrong type
|
|
|
+ // TODO better error message
|
|
|
+ if(!Config.enable_type_casting || !Store.canImplicitTypeCast(type.innerType, expType)) {
|
|
|
+ throw new Error("invalid vector element type");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return type;
|
|
|
+ }
|
|
|
}
|