Change implementation strategy of cashassembly, add scripts, comments support and tests
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import { generateBytecodeMap, IdentifierResolutionType, OpcodesBchSpec } from '@bitauth/libauth';
|
||||
import { CashAssemblyIdentifierCollisionError } from './errors.ts';
|
||||
import type { CompileCashAssemblyContext } from './types.ts';
|
||||
|
||||
/**
|
||||
* Set of opcode names that the compiler recognizes.
|
||||
*/
|
||||
const COMPILER_OPCODE_NAMES: ReadonlySet<string> = new Set(Object.keys(generateBytecodeMap(OpcodesBchSpec)));
|
||||
|
||||
/**
|
||||
* Parameters for {@link assertNoIdentifierCollisions} function.
|
||||
*/
|
||||
export type AssertNoIdentifierCollisionsParameters = Pick<CompileCashAssemblyContext, 'variables' | 'templateScripts'>;
|
||||
|
||||
/**
|
||||
* Libauth resolves opcodes, then variables, then scripts, and the first match silently hides the
|
||||
* rest, leading to unexpected compilation results and no errors. This function throws when one identifier matches more than one resolution type.
|
||||
*
|
||||
* @param {AssertNoIdentifierCollisionsParameters} parameters - Provided variables and optional template scripts.
|
||||
* @throws {@link CashAssemblyIdentifierCollisionError} - When one identifier matches more than one resolution type.
|
||||
*/
|
||||
export const assertNoIdentifierCollisions = (parameters: AssertNoIdentifierCollisionsParameters): void => {
|
||||
const { variables, templateScripts } = parameters;
|
||||
|
||||
// Create a set of the script identifiers from the template scripts map.
|
||||
const scriptIdentifiers = new Set(Object.keys(templateScripts ?? {}));
|
||||
|
||||
const variableNames = new Set(Object.keys(variables));
|
||||
|
||||
// Combine both, the variableNames and the scriptIdentifiers, to get a set of all identifiers.
|
||||
const declaredIdentifiers = new Set([ ...variableNames, ...scriptIdentifiers ]);
|
||||
|
||||
// This loop will check for more than one occurrence of an identifier in OP_CODES, variables, and scripts
|
||||
for (const identifier of declaredIdentifiers) {
|
||||
// Resolution types is a native construct from libauth.
|
||||
const resolutionTypes: IdentifierResolutionType[] = [];
|
||||
|
||||
// If the identifier is an opcode, then push it to the resolution types array, this will also be
|
||||
// detected by either or both of the variableNames and scriptIdentifiers checks.
|
||||
if (COMPILER_OPCODE_NAMES.has(identifier) === true) {
|
||||
resolutionTypes.push(IdentifierResolutionType.opcode);
|
||||
}
|
||||
|
||||
// If the identifier is in variables, then push it to the resolution types array.
|
||||
if (variableNames.has(identifier) === true) {
|
||||
resolutionTypes.push(IdentifierResolutionType.variable);
|
||||
}
|
||||
|
||||
// If the identifier is a script identifier, then push it to the resolution types array.
|
||||
if (scriptIdentifiers.has(identifier) === true) {
|
||||
resolutionTypes.push(IdentifierResolutionType.script);
|
||||
}
|
||||
|
||||
// If there are more than one resolution types, then throw an error.
|
||||
if (resolutionTypes.length > 1) {
|
||||
throw new CashAssemblyIdentifierCollisionError(identifier, resolutionTypes);
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user