123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- using Jint.Runtime.Modules;
- namespace Jint;
- internal sealed class HoistingScope
- {
- internal readonly List<FunctionDeclaration>? _functionDeclarations;
- internal readonly List<VariableDeclaration>? _variablesDeclarations;
- internal readonly List<Key>? _varNames;
- internal readonly List<Declaration>? _lexicalDeclarations;
- internal readonly List<string>? _lexicalNames;
- private HoistingScope(
- List<FunctionDeclaration>? functionDeclarations,
- List<Key>? varNames,
- List<VariableDeclaration>? variableDeclarations,
- List<Declaration>? lexicalDeclarations,
- List<string>? lexicalNames)
- {
- _functionDeclarations = functionDeclarations;
- _varNames = varNames;
- _variablesDeclarations = variableDeclarations;
- _lexicalDeclarations = lexicalDeclarations;
- _lexicalNames = lexicalNames;
- }
- public static HoistingScope GetProgramLevelDeclarations(
- Program script,
- bool collectVarNames = false,
- bool collectLexicalNames = false)
- {
- var treeWalker = new ScriptWalker(collectVarNames, collectLexicalNames);
- treeWalker.Visit(script, null);
- return new HoistingScope(
- treeWalker._functions,
- treeWalker._varNames,
- treeWalker._variableDeclarations,
- treeWalker._lexicalDeclarations,
- treeWalker._lexicalNames);
- }
- public static HoistingScope GetFunctionLevelDeclarations(bool strict, IFunction node)
- {
- var treeWalker = new ScriptWalker(collectVarNames: true, collectLexicalNames: true);
- treeWalker.Visit(node.Body, null);
- return new HoistingScope(
- treeWalker._functions,
- treeWalker._varNames,
- treeWalker._variableDeclarations,
- treeWalker._lexicalDeclarations,
- treeWalker._lexicalNames);
- }
- public static HoistingScope GetModuleLevelDeclarations(
- AstModule module,
- bool collectVarNames = false,
- bool collectLexicalNames = false)
- {
- // modules area always strict
- var treeWalker = new ScriptWalker(collectVarNames, collectLexicalNames);
- treeWalker.Visit(module, null);
- return new HoistingScope(
- treeWalker._functions,
- treeWalker._varNames,
- treeWalker._variableDeclarations,
- treeWalker._lexicalDeclarations,
- treeWalker._lexicalNames);
- }
- public static List<Declaration>? GetLexicalDeclarations(BlockStatement statement)
- {
- List<Declaration>? lexicalDeclarations = null;
- ref readonly var statementListItems = ref statement.Body;
- for (var i = 0; i < statementListItems.Count; i++)
- {
- var node = statementListItems[i];
- if (node.Type != NodeType.VariableDeclaration && node.Type != NodeType.FunctionDeclaration && node.Type != NodeType.ClassDeclaration)
- {
- continue;
- }
- if (node is VariableDeclaration { Kind: VariableDeclarationKind.Var })
- {
- continue;
- }
- lexicalDeclarations ??= new List<Declaration>();
- lexicalDeclarations.Add((Declaration)node);
- }
- return lexicalDeclarations;
- }
- public static List<Declaration>? GetLexicalDeclarations(SwitchCase statement)
- {
- List<Declaration>? lexicalDeclarations = null;
- ref readonly var statementListItems = ref statement.Consequent;
- for (var i = 0; i < statementListItems.Count; i++)
- {
- var node = statementListItems[i];
- if (node.Type != NodeType.VariableDeclaration)
- {
- continue;
- }
- var rootVariable = (VariableDeclaration)node;
- if (rootVariable.Kind == VariableDeclarationKind.Var)
- {
- continue;
- }
- lexicalDeclarations ??= new List<Declaration>();
- lexicalDeclarations.Add(rootVariable);
- }
- return lexicalDeclarations;
- }
- public static void GetImportsAndExports(
- AstModule module,
- out HashSet<ModuleRequest> requestedModules,
- out List<ImportEntry>? importEntries,
- out List<ExportEntry> localExportEntries,
- out List<ExportEntry> indirectExportEntries,
- out List<ExportEntry> starExportEntries)
- {
- var treeWalker = new ModuleWalker();
- treeWalker.Visit(module);
- importEntries = treeWalker._importEntries;
- requestedModules = treeWalker._requestedModules ?? [];
- var importedBoundNames = new HashSet<string?>(StringComparer.Ordinal);
- if (importEntries != null)
- {
- for (var i = 0; i < importEntries.Count; i++)
- {
- var ie = importEntries[i];
- if (ie.LocalName is not null)
- {
- importedBoundNames.Add(ie.LocalName);
- }
- }
- }
- var exportEntries = treeWalker._exportEntries;
- localExportEntries = new();
- indirectExportEntries = new();
- starExportEntries = new();
- if (exportEntries != null)
- {
- for (var i = 0; i < exportEntries.Count; i++)
- {
- var ee = exportEntries[i];
- if (ee.ModuleRequest is null)
- {
- if (!importedBoundNames.Contains(ee.LocalName))
- {
- localExportEntries.Add(ee);
- }
- else
- {
- for (var j = 0; j < importEntries!.Count; j++)
- {
- var ie = importEntries[j];
- if (string.Equals(ie.LocalName, ee.LocalName, StringComparison.Ordinal))
- {
- if (string.Equals(ie.ImportName, "*", StringComparison.Ordinal))
- {
- localExportEntries.Add(ee);
- }
- else
- {
- indirectExportEntries.Add(new(ee.ExportName, ie.ModuleRequest, ie.ImportName, null));
- }
- break;
- }
- }
- }
- }
- else if (string.Equals(ee.ImportName, "*", StringComparison.Ordinal) && ee.ExportName is null)
- {
- starExportEntries.Add(ee);
- }
- else
- {
- indirectExportEntries.Add(ee);
- }
- }
- }
- }
- private sealed class ScriptWalker
- {
- internal List<FunctionDeclaration>? _functions;
- private readonly bool _collectVarNames;
- internal List<VariableDeclaration>? _variableDeclarations;
- internal List<Key>? _varNames;
- private readonly bool _collectLexicalNames;
- internal List<Declaration>? _lexicalDeclarations;
- internal List<string>? _lexicalNames;
- public ScriptWalker(bool collectVarNames, bool collectLexicalNames)
- {
- _collectVarNames = collectVarNames;
- _collectLexicalNames = collectLexicalNames;
- }
- public void Visit(Node node, Node? parent)
- {
- foreach (var childNode in node.ChildNodes)
- {
- var childType = childNode.Type;
- if (childType == NodeType.VariableDeclaration)
- {
- var variableDeclaration = (VariableDeclaration)childNode;
- if (variableDeclaration.Kind == VariableDeclarationKind.Var)
- {
- _variableDeclarations ??= new List<VariableDeclaration>();
- _variableDeclarations.Add(variableDeclaration);
- if (_collectVarNames)
- {
- _varNames ??= new List<Key>();
- ref readonly var nodeList = ref variableDeclaration.Declarations;
- foreach (var declaration in nodeList)
- {
- if (declaration.Id is Identifier identifier)
- {
- _varNames.Add(identifier.Name);
- }
- }
- }
- }
- if (parent is null or AstModule && variableDeclaration.Kind != VariableDeclarationKind.Var)
- {
- _lexicalDeclarations ??= new List<Declaration>();
- _lexicalDeclarations.Add(variableDeclaration);
- if (_collectLexicalNames)
- {
- _lexicalNames ??= new List<string>();
- ref readonly var nodeList = ref variableDeclaration.Declarations;
- foreach (var declaration in nodeList)
- {
- if (declaration.Id is Identifier identifier)
- {
- _lexicalNames.Add(identifier.Name);
- }
- }
- }
- }
- }
- else if (childType == NodeType.FunctionDeclaration)
- {
- // function declarations are not hoisted if they are under block or case clauses
- if (parent is null || (node.Type != NodeType.BlockStatement && node.Type != NodeType.SwitchCase))
- {
- _functions ??= new List<FunctionDeclaration>();
- _functions.Add((FunctionDeclaration)childNode);
- }
- }
- else if (childType == NodeType.ClassDeclaration && parent is null or AstModule)
- {
- _lexicalDeclarations ??= new List<Declaration>();
- _lexicalDeclarations.Add((Declaration) childNode);
- }
- if (childType != NodeType.FunctionDeclaration
- && childType != NodeType.ArrowFunctionExpression
- && childType != NodeType.FunctionExpression
- && !childNode.ChildNodes.IsEmpty())
- {
- Visit(childNode, node);
- }
- }
- }
- }
- private sealed class ModuleRequestRecordComparer : IComparer<ModuleRequest>
- {
- public int Compare(ModuleRequest x, ModuleRequest y)
- {
- return string.Compare(x.Specifier, y.Specifier, StringComparison.Ordinal);
- }
- }
- private sealed class ModuleWalker
- {
- internal List<ImportEntry>? _importEntries;
- internal List<ExportEntry>? _exportEntries;
- internal HashSet<ModuleRequest>? _requestedModules;
- internal void Visit(Node node)
- {
- foreach (var childNode in node.ChildNodes)
- {
- if (childNode.Type == NodeType.ImportDeclaration)
- {
- _importEntries ??= [];
- _requestedModules ??= [];
- var import = (ImportDeclaration) childNode;
- import.GetImportEntries(_importEntries, _requestedModules);
- }
- else if (childNode.Type is NodeType.ExportAllDeclaration or NodeType.ExportDefaultDeclaration or NodeType.ExportNamedDeclaration)
- {
- _exportEntries ??= [];
- _requestedModules ??= [];
- var export = (ExportDeclaration) childNode;
- export.GetExportEntries(_exportEntries, _requestedModules);
- }
- if (!childNode.ChildNodes.IsEmpty())
- {
- Visit(childNode);
- }
- }
- }
- }
- }
|