mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-19 00:31:06 +00:00
Merge commit '6e92d2345e8231a44556ce7d416451f5f3e6c398' as 'engine262'
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-static-semantics-bodytext */
|
||||
// RegularExpressionLiteral :: `/` RegularExpressionBody `/` RegularExpressionFlags
|
||||
export function BodyText(RegularExpressionLiteral: ParseNode.RegularExpressionLiteral) {
|
||||
return RegularExpressionLiteral.RegularExpressionBody;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import { OutOfRange, isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { JSStringValue, Value } from '../value.mts';
|
||||
import { StringValue } from './all.mts';
|
||||
|
||||
export function BoundNames(node: ParseNode | readonly ParseNode[]): JSStringValue[] {
|
||||
if (isArray(node)) {
|
||||
const names = [];
|
||||
for (const item of node) {
|
||||
names.push(...BoundNames(item));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'BindingIdentifier':
|
||||
return [StringValue(node)];
|
||||
case 'LexicalDeclaration':
|
||||
return BoundNames(node.BindingList);
|
||||
case 'LexicalBinding':
|
||||
if (node.BindingIdentifier) {
|
||||
return BoundNames(node.BindingIdentifier);
|
||||
}
|
||||
return BoundNames(node.BindingPattern!);
|
||||
case 'VariableStatement':
|
||||
return BoundNames(node.VariableDeclarationList);
|
||||
case 'VariableDeclaration':
|
||||
if (node.BindingIdentifier) {
|
||||
return BoundNames(node.BindingIdentifier);
|
||||
}
|
||||
return BoundNames(node.BindingPattern!);
|
||||
case 'ForDeclaration':
|
||||
return BoundNames(node.ForBinding);
|
||||
case 'ForBinding':
|
||||
if (node.BindingIdentifier) {
|
||||
return BoundNames(node.BindingIdentifier);
|
||||
}
|
||||
return BoundNames(node.BindingPattern!);
|
||||
case 'FunctionDeclaration':
|
||||
case 'GeneratorDeclaration':
|
||||
case 'AsyncFunctionDeclaration':
|
||||
case 'AsyncGeneratorDeclaration':
|
||||
case 'ClassDeclaration':
|
||||
if (node.BindingIdentifier) {
|
||||
return BoundNames(node.BindingIdentifier);
|
||||
}
|
||||
return [Value('*default*')];
|
||||
case 'ImportSpecifier':
|
||||
return BoundNames(node.ImportedBinding);
|
||||
case 'ExportDeclaration':
|
||||
if (node.FromClause || node.NamedExports) {
|
||||
return [];
|
||||
}
|
||||
if (node.VariableStatement) {
|
||||
return BoundNames(node.VariableStatement);
|
||||
}
|
||||
if (node.Declaration) {
|
||||
return BoundNames(node.Declaration);
|
||||
}
|
||||
if (node.HoistableDeclaration) {
|
||||
const declarationNames = BoundNames(node.HoistableDeclaration);
|
||||
return declarationNames;
|
||||
}
|
||||
if (node.ClassDeclaration) {
|
||||
const declarationNames = BoundNames(node.ClassDeclaration);
|
||||
return declarationNames;
|
||||
}
|
||||
if (node.AssignmentExpression) {
|
||||
return [Value('*default*')];
|
||||
}
|
||||
throw new OutOfRange('BoundNames', node);
|
||||
case 'SingleNameBinding':
|
||||
return BoundNames(node.BindingIdentifier);
|
||||
case 'BindingRestElement':
|
||||
if (node.BindingIdentifier) {
|
||||
return BoundNames(node.BindingIdentifier);
|
||||
}
|
||||
return BoundNames(node.BindingPattern!);
|
||||
case 'BindingRestProperty':
|
||||
return BoundNames(node.BindingIdentifier);
|
||||
case 'BindingElement':
|
||||
return BoundNames(node.BindingPattern);
|
||||
case 'BindingProperty':
|
||||
return BoundNames(node.BindingElement);
|
||||
case 'ObjectBindingPattern': {
|
||||
const names = BoundNames(node.BindingPropertyList);
|
||||
if (node.BindingRestProperty) {
|
||||
names.push(...BoundNames(node.BindingRestProperty));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
case 'ArrayBindingPattern': {
|
||||
const names = BoundNames(node.BindingElementList);
|
||||
if (node.BindingRestElement) {
|
||||
names.push(...BoundNames(node.BindingRestElement));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import { OutOfRange, unreachable } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { UTF16SurrogatePairToCodePoint } from './all.mts';
|
||||
import { Unicode, type CodePoint } from '#self';
|
||||
|
||||
export type CharacterValueAcceptNode =
|
||||
| ParseNode.RegExp.CharacterEscape
|
||||
| ParseNode.RegExp.RegExpUnicodeEscapeSequence
|
||||
| ParseNode.RegExp.ClassAtom
|
||||
| ParseNode.RegExp.ClassEscape
|
||||
| ParseNode.RegExp.ClassSetCharacter;
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-patterns-static-semantics-character-value */
|
||||
export function CharacterValue(node: CharacterValueAcceptNode): CodePoint {
|
||||
switch (node.type) {
|
||||
case 'CharacterEscape':
|
||||
switch (node.production) {
|
||||
case 'ControlEscape':
|
||||
switch (node.ControlEscape) {
|
||||
case 't':
|
||||
return 0x0009 as CodePoint;
|
||||
case 'n':
|
||||
return 0x000A as CodePoint;
|
||||
case 'v':
|
||||
return 0x000B as CodePoint;
|
||||
case 'f':
|
||||
return 0x000C as CodePoint;
|
||||
case 'r':
|
||||
return 0x000D as CodePoint;
|
||||
default:
|
||||
unreachable(node.ControlEscape);
|
||||
}
|
||||
case 'AsciiLetter': {
|
||||
// 1. Let ch be the code point matched by ControlLetter.
|
||||
const ch = node.AsciiLetter;
|
||||
// 2. Let i be ch's code point value.
|
||||
const i = ch.codePointAt(0)!;
|
||||
// 3. Return the remainder of dividing i by 32.
|
||||
return i % 32 as CodePoint;
|
||||
}
|
||||
case 'HexEscapeSequence':
|
||||
// 1. Return the numeric value of the code unit that is the SV of HexEscapeSequence.
|
||||
return Number.parseInt(`${node.HexEscapeSequence.HexDigit_a}${node.HexEscapeSequence.HexDigit_b}`, 16) as CodePoint;
|
||||
case 'RegExpUnicodeEscapeSequence':
|
||||
return CharacterValue(node.RegExpUnicodeEscapeSequence);
|
||||
case '0':
|
||||
// 1. Return the code point value of U+0000 (NULL).
|
||||
return 0x0000 as CodePoint;
|
||||
case 'IdentityEscape': {
|
||||
// 1. Let ch be the code point matched by IdentityEscape.
|
||||
const ch = node.IdentityEscape.codePointAt(0)!;
|
||||
// 2. Return the code point value of ch.
|
||||
return ch as CodePoint;
|
||||
}
|
||||
default:
|
||||
unreachable(node);
|
||||
}
|
||||
case 'RegExpUnicodeEscapeSequence':
|
||||
switch (true) {
|
||||
case 'Hex4Digits' in node:
|
||||
return node.Hex4Digits as CodePoint;
|
||||
case 'CodePoint' in node:
|
||||
return node.CodePoint as CodePoint;
|
||||
case 'HexTrailSurrogate' in node:
|
||||
return UTF16SurrogatePairToCodePoint(node.HexLeadSurrogate!, node.HexTrailSurrogate!);
|
||||
case 'HexLeadSurrogate' in node:
|
||||
return node.HexLeadSurrogate as CodePoint;
|
||||
default:
|
||||
throw new OutOfRange('CharacterValue', node);
|
||||
}
|
||||
case 'ClassAtom':
|
||||
switch (node.production) {
|
||||
case '-':
|
||||
// 1. Return the code point value of U+002D (HYPHEN-MINUS).
|
||||
return 0x002D as CodePoint;
|
||||
case 'SourceCharacter': {
|
||||
// 1. Let ch be the code point matched by SourceCharacter.
|
||||
const ch = node.SourceCharacter.codePointAt(0)!;
|
||||
// 2. Return ch.
|
||||
return ch as CodePoint;
|
||||
}
|
||||
case 'ClassEscape':
|
||||
return CharacterValue(node.ClassEscape);
|
||||
default:
|
||||
unreachable(node);
|
||||
}
|
||||
case 'ClassEscape':
|
||||
switch (node.production) {
|
||||
case 'b':
|
||||
// 1. Return the code point value of U+0008 (BACKSPACE).
|
||||
return 0x0008 as CodePoint;
|
||||
case '-':
|
||||
// 1. Return the code point value of U+002D (HYPHEN-MINUS).
|
||||
return 0x002D as CodePoint;
|
||||
case 'CharacterEscape':
|
||||
return CharacterValue(node.CharacterEscape);
|
||||
case 'CharacterClassEscape':
|
||||
throw new OutOfRange('CharacterValue', node);
|
||||
default:
|
||||
unreachable(node);
|
||||
}
|
||||
case 'ClassSetCharacter': {
|
||||
if (node.production === 'CharacterEscape') {
|
||||
return CharacterValue(node.CharacterEscape);
|
||||
} else {
|
||||
return Unicode.toCodePoint(node.UnicodeCharacter);
|
||||
}
|
||||
}
|
||||
default:
|
||||
unreachable(node);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { X } from '../completion.mts';
|
||||
import { UTF16SurrogatePairToCodePoint } from './all.mts';
|
||||
import { Assert } from '#self';
|
||||
import { isLeadingSurrogate, isTrailingSurrogate, type CodePoint } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-codepointat */
|
||||
export function CodePointAt(string: string, position: number) {
|
||||
// 1 .Let size be the length of string.
|
||||
const size = string.length;
|
||||
// 2. Assert: position ≥ 0 and position < size.
|
||||
Assert(position >= 0 && position < size);
|
||||
// 3. Let first be the code unit at index position within string.
|
||||
const first = string.charCodeAt(position);
|
||||
// 4. Let cp be the code point whose numeric value is that of first.
|
||||
let cp = first;
|
||||
// 5. If first is not a leading surrogate or trailing surrogate, then
|
||||
if (!isLeadingSurrogate(first) && !isTrailingSurrogate(first)) {
|
||||
// a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: false }.
|
||||
return {
|
||||
CodePoint: cp as CodePoint,
|
||||
CodeUnitCount: 1,
|
||||
IsUnpairedSurrogate: false,
|
||||
};
|
||||
}
|
||||
// 6. If first is a trailing surrogate or position + 1 = size, then
|
||||
if (isTrailingSurrogate(first) || position + 1 === size) {
|
||||
// a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }.
|
||||
return {
|
||||
CodePoint: cp as CodePoint,
|
||||
CodeUnitCount: 1,
|
||||
IsUnpairedSurrogate: true,
|
||||
};
|
||||
}
|
||||
// 7. Let second be the code unit at index position + 1 within string.
|
||||
const second = string.charCodeAt(position + 1);
|
||||
// 8. If seconds is not a trailing surrogate, then
|
||||
if (!isTrailingSurrogate(second)) {
|
||||
// a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }.
|
||||
return {
|
||||
CodePoint: cp as CodePoint,
|
||||
CodeUnitCount: 1,
|
||||
IsUnpairedSurrogate: true,
|
||||
};
|
||||
}
|
||||
// 9. Set cp to ! UTF16SurrogatePairToCodePoint(first, second).
|
||||
cp = X(UTF16SurrogatePairToCodePoint(first, second));
|
||||
// 10. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 2, [[IsUnpairedSurrogate]]: false }.
|
||||
return {
|
||||
CodePoint: cp as CodePoint,
|
||||
CodeUnitCount: 2,
|
||||
IsUnpairedSurrogate: false,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { UTF16EncodeCodePoint } from './all.mts';
|
||||
import type { CodePoint } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-codepointstostring */
|
||||
export function CodePointsToString(text: string) {
|
||||
// 1. Let result be the empty String.
|
||||
let result = '';
|
||||
// 2. For each code point cp in text, do
|
||||
for (const cp of text) {
|
||||
// a. Set result to the string-concatenation of result and UTF16EncodeCodePoint(cp).
|
||||
result += UTF16EncodeCodePoint(cp.codePointAt(0)! as CodePoint);
|
||||
}
|
||||
// 3. Return result.
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { PropName } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-static-semantics-constructormethod */
|
||||
// ClassElementList :
|
||||
// ClassElement
|
||||
// ClassElementList ClassElement
|
||||
export function ConstructorMethod(ClassElementList: ParseNode.ClassElementList): ParseNode.MethodDefinition | undefined {
|
||||
return ClassElementList.find((ClassElement) => ClassElement.static === false && PropName(ClassElement) === 'constructor') as ParseNode.MethodDefinition;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-static-semantics-containsarguments */
|
||||
export function ContainsArguments(node: ParseNode): ParseNode.IdentifierReference | null {
|
||||
switch (node.type) {
|
||||
case 'IdentifierReference':
|
||||
if (node.name === 'arguments') {
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
case 'FunctionDeclaration':
|
||||
case 'FunctionExpression':
|
||||
case 'MethodDefinition':
|
||||
case 'GeneratorMethod':
|
||||
case 'GeneratorDeclaration':
|
||||
case 'GeneratorExpression':
|
||||
case 'AsyncMethod':
|
||||
case 'AsyncFunctionDeclaration':
|
||||
case 'AsyncFunctionExpression':
|
||||
return null;
|
||||
default:
|
||||
for (const value of Object.values(node)) {
|
||||
// TODO(ts): This function does not accept a ParseNode[], when isArray(value), ContainsArguments should never return a result?
|
||||
if ((value?.type || Array.isArray(value))) {
|
||||
const maybe = ContainsArguments(value);
|
||||
if (maybe) {
|
||||
return maybe;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { OutOfRange, isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export function ContainsExpression(node: ParseNode | readonly ParseNode[]): boolean {
|
||||
if (isArray(node)) {
|
||||
for (const n of node) {
|
||||
if (ContainsExpression(n)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'SingleNameBinding':
|
||||
return !!node.Initializer;
|
||||
case 'BindingElement':
|
||||
if (ContainsExpression(node.BindingPattern)) {
|
||||
return true;
|
||||
}
|
||||
return !!node.Initializer;
|
||||
case 'ObjectBindingPattern':
|
||||
if (ContainsExpression(node.BindingPropertyList)) {
|
||||
return true;
|
||||
}
|
||||
if (node.BindingRestProperty) {
|
||||
return ContainsExpression(node.BindingRestProperty);
|
||||
}
|
||||
return false;
|
||||
case 'BindingProperty':
|
||||
if (node.PropertyName && 'ComputedPropertyName' in node.PropertyName && node.PropertyName.ComputedPropertyName) {
|
||||
return true;
|
||||
}
|
||||
return ContainsExpression(node.BindingElement);
|
||||
case 'BindingRestProperty':
|
||||
if (node.BindingIdentifier) {
|
||||
return false;
|
||||
}
|
||||
// TODO(ts): BindingRestProperty and BindingElement is different. Is there missing a case?
|
||||
// @ts-expect-error
|
||||
return ContainsExpression((node as ParseNode.BindingElement).BindingPattern);
|
||||
case 'ArrayBindingPattern':
|
||||
if (ContainsExpression(node.BindingElementList)) {
|
||||
return true;
|
||||
}
|
||||
if (node.BindingRestElement) {
|
||||
return ContainsExpression(node.BindingRestElement);
|
||||
}
|
||||
return false;
|
||||
case 'BindingRestElement':
|
||||
if (node.BindingIdentifier) {
|
||||
return false;
|
||||
}
|
||||
return ContainsExpression(node.BindingPattern!);
|
||||
case 'Elision':
|
||||
return false;
|
||||
default:
|
||||
throw new OutOfRange('ContainsExpression', node);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export function DeclarationPart<T extends ParseNode>(node: T): T {
|
||||
return node;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { HasInitializer } from './all.mts';
|
||||
|
||||
export function ExpectedArgumentCount(FormalParameterList: ParseNode.FormalParameters) {
|
||||
if (FormalParameterList.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
for (const FormalParameter of FormalParameterList.slice(0, -1)) {
|
||||
const BindingElement = FormalParameter;
|
||||
if (HasInitializer(BindingElement)) {
|
||||
return count;
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
|
||||
const last = FormalParameterList[FormalParameterList.length - 1];
|
||||
if (last.type === 'BindingRestElement') {
|
||||
return count;
|
||||
}
|
||||
if (HasInitializer(last)) {
|
||||
return count;
|
||||
}
|
||||
return count + 1;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
import { JSStringValue, NullValue, Value } from '../value.mts';
|
||||
import { OutOfRange, isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
BoundNames, ModuleRequests, ExportEntriesForModule, type ModuleRequestRecord,
|
||||
} from './all.mts';
|
||||
|
||||
export function ExportEntries(node: ParseNode | readonly ParseNode[]): ExportEntry[] {
|
||||
if (isArray(node)) {
|
||||
const entries: ExportEntry[] = [];
|
||||
node.forEach((n) => {
|
||||
entries.push(...ExportEntries(n));
|
||||
});
|
||||
return entries;
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'Module':
|
||||
if (!node.ModuleBody) {
|
||||
return [];
|
||||
}
|
||||
return ExportEntries(node.ModuleBody);
|
||||
case 'ModuleBody':
|
||||
return ExportEntries(node.ModuleItemList);
|
||||
case 'ExportDeclaration':
|
||||
switch (true) {
|
||||
case !!node.ExportFromClause && !!node.FromClause: {
|
||||
// `export` ExportFromClause FromClause WithClause? `;`
|
||||
// 1. Let module be the sole element of ModuleRequests of FromClause.
|
||||
const module = ModuleRequests(node)[0];
|
||||
// 2. Return ExportEntriesForModule(ExportFromClause, module).
|
||||
return ExportEntriesForModule(node.ExportFromClause, module);
|
||||
}
|
||||
case !!node.NamedExports: {
|
||||
// `export` NamedExports `;`
|
||||
// 1. Return ExportEntriesForModule(NamedExports, null).
|
||||
return ExportEntriesForModule(node.NamedExports, Value.null);
|
||||
}
|
||||
case !!node.VariableStatement: {
|
||||
// `export` VariableStatement
|
||||
// 1. Let entries be a new empty List.
|
||||
const entries = [];
|
||||
// 2. Let names be the BoundNames of VariableStatement.
|
||||
const names = BoundNames(node.VariableStatement);
|
||||
// 3. For each name in names, do
|
||||
for (const name of names) {
|
||||
// a. Append the ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: name, [[ExportName]]: name } to entries.
|
||||
entries.push({
|
||||
ModuleRequest: Value.null,
|
||||
ImportName: Value.null,
|
||||
LocalName: name,
|
||||
ExportName: name,
|
||||
});
|
||||
}
|
||||
// 4. Return entries.
|
||||
return entries;
|
||||
}
|
||||
case !!node.Declaration: {
|
||||
// `export` Declaration
|
||||
// 1. Let entries be a new empty List.
|
||||
const entries: ExportEntry[] = [];
|
||||
// 2. Let names be the BoundNames of Declaration.
|
||||
const names = BoundNames(node.Declaration);
|
||||
// 3. For each name in names, do
|
||||
for (const name of names) {
|
||||
// a. Append the ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: name, [[ExportName]]: name } to entries.
|
||||
entries.push({
|
||||
ModuleRequest: Value.null,
|
||||
ImportName: Value.null,
|
||||
LocalName: name,
|
||||
ExportName: name,
|
||||
});
|
||||
}
|
||||
// 4. Return entries.
|
||||
return entries;
|
||||
}
|
||||
case node.default && !!node.HoistableDeclaration: {
|
||||
// `export` `default` HoistableDeclaration
|
||||
// 1. Let names be BoundNames of HoistableDeclaration.
|
||||
const names = BoundNames(node.HoistableDeclaration);
|
||||
// 2. Let localName be the sole element of names.
|
||||
const localName = names[0];
|
||||
// 3. Return a new List containing the ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default" }.
|
||||
return [{
|
||||
ModuleRequest: Value.null,
|
||||
ImportName: Value.null,
|
||||
LocalName: localName,
|
||||
ExportName: Value('default'),
|
||||
}];
|
||||
}
|
||||
case node.default && !!node.ClassDeclaration: {
|
||||
// `export` `default` ClassDeclaration
|
||||
// 1. Let names be BoundNames of ClassDeclaration.
|
||||
const names = BoundNames(node.ClassDeclaration);
|
||||
// 2. Let localName be the sole element of names.
|
||||
const localName = names[0];
|
||||
// 3. Return a new List containing the ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default" }.
|
||||
return [{
|
||||
ModuleRequest: Value.null,
|
||||
ImportName: Value.null,
|
||||
LocalName: localName,
|
||||
ExportName: Value('default'),
|
||||
}];
|
||||
}
|
||||
case node.default && !!node.AssignmentExpression: {
|
||||
// `export` `default` AssignmentExpression `;`
|
||||
// 1. Let entry be the ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: "*default*", [[ExportName]]: "default" }.
|
||||
const entry = {
|
||||
ModuleRequest: Value.null,
|
||||
ImportName: Value.null,
|
||||
LocalName: Value('*default*'),
|
||||
ExportName: Value('default'),
|
||||
};
|
||||
// 2. Return a new List containing entry.
|
||||
return [entry];
|
||||
}
|
||||
default:
|
||||
throw new OutOfRange('ExportEntries', node);
|
||||
}
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export interface ExportEntry {
|
||||
readonly ModuleRequest: ModuleRequestRecord | NullValue;
|
||||
readonly ImportName: JSStringValue | NullValue | 'all' | 'all-but-default';
|
||||
readonly LocalName: JSStringValue | NullValue;
|
||||
readonly ExportName: JSStringValue | NullValue;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { NullValue, Value } from '../value.mts';
|
||||
import { OutOfRange, isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { StringValue, type ExportEntry, type ModuleRequestRecord } from './all.mts';
|
||||
|
||||
export function ExportEntriesForModule(node: ParseNode | readonly ParseNode[], module: ModuleRequestRecord | NullValue): ExportEntry[] {
|
||||
if (isArray(node)) {
|
||||
const specs: ExportEntry[] = [];
|
||||
node.forEach((n) => {
|
||||
specs.push(...ExportEntriesForModule(n, module));
|
||||
});
|
||||
return specs;
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'ExportFromClause':
|
||||
if (node.ModuleExportName) {
|
||||
// 1. Let exportName be the StringValue of ModuleExportName.
|
||||
const exportName = StringValue(node.ModuleExportName);
|
||||
// 2. Let entry be the ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: ~all~, [[LocalName]]: null, [[ExportName]]: exportName }.
|
||||
const entry: ExportEntry = {
|
||||
ModuleRequest: module,
|
||||
ImportName: 'all',
|
||||
LocalName: Value.null,
|
||||
ExportName: exportName,
|
||||
};
|
||||
// 3. Return a new List containing entry.
|
||||
return [entry];
|
||||
} else {
|
||||
// 1. Let entry be the ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: ~all-but-default~, [[LocalName]]: null, [[ExportName]]: null }.
|
||||
const entry: ExportEntry = {
|
||||
ModuleRequest: module,
|
||||
ImportName: 'all-but-default',
|
||||
LocalName: Value.null,
|
||||
ExportName: Value.null,
|
||||
};
|
||||
// 2. Return a new List containing entry.
|
||||
return [entry];
|
||||
}
|
||||
case 'ExportSpecifier': {
|
||||
const sourceName = StringValue(node.localName);
|
||||
const exportName = StringValue(node.exportName);
|
||||
let localName;
|
||||
let importName;
|
||||
if (module === Value.null) {
|
||||
localName = sourceName;
|
||||
importName = Value.null;
|
||||
} else { // 4. Else,
|
||||
localName = Value.null;
|
||||
importName = sourceName;
|
||||
}
|
||||
return [{
|
||||
ModuleRequest: module,
|
||||
ImportName: importName,
|
||||
LocalName: localName,
|
||||
ExportName: exportName,
|
||||
}];
|
||||
}
|
||||
case 'NamedExports':
|
||||
return ExportEntriesForModule(node.ExportsList, module);
|
||||
default:
|
||||
throw new OutOfRange('ExportEntriesForModule', node);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-static-semantics-flagtext */
|
||||
// RegularExpressionLiteral :: `/` RegularExpressionBody `/` RegularExpressionFlags
|
||||
export function FlagText(RegularExpressionLiteral: ParseNode.RegularExpressionLiteral) {
|
||||
return RegularExpressionLiteral.RegularExpressionFlags;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export function HasInitializer(node: ParseNode): node is ParseNode & { readonly Initializer: ParseNode.Initializer; } {
|
||||
return 'Initializer' in node && !!node.Initializer;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export function HasName(node: ParseNode): boolean {
|
||||
if (node.type === 'ParenthesizedExpression') {
|
||||
return HasName(node.Expression);
|
||||
}
|
||||
return 'BindingIdentifier' in node && !!node.BindingIdentifier;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { JSStringValue } from '../value.mts';
|
||||
import { ImportEntriesForModule, ModuleRequests, type ModuleRequestRecord } from './all.mts';
|
||||
|
||||
export function ImportEntries(node: ParseNode): ImportEntry[] {
|
||||
switch (node.type) {
|
||||
case 'Module':
|
||||
if (node.ModuleBody) {
|
||||
return ImportEntries(node.ModuleBody);
|
||||
}
|
||||
return [];
|
||||
case 'ModuleBody': {
|
||||
const entries: ImportEntry[] = [];
|
||||
for (const item of node.ModuleItemList) {
|
||||
entries.push(...ImportEntries(item));
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
case 'ImportDeclaration':
|
||||
if (node.FromClause) {
|
||||
// 1. Let module be the sole element of ModuleRequests of FromClause.
|
||||
const module = ModuleRequests(node)[0];
|
||||
// 2. Return ImportEntriesForModule of ImportClause with argument module.
|
||||
return ImportEntriesForModule(node.ImportClause!, module);
|
||||
}
|
||||
return [];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export interface ImportEntry {
|
||||
readonly ModuleRequest: ModuleRequestRecord;
|
||||
readonly ImportName: JSStringValue | 'namespace-object';
|
||||
readonly LocalName: JSStringValue;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import {
|
||||
BoundNames, StringValue, type ImportEntry, type ModuleRequestRecord,
|
||||
} from './all.mts';
|
||||
|
||||
export function ImportEntriesForModule(node: ParseNode, module: ModuleRequestRecord): ImportEntry[] {
|
||||
switch (node.type) {
|
||||
case 'ImportClause':
|
||||
switch (true) {
|
||||
case !!node.ImportedDefaultBinding && !!node.NameSpaceImport: {
|
||||
// 1. Let entries be ImportEntriesForModule of ImportedDefaultBinding with argument module.
|
||||
const entries = ImportEntriesForModule(node.ImportedDefaultBinding, module);
|
||||
// 2. Append to entries the elements of the ImportEntriesForModule of NameSpaceImport with argument module.
|
||||
entries.push(...ImportEntriesForModule(node.NameSpaceImport, module));
|
||||
// 3. Return entries.
|
||||
return entries;
|
||||
}
|
||||
case !!node.ImportedDefaultBinding && !!node.NamedImports: {
|
||||
// 1. Let entries be ImportEntriesForModule of ImportedDefaultBinding with argument module.
|
||||
const entries = ImportEntriesForModule(node.ImportedDefaultBinding, module);
|
||||
// 2. Append to entries the elements of the ImportEntriesForModule of NamedImports with argument module.
|
||||
entries.push(...ImportEntriesForModule(node.NamedImports, module));
|
||||
// 3. Return entries.
|
||||
return entries;
|
||||
}
|
||||
case !!node.ImportedDefaultBinding:
|
||||
return ImportEntriesForModule(node.ImportedDefaultBinding, module);
|
||||
case !!node.NameSpaceImport:
|
||||
return ImportEntriesForModule(node.NameSpaceImport, module);
|
||||
case !!node.NamedImports:
|
||||
return ImportEntriesForModule(node.NamedImports, module);
|
||||
default:
|
||||
throw new OutOfRange('ImportEntriesForModule', node);
|
||||
}
|
||||
case 'ImportedDefaultBinding': {
|
||||
// 1. Let localName be the sole element of BoundNames of ImportedBinding.
|
||||
const localName = BoundNames(node.ImportedBinding)[0];
|
||||
// 2. Let defaultEntry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: "default", [[LocalName]]: localName }.
|
||||
const defaultEntry: ImportEntry = {
|
||||
ModuleRequest: module,
|
||||
ImportName: Value('default'),
|
||||
LocalName: localName,
|
||||
};
|
||||
// 3. Return a new List containing defaultEntry.
|
||||
return [defaultEntry];
|
||||
}
|
||||
case 'NameSpaceImport': {
|
||||
// 1. Let localName be the StringValue of ImportedBinding.
|
||||
const localName = StringValue(node.ImportedBinding);
|
||||
// 2. Let entry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: ~namespace-object~, [[LocalName]]: localName }.
|
||||
const entry: ImportEntry = {
|
||||
ModuleRequest: module,
|
||||
ImportName: 'namespace-object',
|
||||
LocalName: localName,
|
||||
};
|
||||
// 3. Return a new List containing entry.
|
||||
return [entry];
|
||||
}
|
||||
case 'NamedImports': {
|
||||
const specs: ImportEntry[] = [];
|
||||
node.ImportsList.forEach((n) => {
|
||||
specs.push(...ImportEntriesForModule(n, module));
|
||||
});
|
||||
return specs;
|
||||
}
|
||||
case 'ImportSpecifier':
|
||||
if (node.ModuleExportName) {
|
||||
// 1. Let importName be the StringValue of ModuleExportName.
|
||||
const importName = StringValue(node.ModuleExportName);
|
||||
// 2. Let localName be the StringValue of ImportedBinding.
|
||||
const localName = StringValue(node.ImportedBinding);
|
||||
// 3. Let entry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: importName, [[LocalName]]: localName }.
|
||||
const entry: ImportEntry = {
|
||||
ModuleRequest: module,
|
||||
ImportName: importName,
|
||||
LocalName: localName,
|
||||
};
|
||||
// 4. Return a new List containing entry.
|
||||
return [entry];
|
||||
} else {
|
||||
// 1. Let localName be the sole element of BoundNames of ImportedBinding.
|
||||
const localName = BoundNames(node.ImportedBinding)[0];
|
||||
// 2. Let entry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: localName, [[LocalName]]: localName }.
|
||||
const entry: ImportEntry = {
|
||||
ModuleRequest: module,
|
||||
ImportName: localName,
|
||||
LocalName: localName,
|
||||
};
|
||||
// 3. Return a new List containing entry.
|
||||
return [entry];
|
||||
}
|
||||
default:
|
||||
throw new OutOfRange('ImportEntriesForModule', node);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { ImportEntry } from './ImportEntries.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-importedlocalnames */
|
||||
export function ImportedLocalNames(importEntries: readonly ImportEntry[]) {
|
||||
// 1. Let localNames be a new empty List.
|
||||
const localNames = [];
|
||||
// 2. For each ImportEntry Record i in importEntries, do
|
||||
for (const i of importEntries) {
|
||||
// a. Append i.[[LocalName]] to localNames.
|
||||
localNames.push(i.LocalName);
|
||||
}
|
||||
// 3. Return localNames.
|
||||
return localNames;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { IsFunctionDefinition, HasName } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-isanonymousfunctiondefinition */
|
||||
export function IsAnonymousFunctionDefinition(expr: ParseNode) {
|
||||
// 1. If IsFunctionDefinition of expr is false, return false.
|
||||
if (!IsFunctionDefinition(expr)) {
|
||||
return false;
|
||||
}
|
||||
// 1. Let hasName be HasName of expr.
|
||||
const hasName = HasName(expr);
|
||||
// 1. If hasName is true, return false.
|
||||
if (hasName) {
|
||||
return false;
|
||||
}
|
||||
// 1. Return true.
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export function IsComputedPropertyKey(node: ParseNode.PropertyNameLike): node is ParseNode.PropertyName {
|
||||
return node.type !== 'IdentifierName'
|
||||
&& node.type !== 'StringLiteral'
|
||||
&& node.type !== 'NumericLiteral';
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export function IsConstantDeclaration(node: ParseNode | ParseNode.LetOrConst) {
|
||||
return node === 'const' || (typeof node === 'object' && 'LetOrConst' in node && node.LetOrConst === 'const');
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export type DestructuringParseNode = ParseNode.ObjectBindingPattern | ParseNode.ArrayBindingPattern | ParseNode.ObjectLiteral | ParseNode.ArrayLiteral | ParseNode.ForDeclaration | ParseNode.ForBinding;
|
||||
export function IsDestructuring(node: ParseNode): boolean {
|
||||
switch (node.type) {
|
||||
case 'ObjectBindingPattern':
|
||||
case 'ArrayBindingPattern':
|
||||
case 'ObjectLiteral':
|
||||
case 'ArrayLiteral':
|
||||
return true;
|
||||
case 'ForDeclaration':
|
||||
return IsDestructuring(node.ForBinding);
|
||||
case 'ForBinding':
|
||||
if (node.BindingIdentifier) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export type FunctionDeclaration = ParseNode.FunctionExpression | ParseNode.GeneratorExpression | ParseNode.AsyncFunctionExpression | ParseNode.AsyncGeneratorExpression | ParseNode.ClassExpression | ParseNode.ArrowFunction | ParseNode.AsyncArrowFunction | ParseNode.ParenthesizedExpression & { readonly Expression: FunctionDeclaration };
|
||||
export function IsFunctionDefinition(node: ParseNode): node is FunctionDeclaration {
|
||||
if (node.type === 'ParenthesizedExpression') {
|
||||
return IsFunctionDefinition(node.Expression);
|
||||
}
|
||||
return node.type === 'FunctionExpression'
|
||||
|| node.type === 'GeneratorExpression'
|
||||
|| node.type === 'AsyncGeneratorExpression'
|
||||
|| node.type === 'AsyncFunctionExpression'
|
||||
|| node.type === 'ClassExpression'
|
||||
|| node.type === 'ArrowFunction'
|
||||
|| node.type === 'AsyncArrowFunction';
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export function IsIdentifierRef(node: ParseNode): node is ParseNode.IdentifierReference {
|
||||
return node.type === 'IdentifierReference';
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export function IsInTailPosition(_node: ParseNode): boolean {
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { OutOfRange, isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export function IsSimpleParameterList(node: ParseNode | readonly ParseNode[]) {
|
||||
if (isArray(node)) {
|
||||
for (const n of node) {
|
||||
if (!IsSimpleParameterList(n)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'SingleNameBinding':
|
||||
return node.Initializer === null;
|
||||
case 'BindingElement':
|
||||
return false;
|
||||
case 'BindingRestElement':
|
||||
return false;
|
||||
default:
|
||||
throw new OutOfRange('IsSimpleParameterList', node);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-static-semantics-isstatic */
|
||||
// ClassElement :
|
||||
// MethodDefinition
|
||||
// `static` MethodDefinition
|
||||
// `;`
|
||||
export function IsStatic(ClassElement: ParseNode.ClassElement) {
|
||||
return ClassElement.static;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-static-semantics-isstrict */
|
||||
export function IsStrict({ ScriptBody }: ParseNode.Script) {
|
||||
// 1. If ScriptBody is present and the Directive Prologue of ScriptBody contains a Use Strict Directive, return true; otherwise, return false.
|
||||
return ScriptBody!.strict;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { X } from '../completion.mts';
|
||||
import type { JSStringValue } from '../value.mts';
|
||||
import { CodePointAt } from './all.mts';
|
||||
|
||||
export function IsStringWellFormedUnicode(string_: JSStringValue) {
|
||||
const string = string_.stringValue();
|
||||
// 1. Let _strLen_ be the number of code units in string.
|
||||
const strLen = string.length;
|
||||
// 2. Let k be 0.
|
||||
let k = 0;
|
||||
// 3. Repeat, while k ≠ strLen,
|
||||
while (k !== strLen) {
|
||||
// a. Let cp be ! CodePointAt(string, k).
|
||||
const cp = X(CodePointAt(string, k));
|
||||
// b. If cp.[[IsUnpairedSurrogate]] is true, return false.
|
||||
if (cp.IsUnpairedSurrogate) {
|
||||
return false;
|
||||
}
|
||||
// c. Set k to k + cp.[[CodeUnitCount]].
|
||||
k += cp.CodeUnitCount;
|
||||
}
|
||||
// 4. Return true.
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { JSStringValue } from '../value.mts';
|
||||
import {
|
||||
TopLevelLexicallyDeclaredNames,
|
||||
} from './all.mts';
|
||||
|
||||
export function LexicallyDeclaredNames(node: ParseNode): JSStringValue[] {
|
||||
switch (node.type) {
|
||||
case 'Script':
|
||||
if (node.ScriptBody) {
|
||||
return LexicallyDeclaredNames(node.ScriptBody);
|
||||
}
|
||||
return [];
|
||||
case 'ScriptBody':
|
||||
return TopLevelLexicallyDeclaredNames(node.StatementList);
|
||||
case 'FunctionBody':
|
||||
case 'GeneratorBody':
|
||||
case 'AsyncBody':
|
||||
case 'AsyncGeneratorBody':
|
||||
return TopLevelLexicallyDeclaredNames(node.FunctionStatementList);
|
||||
case 'ClassStaticBlockBody':
|
||||
return TopLevelLexicallyDeclaredNames(node.ClassStaticBlockStatementList);
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import { isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { TopLevelLexicallyScopedDeclarations, DeclarationPart } from './all.mts';
|
||||
|
||||
export function LexicallyScopedDeclarations(node: ParseNode | readonly ParseNode[]): (ParseNode.Declaration | ParseNode.ExportDeclaration)[] {
|
||||
if (isArray(node)) {
|
||||
const declarations = [];
|
||||
for (const item of node) {
|
||||
declarations.push(...LexicallyScopedDeclarations(item));
|
||||
}
|
||||
return declarations;
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'LabelledStatement':
|
||||
return LexicallyScopedDeclarations(node.LabelledItem);
|
||||
case 'Script':
|
||||
if (node.ScriptBody) {
|
||||
return LexicallyScopedDeclarations(node.ScriptBody);
|
||||
}
|
||||
return [];
|
||||
case 'ScriptBody':
|
||||
return TopLevelLexicallyScopedDeclarations(node.StatementList);
|
||||
case 'Module':
|
||||
if (node.ModuleBody) {
|
||||
return LexicallyScopedDeclarations(node.ModuleBody);
|
||||
}
|
||||
return [];
|
||||
case 'ModuleBody':
|
||||
return LexicallyScopedDeclarations(node.ModuleItemList);
|
||||
case 'FunctionBody':
|
||||
case 'GeneratorBody':
|
||||
case 'AsyncBody':
|
||||
case 'AsyncGeneratorBody':
|
||||
return TopLevelLexicallyScopedDeclarations(node.FunctionStatementList);
|
||||
case 'ClassStaticBlockBody':
|
||||
return TopLevelLexicallyScopedDeclarations(node.ClassStaticBlockStatementList);
|
||||
case 'ImportDeclaration':
|
||||
return [];
|
||||
case 'ClassDeclaration':
|
||||
case 'LexicalDeclaration':
|
||||
case 'FunctionDeclaration':
|
||||
case 'GeneratorDeclaration':
|
||||
case 'AsyncFunctionDeclaration':
|
||||
case 'AsyncGeneratorDeclaration':
|
||||
return [DeclarationPart(node)];
|
||||
case 'CaseBlock': {
|
||||
const names = [];
|
||||
if (node.CaseClauses_a) {
|
||||
names.push(...LexicallyScopedDeclarations(node.CaseClauses_a));
|
||||
}
|
||||
if (node.DefaultClause) {
|
||||
names.push(...LexicallyScopedDeclarations(node.DefaultClause));
|
||||
}
|
||||
if (node.CaseClauses_b) {
|
||||
names.push(...LexicallyScopedDeclarations(node.CaseClauses_b));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
case 'CaseClause':
|
||||
case 'DefaultClause':
|
||||
if (node.StatementList) {
|
||||
return LexicallyScopedDeclarations(node.StatementList);
|
||||
}
|
||||
return [];
|
||||
case 'ExportDeclaration':
|
||||
if (node.Declaration) {
|
||||
return [DeclarationPart(node.Declaration)];
|
||||
}
|
||||
if (node.HoistableDeclaration) {
|
||||
return [DeclarationPart(node.HoistableDeclaration)];
|
||||
}
|
||||
if (node.ClassDeclaration) {
|
||||
return [node.ClassDeclaration];
|
||||
}
|
||||
if (node.AssignmentExpression) {
|
||||
return [node];
|
||||
}
|
||||
return [];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { JSStringValue } from '../value.mts';
|
||||
import { StringValue } from './all.mts';
|
||||
import { type LoadedModuleRequestRecord } from '#self';
|
||||
|
||||
// https://tc39.es/ecma262/#modulerequest-record
|
||||
export interface ModuleRequestRecord {
|
||||
readonly Specifier: JSStringValue;
|
||||
readonly Attributes: ImportAttributeRecord[];
|
||||
readonly Phase: 'defer' | 'evaluation';
|
||||
}
|
||||
|
||||
// https://tc39.es/ecma262/#importattribute-record
|
||||
export interface ImportAttributeRecord {
|
||||
readonly Key: JSStringValue;
|
||||
readonly Value: JSStringValue;
|
||||
}
|
||||
|
||||
function stringsEqual(left: JSStringValue, right: JSStringValue) {
|
||||
return left === right || left.stringValue() === right.stringValue();
|
||||
}
|
||||
|
||||
// https://tc39.es/ecma262/#sec-ModuleRequestsEqual
|
||||
export function ModuleRequestsEqual(left: ModuleRequestRecord | LoadedModuleRequestRecord, right: ModuleRequestRecord | LoadedModuleRequestRecord) {
|
||||
if (!stringsEqual(left.Specifier, right.Specifier)) {
|
||||
return false;
|
||||
}
|
||||
const leftAttrs = left.Attributes;
|
||||
const rightAttrs = right.Attributes;
|
||||
const leftAttrsCount = leftAttrs.length;
|
||||
const rightAttrsCount = rightAttrs.length;
|
||||
if (leftAttrsCount !== rightAttrsCount) {
|
||||
return false;
|
||||
}
|
||||
for (const l of leftAttrs) {
|
||||
if (!rightAttrs.some((r) => stringsEqual(l.Key, r.Key) && stringsEqual(l.Value, r.Value))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://tc39.es/ecma262/#sec-withclausetoattributes
|
||||
function WithClauseToAttributes(node: ParseNode.WithClause): ImportAttributeRecord[] {
|
||||
const attributes: ImportAttributeRecord[] = [];
|
||||
for (const attribute of node.WithEntries) {
|
||||
attributes.push({
|
||||
Key: StringValue(attribute.AttributeKey),
|
||||
Value: StringValue(attribute.AttributeValue),
|
||||
});
|
||||
}
|
||||
attributes.sort((a, b) => (a.Key.value < b.Key.value ? -1 : 1));
|
||||
return attributes;
|
||||
}
|
||||
|
||||
export function ModuleRequests(node: ParseNode): ModuleRequestRecord[] {
|
||||
switch (node.type) {
|
||||
case 'Module':
|
||||
if (node.ModuleBody) {
|
||||
return ModuleRequests(node.ModuleBody);
|
||||
}
|
||||
return [];
|
||||
case 'ModuleBody': {
|
||||
const requests: ModuleRequestRecord[] = [];
|
||||
for (const item of node.ModuleItemList) {
|
||||
const additionalRequests = ModuleRequests(item);
|
||||
for (const mr of additionalRequests) {
|
||||
if (!requests.some((r) => ModuleRequestsEqual(r, mr) && r.Phase === mr.Phase)
|
||||
) {
|
||||
requests.push(mr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return requests;
|
||||
}
|
||||
case 'ImportDeclaration':
|
||||
if (node.FromClause) {
|
||||
const specifier = StringValue(node.FromClause);
|
||||
const attributes = node.WithClause ? WithClauseToAttributes(node.WithClause) : [];
|
||||
return [{ Specifier: specifier, Attributes: attributes, Phase: node.Phase }];
|
||||
}
|
||||
if (node.ModuleSpecifier) {
|
||||
const specifier = StringValue(node.ModuleSpecifier);
|
||||
const attributes = node.WithClause ? WithClauseToAttributes(node.WithClause) : [];
|
||||
return [{ Specifier: specifier, Attributes: attributes, Phase: node.Phase }];
|
||||
}
|
||||
throw new Error('Unreachable: all imports must have either an ImportClause or a ModuleSpecifier');
|
||||
case 'ExportDeclaration':
|
||||
if (node.FromClause) {
|
||||
const specifier = StringValue(node.FromClause);
|
||||
const attributes = node.WithClause ? WithClauseToAttributes(node.WithClause) : [];
|
||||
return [{ Specifier: specifier, Attributes: attributes, Phase: 'evaluation' }];
|
||||
}
|
||||
return [];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { PropName } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-static-semantics-nonconstructorelements */
|
||||
// ClassElementList :
|
||||
// ClassElement
|
||||
// ClassElementList ClassElement
|
||||
export function NonConstructorElements(ClassElementList: ParseNode.ClassElementList) {
|
||||
return ClassElementList.filter((ClassElement) => {
|
||||
if (ClassElement.static === false && PropName(ClassElement) === 'constructor') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/** https://tc39.es/ecma262/#sec-numericvalue */
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { Value } from '../value.mts';
|
||||
|
||||
export function NumericValue(node: ParseNode.NumericLiteral) {
|
||||
return Value(node.value);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { JSStringValue } from '../value.mts';
|
||||
import { StringValue } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-static-semantics-privateboundidentifiers */
|
||||
export function PrivateBoundIdentifiers(node: ParseNode | readonly ParseNode[]): JSStringValue[] {
|
||||
if (isArray(node)) {
|
||||
return node.flatMap((n) => PrivateBoundIdentifiers(n));
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'PrivateIdentifier':
|
||||
return [StringValue(node)];
|
||||
case 'MethodDefinition':
|
||||
case 'GeneratorMethod':
|
||||
case 'AsyncMethod':
|
||||
case 'AsyncGeneratorMethod':
|
||||
case 'FieldDefinition':
|
||||
return PrivateBoundIdentifiers(node.ClassElementName);
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export function PropName(node: ParseNode): string | undefined {
|
||||
switch (node.type) {
|
||||
case 'IdentifierName':
|
||||
return node.name;
|
||||
case 'StringLiteral':
|
||||
return node.value;
|
||||
case 'MethodDefinition':
|
||||
case 'GeneratorMethod':
|
||||
case 'AsyncGeneratorMethod':
|
||||
case 'AsyncMethod':
|
||||
case 'FieldDefinition':
|
||||
return PropName(node.ClassElementName);
|
||||
case 'PropertyDefinition':
|
||||
if (node.PropertyName) {
|
||||
return PropName(node.PropertyName);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { CodePointAt } from './all.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-stringtocodepoints */
|
||||
export function StringToCodePoints(string: string) {
|
||||
// 1. Let codePoints be a new empty List.
|
||||
const codePoints = [];
|
||||
// 2. Let size be the length of string.
|
||||
const size = string.length;
|
||||
// 3. Let position be 0.
|
||||
let position = 0;
|
||||
// 4. Repeat, while position < size,
|
||||
while (position < size) {
|
||||
// a. Let cp be ! CodePointAt(string, position).
|
||||
const cp = CodePointAt(string, position);
|
||||
// b. Append cp.[[CodePoint]] to codePoints.
|
||||
codePoints.push(cp.CodePoint);
|
||||
// c. Set position to position + cp.[[CodeUnitCount]].
|
||||
position += cp.CodeUnitCount;
|
||||
}
|
||||
// 5. Return codePoints.
|
||||
return codePoints;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { OutOfRange } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export function StringValue(node: ParseNode) {
|
||||
switch (node.type) {
|
||||
case 'IdentifierName':
|
||||
case 'BindingIdentifier':
|
||||
case 'IdentifierReference':
|
||||
case 'LabelIdentifier':
|
||||
return Value(node.name);
|
||||
case 'PrivateIdentifier':
|
||||
return Value(`#${node.name}`);
|
||||
case 'StringLiteral':
|
||||
return Value(node.value);
|
||||
default:
|
||||
throw new OutOfRange('StringValue', node);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import { Value } from '../value.mts';
|
||||
import { isHexDigit, isDecimalDigit, isLineTerminator } from '../parser/Lexer.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-static-semantics-tv */
|
||||
export function TV(s: string) {
|
||||
let buffer = '';
|
||||
for (let i = 0; i < s.length; i += 1) {
|
||||
if (s[i] === '\\') {
|
||||
i += 1;
|
||||
switch (s[i]) {
|
||||
case '$':
|
||||
buffer += '$';
|
||||
break;
|
||||
case '\\':
|
||||
buffer += '\\';
|
||||
break;
|
||||
case '`':
|
||||
buffer += '`';
|
||||
break;
|
||||
case '\'':
|
||||
buffer += '\'';
|
||||
break;
|
||||
case '"':
|
||||
buffer += '"';
|
||||
break;
|
||||
case 'b':
|
||||
buffer += '\b';
|
||||
break;
|
||||
case 'f':
|
||||
buffer += '\f';
|
||||
break;
|
||||
case 'n':
|
||||
buffer += '\n';
|
||||
break;
|
||||
case 'r':
|
||||
buffer += '\r';
|
||||
break;
|
||||
case 't':
|
||||
buffer += '\t';
|
||||
break;
|
||||
case 'v':
|
||||
buffer += '\v';
|
||||
break;
|
||||
case 'x':
|
||||
i += 1;
|
||||
if (isHexDigit(s[i]) && isHexDigit(s[i + 1])) {
|
||||
const n = Number.parseInt(s.slice(i, i + 2), 16);
|
||||
i += 1;
|
||||
buffer += String.fromCharCode(n);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
i += 1;
|
||||
if (s[i] === '{') {
|
||||
i += 1;
|
||||
const start = i;
|
||||
do {
|
||||
i += 1;
|
||||
} while (isHexDigit(s[i]));
|
||||
if (s[i] !== '}') {
|
||||
return undefined;
|
||||
}
|
||||
const n = Number.parseInt(s.slice(start, i), 16);
|
||||
if (n > 0x10FFFF) {
|
||||
return undefined;
|
||||
}
|
||||
buffer += String.fromCodePoint(n);
|
||||
} else if (isHexDigit(s[i]) && isHexDigit(s[i + 1])
|
||||
&& isHexDigit(s[i + 2]) && isHexDigit(s[i + 3])) {
|
||||
const n = Number.parseInt(s.slice(i, i + 4), 16);
|
||||
i += 3;
|
||||
buffer += String.fromCodePoint(n);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
break;
|
||||
case '0':
|
||||
if (isDecimalDigit(s[i + 1])) {
|
||||
return undefined;
|
||||
}
|
||||
return '\u{0000}';
|
||||
default:
|
||||
if (isLineTerminator(s)) {
|
||||
return '';
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
buffer += s[i];
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
export function TemplateStrings(node: ParseNode.TemplateLiteral, raw: boolean) {
|
||||
if (raw) {
|
||||
return node.TemplateSpanList.map((s) => Value(s));
|
||||
}
|
||||
return node.TemplateSpanList.map((v) => {
|
||||
const tv = TV(v);
|
||||
if (tv === undefined) {
|
||||
return Value.undefined;
|
||||
}
|
||||
return Value(tv);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { JSStringValue } from '../value.mts';
|
||||
import { BoundNames } from './all.mts';
|
||||
|
||||
export function TopLevelLexicallyDeclaredNames(node: ParseNode | readonly ParseNode[]): JSStringValue[] {
|
||||
if (isArray(node)) {
|
||||
const names = [];
|
||||
for (const StatementListItem of node) {
|
||||
names.push(...TopLevelLexicallyDeclaredNames(StatementListItem));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'ClassDeclaration':
|
||||
case 'LexicalDeclaration':
|
||||
return BoundNames(node);
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
|
||||
export function TopLevelLexicallyScopedDeclarations(node: ParseNode | readonly ParseNode[]): LexicallyScopedDeclaration[] {
|
||||
if (isArray(node)) {
|
||||
const declarations = [];
|
||||
for (const item of node) {
|
||||
declarations.push(...TopLevelLexicallyScopedDeclarations(item));
|
||||
}
|
||||
return declarations;
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'ClassDeclaration':
|
||||
case 'LexicalDeclaration':
|
||||
return [node];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export type LexicallyScopedDeclaration =
|
||||
| ParseNode.ClassDeclaration
|
||||
| ParseNode.LexicalDeclaration;
|
||||
@@ -0,0 +1,26 @@
|
||||
import { isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { JSStringValue } from '../value.mts';
|
||||
import { BoundNames, VarDeclaredNames } from './all.mts';
|
||||
|
||||
export function TopLevelVarDeclaredNames(node: ParseNode | readonly ParseNode[]): JSStringValue[] {
|
||||
if (isArray(node)) {
|
||||
const names = [];
|
||||
for (const item of node) {
|
||||
names.push(...TopLevelVarDeclaredNames(item));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'ClassDeclaration':
|
||||
case 'LexicalDeclaration':
|
||||
return [];
|
||||
case 'FunctionDeclaration':
|
||||
case 'GeneratorDeclaration':
|
||||
case 'AsyncFunctionDeclaration':
|
||||
case 'AsyncGeneratorDeclaration':
|
||||
return BoundNames(node);
|
||||
default:
|
||||
return VarDeclaredNames(node);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { DeclarationPart, VarScopedDeclarations } from './all.mts';
|
||||
|
||||
export function TopLevelVarScopedDeclarations(node: ParseNode | readonly ParseNode[]): VarScopedDeclaration[] {
|
||||
if (isArray(node)) {
|
||||
const declarations = [];
|
||||
for (const item of node) {
|
||||
declarations.push(...TopLevelVarScopedDeclarations(item));
|
||||
}
|
||||
return declarations;
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'ClassDeclaration':
|
||||
case 'LexicalDeclaration':
|
||||
return [];
|
||||
case 'FunctionDeclaration':
|
||||
case 'GeneratorDeclaration':
|
||||
case 'AsyncFunctionDeclaration':
|
||||
case 'AsyncGeneratorDeclaration':
|
||||
return [DeclarationPart(node)];
|
||||
default:
|
||||
return VarScopedDeclarations(node);
|
||||
}
|
||||
}
|
||||
|
||||
export type VarScopedDeclaration =
|
||||
| ParseNode.ForBinding
|
||||
| ParseNode.VariableDeclaration
|
||||
| ParseNode.FunctionDeclaration
|
||||
| ParseNode.GeneratorDeclaration
|
||||
| ParseNode.AsyncFunctionDeclaration
|
||||
| ParseNode.AsyncGeneratorDeclaration
|
||||
| ParseNode.BindingIdentifier;
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Assert } from '#self';
|
||||
import type { CodePoint } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-utf16encodecodepoint */
|
||||
export function UTF16EncodeCodePoint(cp: CodePoint) {
|
||||
// 1. Assert: 0 ≤ cp ≤ 0x10FFFF.
|
||||
Assert(cp >= 0 && cp <= 0x10FFFF);
|
||||
// 2. If cp ≤ 0xFFFF, return the String value consisting of the code unit whose value is cp.
|
||||
if (cp <= 0xFFFF) {
|
||||
return String.fromCodePoint(cp);
|
||||
}
|
||||
// 3. Let cu1 be the code unit whose value is floor((cp - 0x10000) / 0x400) + 0xD800.
|
||||
const cu1 = Math.floor((cp - 0x10000) / 0x400) + 0xD800;
|
||||
// 4. Let cu2 be the code unit whose value is ((cp - 0x10000) modulo 0x400) + 0xDC00.
|
||||
const cu2 = ((cp - 0x10000) % 0x400) + 0xDC00;
|
||||
// 5. Return the string-concatenation of cu1 and cu2.
|
||||
return String.fromCodePoint(cu1, cu2);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Assert } from '#self';
|
||||
import { isLeadingSurrogate, isTrailingSurrogate, type CodePoint } from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-utf16decodesurrogatepair */
|
||||
export function UTF16SurrogatePairToCodePoint(lead: number, trail: number): CodePoint {
|
||||
// 1. Assert: lead is a leading surrogate and trail is a trailing surrogate.
|
||||
Assert(isLeadingSurrogate(lead) && isTrailingSurrogate(trail));
|
||||
// 2. Let cp be (lead - 0xD800) × 0x400 + (trail - 0xDC00) + 0x10000.
|
||||
const cp = (lead - 0xD800) * 0x400 + (trail - 0xDC00) + 0x10000;
|
||||
// 3. Return the code point cp.
|
||||
return cp as CodePoint;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import { isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import type { JSStringValue } from '../value.mts';
|
||||
import { BoundNames, TopLevelVarDeclaredNames } from './all.mts';
|
||||
|
||||
export function VarDeclaredNames(node: ParseNode | readonly ParseNode[]): JSStringValue[] {
|
||||
if (isArray(node)) {
|
||||
const names = [];
|
||||
for (const item of node) {
|
||||
names.push(...VarDeclaredNames(item));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'VariableStatement':
|
||||
return BoundNames(node.VariableDeclarationList);
|
||||
case 'VariableDeclaration':
|
||||
return BoundNames(node);
|
||||
case 'IfStatement': {
|
||||
const names = VarDeclaredNames(node.Statement_a);
|
||||
if (node.Statement_b) {
|
||||
names.push(...VarDeclaredNames(node.Statement_b));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
case 'Block':
|
||||
return VarDeclaredNames(node.StatementList);
|
||||
case 'WhileStatement':
|
||||
return VarDeclaredNames(node.Statement);
|
||||
case 'DoWhileStatement':
|
||||
return VarDeclaredNames(node.Statement);
|
||||
case 'ForStatement': {
|
||||
const names = [];
|
||||
if (node.VariableDeclarationList) {
|
||||
names.push(...VarDeclaredNames(node.VariableDeclarationList));
|
||||
}
|
||||
names.push(...VarDeclaredNames(node.Statement));
|
||||
return names;
|
||||
}
|
||||
case 'ForInStatement':
|
||||
case 'ForOfStatement':
|
||||
case 'ForAwaitStatement': {
|
||||
const names = [];
|
||||
if (node.ForBinding) {
|
||||
names.push(...BoundNames(node.ForBinding));
|
||||
}
|
||||
names.push(...VarDeclaredNames(node.Statement));
|
||||
return names;
|
||||
}
|
||||
case 'WithStatement':
|
||||
return VarDeclaredNames(node.Statement);
|
||||
case 'SwitchStatement':
|
||||
return VarDeclaredNames(node.CaseBlock);
|
||||
case 'CaseBlock': {
|
||||
const names = [];
|
||||
if (node.CaseClauses_a) {
|
||||
names.push(...VarDeclaredNames(node.CaseClauses_a));
|
||||
}
|
||||
if (node.DefaultClause) {
|
||||
names.push(...VarDeclaredNames(node.DefaultClause));
|
||||
}
|
||||
if (node.CaseClauses_b) {
|
||||
names.push(...VarDeclaredNames(node.CaseClauses_b));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
case 'CaseClause':
|
||||
case 'DefaultClause':
|
||||
if (node.StatementList) {
|
||||
return VarDeclaredNames(node.StatementList);
|
||||
}
|
||||
return [];
|
||||
case 'LabelledStatement':
|
||||
return VarDeclaredNames(node.LabelledItem);
|
||||
case 'TryStatement': {
|
||||
const names = VarDeclaredNames(node.Block);
|
||||
if (node.Catch) {
|
||||
names.push(...VarDeclaredNames(node.Catch));
|
||||
}
|
||||
if (node.Finally) {
|
||||
names.push(...VarDeclaredNames(node.Finally));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
case 'Catch':
|
||||
return VarDeclaredNames(node.Block);
|
||||
case 'Script':
|
||||
if (node.ScriptBody) {
|
||||
return VarDeclaredNames(node.ScriptBody);
|
||||
}
|
||||
return [];
|
||||
case 'ScriptBody':
|
||||
return TopLevelVarDeclaredNames(node.StatementList);
|
||||
case 'FunctionBody':
|
||||
case 'GeneratorBody':
|
||||
case 'AsyncBody':
|
||||
case 'AsyncGeneratorBody':
|
||||
return TopLevelVarDeclaredNames(node.FunctionStatementList);
|
||||
case 'ClassStaticBlockBody':
|
||||
return TopLevelVarDeclaredNames(node.ClassStaticBlockStatementList);
|
||||
case 'ExportDeclaration':
|
||||
if (node.VariableStatement) {
|
||||
return BoundNames(node);
|
||||
}
|
||||
return [];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import { isArray } from '../helpers.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { TopLevelVarScopedDeclarations, type VarScopedDeclaration } from './all.mts';
|
||||
|
||||
export function VarScopedDeclarations(node: ParseNode | readonly ParseNode[]): VarScopedDeclaration[] {
|
||||
if (isArray(node)) {
|
||||
const declarations = [];
|
||||
for (const item of node) {
|
||||
declarations.push(...VarScopedDeclarations(item));
|
||||
}
|
||||
return declarations;
|
||||
}
|
||||
switch (node.type) {
|
||||
case 'VariableStatement':
|
||||
return VarScopedDeclarations(node.VariableDeclarationList);
|
||||
case 'VariableDeclaration':
|
||||
return [node];
|
||||
case 'Block':
|
||||
return VarScopedDeclarations(node.StatementList);
|
||||
case 'IfStatement': {
|
||||
const declarations = VarScopedDeclarations(node.Statement_a);
|
||||
if (node.Statement_b) {
|
||||
declarations.push(...VarScopedDeclarations(node.Statement_b));
|
||||
}
|
||||
return declarations;
|
||||
}
|
||||
case 'WhileStatement':
|
||||
return VarScopedDeclarations(node.Statement);
|
||||
case 'DoWhileStatement':
|
||||
return VarScopedDeclarations(node.Statement);
|
||||
case 'ForStatement': {
|
||||
const names = [];
|
||||
if (node.VariableDeclarationList) {
|
||||
names.push(...VarScopedDeclarations(node.VariableDeclarationList));
|
||||
}
|
||||
names.push(...VarScopedDeclarations(node.Statement));
|
||||
return names;
|
||||
}
|
||||
case 'ForInStatement':
|
||||
case 'ForOfStatement':
|
||||
case 'ForAwaitStatement': {
|
||||
const declarations = [];
|
||||
if (node.ForBinding) {
|
||||
declarations.push(node.ForBinding);
|
||||
}
|
||||
declarations.push(...VarScopedDeclarations(node.Statement));
|
||||
return declarations;
|
||||
}
|
||||
case 'WithStatement':
|
||||
return VarScopedDeclarations(node.Statement);
|
||||
case 'SwitchStatement':
|
||||
return VarScopedDeclarations(node.CaseBlock);
|
||||
case 'CaseBlock': {
|
||||
const names = [];
|
||||
if (node.CaseClauses_a) {
|
||||
names.push(...VarScopedDeclarations(node.CaseClauses_a));
|
||||
}
|
||||
if (node.DefaultClause) {
|
||||
names.push(...VarScopedDeclarations(node.DefaultClause));
|
||||
}
|
||||
if (node.CaseClauses_b) {
|
||||
names.push(...VarScopedDeclarations(node.CaseClauses_b));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
case 'CaseClause':
|
||||
case 'DefaultClause':
|
||||
if (node.StatementList) {
|
||||
return VarScopedDeclarations(node.StatementList);
|
||||
}
|
||||
return [];
|
||||
case 'LabelledStatement':
|
||||
return VarScopedDeclarations(node.LabelledItem);
|
||||
case 'TryStatement': {
|
||||
const declarations = VarScopedDeclarations(node.Block);
|
||||
if (node.Catch) {
|
||||
declarations.push(...VarScopedDeclarations(node.Catch));
|
||||
}
|
||||
if (node.Finally) {
|
||||
declarations.push(...VarScopedDeclarations(node.Finally));
|
||||
}
|
||||
return declarations;
|
||||
}
|
||||
case 'Catch':
|
||||
return VarScopedDeclarations(node.Block);
|
||||
case 'ExportDeclaration':
|
||||
if (node.VariableStatement) {
|
||||
return VarScopedDeclarations(node.VariableStatement);
|
||||
}
|
||||
return [];
|
||||
case 'Script':
|
||||
if (node.ScriptBody) {
|
||||
return VarScopedDeclarations(node.ScriptBody);
|
||||
}
|
||||
return [];
|
||||
case 'ScriptBody':
|
||||
return TopLevelVarScopedDeclarations(node.StatementList);
|
||||
case 'Module':
|
||||
if (node.ModuleBody) {
|
||||
return VarScopedDeclarations(node.ModuleBody);
|
||||
}
|
||||
return [];
|
||||
case 'ModuleBody':
|
||||
return VarScopedDeclarations(node.ModuleItemList);
|
||||
case 'FunctionBody':
|
||||
case 'GeneratorBody':
|
||||
case 'AsyncBody':
|
||||
case 'AsyncGeneratorBody':
|
||||
return TopLevelVarScopedDeclarations(node.FunctionStatementList);
|
||||
case 'ClassStaticBlockBody':
|
||||
return TopLevelVarScopedDeclarations(node.ClassStaticBlockStatementList);
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
export * from './StringValue.mts';
|
||||
export * from './IsStatic.mts';
|
||||
export * from './NonConstructorElements.mts';
|
||||
export * from './ConstructorMethod.mts';
|
||||
export * from './PropName.mts';
|
||||
export * from './NumericValue.mts';
|
||||
export * from './IsAnonymousFunctionDefinition.mts';
|
||||
export * from './IsFunctionDefinition.mts';
|
||||
export * from './HasName.mts';
|
||||
export * from './IsIdentifierRef.mts';
|
||||
export * from './LexicallyDeclaredNames.mts';
|
||||
export * from './TopLevelLexicallyDeclaredNames.mts';
|
||||
export * from './BoundNames.mts';
|
||||
export * from './VarDeclaredNames.mts';
|
||||
export * from './TopLevelVarDeclaredNames.mts';
|
||||
export * from './VarScopedDeclarations.mts';
|
||||
export * from './TopLevelVarScopedDeclarations.mts';
|
||||
export * from './DeclarationPart.mts';
|
||||
export * from './LexicallyScopedDeclarations.mts';
|
||||
export * from './TopLevelLexicallyScopedDeclarations.mts';
|
||||
export * from './IsConstantDeclaration.mts';
|
||||
export * from './IsInTailPosition.mts';
|
||||
export * from './ExpectedArgumentCount.mts';
|
||||
export * from './HasInitializer.mts';
|
||||
export * from './IsSimpleParameterList.mts';
|
||||
export * from './ContainsExpression.mts';
|
||||
export * from './IsStrict.mts';
|
||||
export * from './BodyText.mts';
|
||||
export * from './FlagText.mts';
|
||||
export * from './ModuleRequests.mts';
|
||||
export * from './ImportEntries.mts';
|
||||
export * from './ExportEntries.mts';
|
||||
export * from './ImportedLocalNames.mts';
|
||||
export * from './IsDestructuring.mts';
|
||||
export * from './TemplateStrings.mts';
|
||||
export * from './ImportEntriesForModule.mts';
|
||||
export * from './ExportEntriesForModule.mts';
|
||||
export * from './CharacterValue.mts';
|
||||
export * from './UTF16SurrogatePairToCodePoint.mts';
|
||||
export * from './CodePointAt.mts';
|
||||
export * from './StringToCodePoints.mts';
|
||||
export * from './CodePointsToString.mts';
|
||||
export * from './IsStringWellFormedUnicode.mts';
|
||||
export * from './IsComputedPropertyKey.mts';
|
||||
export * from './PrivateBoundIdentifiers.mts';
|
||||
export * from './ContainsArguments.mts';
|
||||
export * from './UTF16EncodeCodePoint.mts';
|
||||
Reference in New Issue
Block a user