/* eslint-disable max-classes-per-file */ import type { IdentifierResolutionType } from '@bitauth/libauth'; /** * Error thrown when a required variable is missing. */ export class CashAssemblyRequiredVariableMissingError extends Error { /** * Variable names that were required but absent from the variables map. */ readonly variableNames: string[]; constructor(variableNames: string[] = []) { const defaultMessage = 'Missing required variable'; if (variableNames.length > 0) { super(`${defaultMessage}: variableNames [${variableNames.join(', ')}]`); } else { super(defaultMessage); } this.variableNames = variableNames; } } /** * Error thrown when cash assembly compilation fails. */ export class CashAssemblyCompilationFailedError extends Error { constructor(message?: string) { const defaultMessage = 'Cash assembly compilation failed'; super(message ? `${defaultMessage}: ${message}` : defaultMessage); } } /** * Error thrown when a quoted string inside `$()` never closes. */ export class CashAssemblyQuotedLiteralUnclosedError extends Error { /** * Index of the opening quote that never found a closer. */ readonly openingQuoteIndex: number; /** * Quote character that opened the literal. */ readonly quoteCharacter: string; /** * Text from the opening quote through the end of the scanned string. */ readonly unclosedText: string; constructor(openingQuoteIndex: number, quoteCharacter: string, cashAssemblyText: string) { const unclosedText = cashAssemblyText.slice(openingQuoteIndex); const defaultMessage = 'Quoted literal in a CashAssembly evaluation is unclosed'; const details = [ `quoteCharacter ${JSON.stringify(quoteCharacter)}`, `openingQuoteIndex ${String(openingQuoteIndex)}`, `unclosedText ${JSON.stringify(unclosedText)}`, ].join(', '); super(`${defaultMessage}: ${details}`); this.openingQuoteIndex = openingQuoteIndex; this.quoteCharacter = quoteCharacter; this.unclosedText = unclosedText; } } /** * Error thrown when a block comment inside `$()` never closes. */ export class CashAssemblyBlockCommentUnclosedError extends Error { /** * Index of the first slash of the block comment opener. */ readonly commentStartIndex: number; /** * Text from the block comment opener through the end of the scanned string. */ readonly unclosedText: string; constructor(commentStartIndex: number, cashAssemblyText: string) { const unclosedText = cashAssemblyText.slice(commentStartIndex); const defaultMessage = 'Block comment in a CashAssembly evaluation is unclosed'; const details = [ `commentStartIndex ${String(commentStartIndex)}`, `unclosedText ${JSON.stringify(unclosedText)}` ].join(', '); super(`${defaultMessage}: ${details}`); this.commentStartIndex = commentStartIndex; this.unclosedText = unclosedText; } } /** * Error thrown when a `$()` evaluation never finds its matching closer. */ export class CashAssemblyEvaluationUnclosedError extends Error { /** * Index of the `$` that opened the evaluation. */ readonly evaluationStartIndex: number; /** * How many `$()` remain open at the end of the string, including nested evaluations. */ readonly remainingOpenEvaluations: number; /** * Text from the opening `$` through the end of the scanned string. */ readonly unclosedText: string; constructor(evaluationStartIndex: number, remainingOpenEvaluations: number, cashAssemblyText: string) { const unclosedText = cashAssemblyText.slice(evaluationStartIndex); const defaultMessage = 'CashAssembly evaluation is unclosed'; const details = [ `evaluationStartIndex ${String(evaluationStartIndex)}`, `remainingOpenEvaluations ${String(remainingOpenEvaluations)}`, `unclosedText ${JSON.stringify(unclosedText)}`, ].join(', '); super(`${defaultMessage}: ${details}`); this.evaluationStartIndex = evaluationStartIndex; this.remainingOpenEvaluations = remainingOpenEvaluations; this.unclosedText = unclosedText; } } /** * Error thrown when a variable's runtime type does not match the type required for compilation. */ export class CashAssemblyVariableTypeMismatchError extends Error { constructor(variableKey: string, expectedType: string, actualType: string) { const defaultMessage = 'Variable type mismatch'; super(`${defaultMessage}: variableKey "${variableKey}", expected ${expectedType}, got ${actualType}`); } } /** * Error thrown when a method resolvable primitive type does not expose the requested method. */ export class CashAssemblyPrimitiveMethodMissingError extends Error { constructor(identifier: string, methodName: string, type: string) { const defaultMessage = 'CashAssembly primitive method does not exist'; super(`${defaultMessage}: identifier "${identifier}", methodName "${methodName}", type "${type}"`); } } /** * Error thrown when a value cannot be resolved as bytes. */ export class CashAssemblyUnsupportedValueTypeError extends Error { constructor(identifier: string, returnedType: string) { const defaultMessage = 'CashAssembly value type is unsupported for byte resolution'; super(`${defaultMessage}: identifier "${identifier}", returnedType "${returnedType}"`); } } /** * Error thrown when a number cannot be safely encoded as a CashAssembly VM number. */ export class CashAssemblyNumberNotSafeIntegerError extends Error { constructor(identifier: string, value: number) { const defaultMessage = 'CashAssembly number is not a safe integer'; super(`${defaultMessage}: identifier "${identifier}", got ${String(value)}`); } } /** * Error thrown when a method resolvable primitive is selected but its value is missing from the variables map. */ export class CashAssemblyPrimitiveVariableMissingError extends Error { constructor(identifier: string, variableName: string) { const defaultMessage = 'CashAssembly primitive variable is missing from the variables map'; super(`${defaultMessage}: identifier "${identifier}", variableName "${variableName}"`); } } /** * Error thrown when one identifier would resolve as more than one {@link IdentifierResolutionType}. */ export class CashAssemblyIdentifierCollisionError extends Error { /** * Identifier that more than one resolution type would match. */ readonly identifier: string; /** * The list of resolution types that the identifier matches. */ readonly resolutionTypes: IdentifierResolutionType[]; constructor(identifier: string, resolutionTypes: IdentifierResolutionType[]) { const defaultMessage = 'CashAssembly identifier exists for more than one resolution type'; super(`${defaultMessage}: identifier "${identifier}", resolutionTypes [${resolutionTypes.join(', ')}]`); this.identifier = identifier; this.resolutionTypes = resolutionTypes; } } /** * Error thrown when compiled evaluation bytes cannot be decoded as a VM number. */ export class CashAssemblyVmNumberDecodeError extends Error { constructor(reason: string) { const defaultMessage = 'CashAssembly evaluation could not be decoded as a VM number'; super(`${defaultMessage}: ${reason}`); } }