UNPKG

js-slang

Version:

Javascript-based implementations of Source, written in Typescript

675 lines 23.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NameNotFoundInModuleError = exports.DuplicateTypeAliasError = exports.ConstNotAssignableTypeError = exports.InvalidArrayAccessTypeError = exports.InvalidIndexTypeError = exports.TypeParameterNameNotAllowedError = exports.TypeAliasNameNotAllowedError = exports.TypeNotGenericError = exports.InvalidNumberOfTypeArgumentsForGenericTypeError = exports.InvalidNumberOfArgumentsTypeError = exports.UndefinedVariableTypeError = exports.TypeNotAllowedError = exports.TypecastError = exports.TypeNotCallableError = exports.FunctionShouldHaveReturnValueError = exports.TypeNotFoundError = exports.TypeMismatchError = exports.InconsistentPredicateTestError = exports.CallingNonFunctionType = exports.ConsequentAlternateMismatchError = exports.UndefinedIdentifierError = exports.InvalidTestConditionError = exports.InvalidArgumentTypesError = exports.DifferentNumberArgumentsError = exports.CyclicReferenceError = exports.DifferentAssignmentError = exports.ReassignConstError = exports.ArrayAssignmentError = exports.InvalidArrayIndexType = void 0; const astring_1 = require("astring"); const constants_1 = require("../constants"); const types_1 = require("../types"); const formatters_1 = require("../utils/formatters"); const stringify_1 = require("../utils/stringify"); // tslint:disable:max-classes-per-file class InvalidArrayIndexType { constructor(node, receivedType) { this.node = node; this.receivedType = receivedType; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Expected array index as number, got ${(0, stringify_1.typeToString)(this.receivedType)} instead`; } elaborate() { return this.explain(); } } exports.InvalidArrayIndexType = InvalidArrayIndexType; class ArrayAssignmentError { constructor(node, arrayType, receivedType) { this.node = node; this.arrayType = arrayType; this.receivedType = receivedType; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return (0, formatters_1.stripIndent) `Expected array type: ${(0, stringify_1.typeToString)(this.arrayType)} but got: ${(0, stringify_1.typeToString)(this.receivedType)}`; } elaborate() { return this.explain(); } } exports.ArrayAssignmentError = ArrayAssignmentError; class ReassignConstError { constructor(node) { this.node = node; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { const [varName] = formatAssignment(this.node); return `Reassignment of constant ${varName}`; } elaborate() { return this.explain(); } } exports.ReassignConstError = ReassignConstError; class DifferentAssignmentError { constructor(node, expectedType, receivedType) { this.node = node; this.expectedType = expectedType; this.receivedType = receivedType; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { const [varName, assignmentStr] = formatAssignment(this.node); return (0, formatters_1.stripIndent) ` Expected assignment of ${varName}: ${assignmentStr} to get a value of type: ${(0, stringify_1.typeToString)(this.expectedType)} but got a value of type: ${(0, stringify_1.typeToString)(this.receivedType)} `; } elaborate() { return this.explain(); } } exports.DifferentAssignmentError = DifferentAssignmentError; function formatAssignment(node) { const leftNode = node.left; const assignmentStr = (0, formatters_1.simplify)((0, astring_1.generate)(node.right)); return [leftNode.name, assignmentStr]; } class CyclicReferenceError { constructor(node) { this.node = node; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `${stringifyNode(this.node)} contains cyclic reference to itself`; } elaborate() { return this.explain(); } } exports.CyclicReferenceError = CyclicReferenceError; function stringifyNode(node) { return ['VariableDeclaration', 'FunctionDeclaration'].includes(node.type) ? node.type === 'VariableDeclaration' ? node.declarations[0].id.name : node.id?.name : node.type === 'Identifier' ? node.name : JSON.stringify(node); // might not be a good idea } class DifferentNumberArgumentsError { constructor(node, numExpectedArgs, numReceived) { this.node = node; this.numExpectedArgs = numExpectedArgs; this.numReceived = numReceived; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Function expected ${this.numExpectedArgs} args, but got ${this.numReceived}`; } elaborate() { return this.explain(); } } exports.DifferentNumberArgumentsError = DifferentNumberArgumentsError; class InvalidArgumentTypesError { constructor(node, args, expectedTypes, receivedTypes) { this.node = node; this.args = args; this.expectedTypes = expectedTypes; this.receivedTypes = receivedTypes; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { const argStrings = this.args.map(arg => (0, formatters_1.simplify)((0, astring_1.generate)(arg))); if ('operator' in this.node) { const op = this.node.operator; if (this.expectedTypes.length === 2) { // binary operator return (0, formatters_1.stripIndent) ` A type mismatch was detected in the binary expression: ${argStrings[0]} ${op} ${argStrings[1]} The binary operator (${op}) expected two operands with types: ${(0, stringify_1.typeToString)(this.expectedTypes[0])} ${op} ${(0, stringify_1.typeToString)(this.expectedTypes[1])} but instead it received two operands of types: ${(0, stringify_1.typeToString)(this.receivedTypes[0])} ${op} ${(0, stringify_1.typeToString)(this.receivedTypes[1])} `; } else { // unary operator return (0, formatters_1.stripIndent) ` A type mismatch was detected in the unary expression: ${op} ${argStrings[0]} The unary operator (${op}) expected its operand to be of type: ${(0, stringify_1.typeToString)(this.expectedTypes[0])} but instead it received an operand of type: ${(0, stringify_1.typeToString)(this.receivedTypes[0])} `; } } const functionString = (0, formatters_1.simplify)((0, astring_1.generate)(this.node)); function formatPhrasing(types) { switch (types.length) { // there will at least be one argument case 1: return `an argument of type: ${(0, stringify_1.typeToString)(types[0])}`; default: return `${types.length} arguments of types: ${types.map(stringify_1.typeToString).join(', ')}`; } } return (0, formatters_1.stripIndent) ` A type mismatch was detected in the function call: ${functionString} The function expected ${formatPhrasing(this.expectedTypes)} but instead received ${formatPhrasing(this.receivedTypes)} `; } elaborate() { return this.explain(); } } exports.InvalidArgumentTypesError = InvalidArgumentTypesError; function formatNodeWithTest(node) { let exprString = (0, formatters_1.simplify)((0, astring_1.generate)(node.test)); let kind; switch (node.type) { case 'IfStatement': { exprString = `if (${exprString}) { ... } else { ... }`; kind = 'if statement'; break; } case 'ConditionalExpression': { exprString = `${exprString} ? ... : ...`; kind = 'conditional expression'; break; } case 'WhileStatement': { exprString = `while (${exprString}) { ... }`; kind = 'while statement'; break; } case 'ForStatement': { exprString = `for (...; ${exprString}; ...) { ... }`; kind = 'for statement'; } } return { exprString, kind }; } class InvalidTestConditionError { constructor(node, receivedType) { this.node = node; this.receivedType = receivedType; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { const { exprString, kind } = formatNodeWithTest(this.node); return (0, formatters_1.stripIndent) ` Expected the test part of the ${kind}: ${exprString} to have type boolean, but instead it is type: ${(0, stringify_1.typeToString)(this.receivedType)} `; } elaborate() { return this.explain(); } } exports.InvalidTestConditionError = InvalidTestConditionError; class UndefinedIdentifierError { constructor(node, name) { this.node = node; this.name = name; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return (0, formatters_1.stripIndent) ` One or more undeclared names detected (e.g. '${this.name}'). If there aren't actually any undeclared names, then is either a Source or misconfiguration bug. Please report this to the administrators! `; } elaborate() { return this.explain(); } } exports.UndefinedIdentifierError = UndefinedIdentifierError; class ConsequentAlternateMismatchError { constructor(node, consequentType, alternateType) { this.node = node; this.consequentType = consequentType; this.alternateType = alternateType; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { const { exprString, kind } = formatNodeWithTest(this.node); return (0, formatters_1.stripIndent) ` The two branches of the ${kind}: ${exprString} produce different types! The true branch has type: ${(0, stringify_1.typeToString)(this.consequentType)} but the false branch has type: ${(0, stringify_1.typeToString)(this.alternateType)} `; } elaborate() { return this.explain(); } } exports.ConsequentAlternateMismatchError = ConsequentAlternateMismatchError; class CallingNonFunctionType { constructor(node, callerType) { this.node = node; this.callerType = callerType; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return (0, formatters_1.stripIndent) ` In ${(0, formatters_1.simplify)((0, astring_1.generate)(this.node))} expected ${(0, formatters_1.simplify)((0, astring_1.generate)(this.node.callee))} to be a function type, but instead it is type: ${(0, stringify_1.typeToString)(this.callerType)} `; } elaborate() { return this.explain(); } } exports.CallingNonFunctionType = CallingNonFunctionType; class InconsistentPredicateTestError { constructor(node, argVarName, preUnifyType, predicateType) { this.node = node; this.argVarName = argVarName; this.preUnifyType = preUnifyType; this.predicateType = predicateType; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { const exprString = (0, astring_1.generate)(this.node); return (0, formatters_1.stripIndent) ` Inconsistent type constraints when trying to apply the predicate test ${exprString} It is inconsistent with the predicate tests applied before it. The variable ${this.argVarName} has type ${(0, stringify_1.typeToString)(this.preUnifyType)} but could not unify with type ${(0, stringify_1.typeToString)(this.predicateType)} `; } elaborate() { return this.explain(); } } exports.InconsistentPredicateTestError = InconsistentPredicateTestError; // Errors for Source Typed error checker class TypeMismatchError { constructor(node, actualTypeString, expectedTypeString) { this.node = node; this.actualTypeString = actualTypeString; this.expectedTypeString = expectedTypeString; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Type '${this.actualTypeString}' is not assignable to type '${this.expectedTypeString}'.`; } elaborate() { return this.explain(); } } exports.TypeMismatchError = TypeMismatchError; class TypeNotFoundError { constructor(node, name) { this.node = node; this.name = name; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Type '${this.name}' not declared.`; } elaborate() { return this.explain(); } } exports.TypeNotFoundError = TypeNotFoundError; class FunctionShouldHaveReturnValueError { constructor(node) { this.node = node; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return "A function whose declared type is neither 'void' nor 'any' must return a value."; } elaborate() { return this.explain(); } } exports.FunctionShouldHaveReturnValueError = FunctionShouldHaveReturnValueError; class TypeNotCallableError { constructor(node, typeName) { this.node = node; this.typeName = typeName; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Type '${this.typeName}' is not callable.`; } elaborate() { return this.explain(); } } exports.TypeNotCallableError = TypeNotCallableError; class TypecastError { constructor(node, originalType, typeToCastTo) { this.node = node; this.originalType = originalType; this.typeToCastTo = typeToCastTo; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Type '${this.originalType}' cannot be casted to type '${this.typeToCastTo}' as the two types do not intersect.`; } elaborate() { return this.explain(); } } exports.TypecastError = TypecastError; class TypeNotAllowedError { constructor(node, name) { this.node = node; this.name = name; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Type '${this.name}' is not allowed.`; } elaborate() { return this.explain(); } } exports.TypeNotAllowedError = TypeNotAllowedError; class UndefinedVariableTypeError { constructor(node, name) { this.node = node; this.name = name; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Name ${this.name} not declared.`; } elaborate() { return `Before you can read the value of ${this.name}, you need to declare it as a variable or a constant. You can do this using the let or const keywords.`; } } exports.UndefinedVariableTypeError = UndefinedVariableTypeError; class InvalidNumberOfArgumentsTypeError { constructor(node, expected, got, hasVarArgs = false) { this.node = node; this.expected = expected; this.got = got; this.hasVarArgs = hasVarArgs; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; this.calleeStr = (0, astring_1.generate)(node.callee); } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Expected ${this.expected} ${this.hasVarArgs ? 'or more ' : ''}arguments, but got ${this.got}.`; } elaborate() { const calleeStr = this.calleeStr; const pluralS = this.expected === 1 ? '' : 's'; return `Try calling function ${calleeStr} again, but with ${this.expected} argument${pluralS} instead. Remember that arguments are separated by a ',' (comma).`; } } exports.InvalidNumberOfArgumentsTypeError = InvalidNumberOfArgumentsTypeError; class InvalidNumberOfTypeArgumentsForGenericTypeError { constructor(node, name, expected) { this.node = node; this.name = name; this.expected = expected; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Generic type '${this.name}' requires ${this.expected} type argument(s).`; } elaborate() { return this.explain(); } } exports.InvalidNumberOfTypeArgumentsForGenericTypeError = InvalidNumberOfTypeArgumentsForGenericTypeError; class TypeNotGenericError { constructor(node, name) { this.node = node; this.name = name; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Type '${this.name}' is not generic.`; } elaborate() { return this.explain(); } } exports.TypeNotGenericError = TypeNotGenericError; class TypeAliasNameNotAllowedError { constructor(node, name) { this.node = node; this.name = name; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Type alias name cannot be '${this.name}'.`; } elaborate() { return this.explain(); } } exports.TypeAliasNameNotAllowedError = TypeAliasNameNotAllowedError; class TypeParameterNameNotAllowedError { constructor(node, name) { this.node = node; this.name = name; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Type parameter name cannot be '${this.name}'.`; } elaborate() { return this.explain(); } } exports.TypeParameterNameNotAllowedError = TypeParameterNameNotAllowedError; class InvalidIndexTypeError { constructor(node, typeName) { this.node = node; this.typeName = typeName; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Type '${this.typeName}' cannot be used as an index type.`; } elaborate() { return this.explain(); } } exports.InvalidIndexTypeError = InvalidIndexTypeError; class InvalidArrayAccessTypeError { constructor(node, typeName) { this.node = node; this.typeName = typeName; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Type '${this.typeName}' cannot be accessed as it is not an array.`; } elaborate() { return this.explain(); } } exports.InvalidArrayAccessTypeError = InvalidArrayAccessTypeError; class ConstNotAssignableTypeError { constructor(node, name) { this.node = node; this.name = name; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.WARNING; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Cannot assign to '${this.name}' as it is a constant.`; } elaborate() { return this.explain(); } } exports.ConstNotAssignableTypeError = ConstNotAssignableTypeError; class DuplicateTypeAliasError { constructor(node, name) { this.node = node; this.name = name; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Type alias '${this.name}' has already been declared.`; } elaborate() { return this.explain(); } } exports.DuplicateTypeAliasError = DuplicateTypeAliasError; class NameNotFoundInModuleError { constructor(node, moduleName, name) { this.node = node; this.moduleName = moduleName; this.name = name; this.type = types_1.ErrorType.TYPE; this.severity = types_1.ErrorSeverity.ERROR; } get location() { return this.node.loc ?? constants_1.UNKNOWN_LOCATION; } explain() { return `Module '${this.moduleName}' has no exported member '${this.name}'.`; } elaborate() { return this.explain(); } } exports.NameNotFoundInModuleError = NameNotFoundInModuleError; //# sourceMappingURL=typeErrors.js.map