Files
xo-cash-utils/source/cash-assembly/errors.ts
T

216 lines
7.5 KiB
TypeScript

/* 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}`);
}
}