Change implementation strategy of cashassembly, add scripts, comments support and tests

This commit is contained in:
Kuldeep
2026-09-11 10:02:20 +00:00
parent bd2f1044e7
commit c3dd0162d9
15 changed files with 2035 additions and 332 deletions
+132 -2
View File
@@ -1,16 +1,24 @@
/* 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 {
constructor(variableNames?: string[]) {
/**
* Variable names that were required but absent from the variables map.
*/
readonly variableNames: string[];
constructor(variableNames: string[] = []) {
const defaultMessage = 'Missing required variable';
if (variableNames !== undefined && variableNames.length > 0) {
if (variableNames.length > 0) {
super(`${defaultMessage}: variableNames [${variableNames.join(', ')}]`);
} else {
super(defaultMessage);
}
this.variableNames = variableNames;
}
}
@@ -24,6 +32,104 @@ export class CashAssemblyCompilationFailedError extends Error {
}
}
/**
* 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.
*/
@@ -74,6 +180,30 @@ export class CashAssemblyPrimitiveVariableMissingError extends Error {
}
}
/**
* 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.
*/