|
@@ -2,6 +2,8 @@ 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 { Expression } from './../../ast/expressions/expression'
|
|
|
import { InfixApp, UnaryApp, FunctionCall, IntLiteral, RealLiteral, StringLiteral, BoolLiteral, VariableLiteral, ArrayAccess } from '../../ast/expressions';
|
|
|
import { Literal } from '../../ast/expressions/literal';
|
|
|
import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from '../compatibilityTable';
|
|
@@ -530,69 +532,36 @@ export class SemanticAnalyser {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ *
|
|
|
+ * @param {import('./../../ast/commands/function').Function} fun
|
|
|
+ * @param {Expression[]} actualParametersList
|
|
|
+ */
|
|
|
assertParameters (fun, actualParametersList) {
|
|
|
- if (fun.formalParameters.length !== actualParametersList.length) {
|
|
|
- throw ProcessorErrorFactory.invalid_parameters_size_full(fun.name, actualParametersList.length, fun.formalParameters.length, null);
|
|
|
+ const parameterList = fun.formalParameters;
|
|
|
+ if ((parameterList.length > actualParametersList.length)
|
|
|
+ || (parameterList.length !== actualParametersList.length && !fun.hasVariadic())) {
|
|
|
+ throw ProcessorErrorFactory.invalid_parameters_size_full(fun.name, actualParametersList.length,
|
|
|
+ fun.formalParameters.length, null);
|
|
|
}
|
|
|
- for (let i = 0; i < actualParametersList.length; ++i) {
|
|
|
- const param = actualParametersList[i];
|
|
|
- const formalParam = fun.formalParameters[i];
|
|
|
-
|
|
|
- if(formalParam.byRef) {
|
|
|
- if(param instanceof VariableLiteral) {
|
|
|
- const variable = this.findSymbol(param.id, this.symbolMap);
|
|
|
- if (variable.isConst) {
|
|
|
- throw ProcessorErrorFactory.invalid_const_ref_full(fun.name, param.toString(), param.sourceInfo);
|
|
|
- }
|
|
|
- } else if (!(param instanceof VariableLiteral || param instanceof ArrayAccess)) {
|
|
|
- throw ProcessorErrorFactory.invalid_parameter_type_full(fun.name, param.toString(), param.sourceInfo);
|
|
|
- }
|
|
|
- }
|
|
|
- const resultType = this.evaluateExpressionType(param);
|
|
|
- if(resultType instanceof MultiType && formalParam.type instanceof MultiType) {
|
|
|
- let shared = 0
|
|
|
- for (let j = 0; j < resultType.types.length; ++j) {
|
|
|
- const element = resultType.types[j];
|
|
|
- if(formalParam.type.types.indexOf(element) !== -1) {
|
|
|
- shared += 1;
|
|
|
- }
|
|
|
- }
|
|
|
- if(shared <= 0) {
|
|
|
- if(Config.enable_type_casting && !formalParam.byRef) {
|
|
|
- if(resultType.isCompatible(Types.INTEGER) || resultType.isCompatible(Types.REAL)) {
|
|
|
- if(formalParam.type.isCompatible(Types.INTEGER) || formalParam.type.isCompatible(Types.REAL)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- throw ProcessorErrorFactory.invalid_parameter_type_full(fun.name, param.toString(), param.sourceInfo);
|
|
|
- }
|
|
|
- } else if (resultType instanceof MultiType) {
|
|
|
- if(!resultType.isCompatible(formalParam.type)) {
|
|
|
- if(Config.enable_type_casting && !formalParam.byRef) {
|
|
|
- if(resultType.isCompatible(Types.INTEGER) || resultType.isCompatible(Types.REAL)) {
|
|
|
- if(formalParam.type.isCompatible(Types.INTEGER) || formalParam.type.isCompatible(Types.REAL)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- throw ProcessorErrorFactory.invalid_parameter_type_full(fun.name, param.toString(), param.sourceInfo);
|
|
|
- }
|
|
|
- } else if(!formalParam.type.isCompatible(resultType)) {
|
|
|
- if(Config.enable_type_casting && !formalParam.byRef) {
|
|
|
- if (Store.canImplicitTypeCast(formalParam.type, resultType)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- throw ProcessorErrorFactory.invalid_parameter_type_full(fun.name, param.toString(), param.sourceInfo);
|
|
|
+
|
|
|
+ for (let i = 0, j = 0; i < parameterList.length && j < actualParametersList.length; i += 1, j += 1) {
|
|
|
+ const formalParam = parameterList[i];
|
|
|
+ if (formalParam.variadic && i + 1 !== parameterList.length) {
|
|
|
+ throw "A function variadic parameter must be its last parameter!";
|
|
|
+ }
|
|
|
+ if (formalParam.variadic) {
|
|
|
+ j = this.assertVariadicParameter(fun, formalParam, j, actualParametersList);
|
|
|
+ } else {
|
|
|
+ const param = actualParametersList[j];
|
|
|
+ this.assertParameter(fun, formalParam, param);
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
}
|
|
|
|
|
|
evaluateVectorLiteralType (literal, type) {
|
|
|
|
|
|
- for(let i = 0; i < literal.value.length; i+=1) {
|
|
|
+ for (let i = 0; i < literal.value.length; i+=1) {
|
|
|
const exp = literal.value[i];
|
|
|
const expType = this.evaluateExpressionType(exp);
|
|
|
let compatible = false;
|
|
@@ -601,8 +570,8 @@ export class SemanticAnalyser {
|
|
|
} else {
|
|
|
compatible = type.canAccept(expType, 1);
|
|
|
}
|
|
|
- if(!compatible) {
|
|
|
- if(!Config.enable_type_casting || !Store.canImplicitTypeCast(type.innerType, expType)) {
|
|
|
+ if (!compatible) {
|
|
|
+ if (!Config.enable_type_casting || !Store.canImplicitTypeCast(type.innerType, expType)) {
|
|
|
const stringInfo = type.stringInfo();
|
|
|
const info = stringInfo[0];
|
|
|
const result_string_info = expType.stringInfo();
|
|
@@ -613,4 +582,76 @@ export class SemanticAnalyser {
|
|
|
}
|
|
|
return type;
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ *
|
|
|
+ * @param {import('./../../ast/commands/function').Function} fun
|
|
|
+ * @param {import('./../../ast/commands/formalParameter').FormalParameter} formalParam
|
|
|
+ * @param {number} index
|
|
|
+ * @param {Expression[]} actualParametersList
|
|
|
+ */
|
|
|
+ assertVariadicParameter (fun, formalParam, index, actualParametersList) {
|
|
|
+ let i;
|
|
|
+ for (i = index; i < actualParametersList.length; i += 1) {
|
|
|
+ this.assertParameter(fun, formalParam, actualParametersList[i]);
|
|
|
+ }
|
|
|
+ return i - 1;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ *
|
|
|
+ * @param {import('./../../ast/commands/function').Function} fun
|
|
|
+ * @param {import('./../../ast/commands/formalParameter').FormalParameter} formalParam
|
|
|
+ * @param {Expression} actualParameter
|
|
|
+ */
|
|
|
+ assertParameter (fun, formalParam, actualParameter) {
|
|
|
+
|
|
|
+ if (formalParam.byRef) {
|
|
|
+ if (actualParameter instanceof VariableLiteral) {
|
|
|
+ const variable = this.findSymbol(actualParameter.id, this.symbolMap);
|
|
|
+ if (variable.isConst) {
|
|
|
+ throw ProcessorErrorFactory.invalid_const_ref_full(fun.name, actualParameter.toString(), actualParameter.sourceInfo);
|
|
|
+ }
|
|
|
+ } else if (!(actualParameter instanceof VariableLiteral || actualParameter instanceof ArrayAccess)) {
|
|
|
+ throw ProcessorErrorFactory.invalid_parameter_type_full(fun.name, actualParameter.toString(), actualParameter.sourceInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const resultType = this.evaluateExpressionType(actualParameter);
|
|
|
+ if (resultType instanceof MultiType && formalParam.type instanceof MultiType) {
|
|
|
+ let shared = 0
|
|
|
+ for (let j = 0; j < resultType.types.length; ++j) {
|
|
|
+ const element = resultType.types[j];
|
|
|
+ if (formalParam.type.types.indexOf(element) !== -1) {
|
|
|
+ shared += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (shared <= 0) {
|
|
|
+ if (Config.enable_type_casting && !formalParam.byRef) {
|
|
|
+ if (!resultType.isCompatible(Types.INTEGER) && !resultType.isCompatible(Types.REAL)
|
|
|
+ || (formalParam.type.isCompatible(Types.INTEGER) || formalParam.type.isCompatible(Types.REAL))) {
|
|
|
+ throw ProcessorErrorFactory.invalid_parameter_type_full(fun.name, actualParameter.toString(),
|
|
|
+ actualParameter.sourceInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } else if (resultType instanceof MultiType) {
|
|
|
+ if(!resultType.isCompatible(formalParam.type)) {
|
|
|
+ if (Config.enable_type_casting && !formalParam.byRef) {
|
|
|
+ if (!resultType.isCompatible(Types.INTEGER) && !resultType.isCompatible(Types.REAL)
|
|
|
+ || (formalParam.type.isCompatible(Types.INTEGER) || formalParam.type.isCompatible(Types.REAL))) {
|
|
|
+ throw ProcessorErrorFactory.invalid_parameter_type_full(fun.name, actualParameter.toString(),
|
|
|
+ actualParameter.sourceInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (!formalParam.type.isCompatible(resultType)) {
|
|
|
+ if (Config.enable_type_casting && !formalParam.byRef) {
|
|
|
+ if (!Store.canImplicitTypeCast(formalParam.type, resultType)) {
|
|
|
+ throw ProcessorErrorFactory.invalid_parameter_type_full(fun.name, actualParameter.toString(), actualParameter.sourceInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|