/** * Copyright (c) 2012-2016 André Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.semantics; import static java.util.Collections.emptySet; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.github.anba.es6draft.ast.*; import com.github.anba.es6draft.ast.scope.BlockScope; import com.github.anba.es6draft.ast.scope.Name; import com.github.anba.es6draft.runtime.internal.InlineArrayList; import com.github.anba.es6draft.runtime.modules.ExportEntry; import com.github.anba.es6draft.runtime.modules.ImportEntry; /** * <h1>Static Semantics</h1> * <ul> * <li>BoundNames * <li>ConstructorMethod * <li>ContainsExpression * <li>ExpectedArgumentCount * <li>ExportEntries * <li>HasInitializer * <li>HasName * <li>ImportedLocalNames * <li>ImportEntries * <li>IsAnonymousFunctionDefinition * <li>IsConstantDeclaration * <li>IsFunctionDefinition * <li>IsIdentifierRef * <li>IsSimpleParameterList * <li>IsStrict * <li>LexicallyDeclaredNames * <li>LexicallyScopedDeclarations * <li>ModuleRequests * <li>PropName * <li>SpecialMethod * <li>VarDeclaredNames * <li>VarScopedDeclarations * </ul> */ public final class StaticSemantics { private StaticSemantics() { } /** * Static Semantics: BoundNames * <ul> * <li>12.1.2 Static Semantics: BoundNames * </ul> * * @param node * the binding identifier * @return the bound name */ public static Name BoundName(BindingIdentifier node) { return node.getName(); } /** * Static Semantics: BoundNames * <ul> * <li>14.1.3 Static Semantics: BoundNames * <li>14.4.2 Static Semantics: BoundNames * </ul> * * @param node * the hoistable declaration * @return the bound name */ public static Name BoundName(HoistableDeclaration node) { return node.getName(); } /** * Static Semantics: BoundNames * <ul> * <li>14.5.2 Static Semantics: BoundNames * </ul> * * @param node * the hoistable declaration * @return the bound name */ public static Name BoundName(ClassDeclaration node) { return node.getName(); } /** * Static Semantics: BoundNames * <ul> * <li>12.1.2 Static Semantics: BoundNames * <li>13.3.3.1 Static Semantics: BoundNames * </ul> * * @param node * the binding node * @return the bound names */ public static List<Name> BoundNames(BindingIdentifier node) { return singletonList(node.getName()); } /** * Static Semantics: BoundNames * <ul> * <li>12.1.2 Static Semantics: BoundNames * <li>13.3.3.1 Static Semantics: BoundNames * </ul> * * @param node * the binding node * @return the bound names */ public static List<Name> BoundNames(Binding node) { if (node instanceof BindingIdentifier) { return singletonList(((BindingIdentifier) node).getName()); } assert node instanceof BindingPattern; return node.accept(BoundNames.INSTANCE, new InlineArrayList<>()); } /** * Static Semantics: BoundNames * <ul> * <li>14.1.3 Static Semantics: BoundNames * <li>14.2.2 Static Semantics: BoundNames * </ul> * * @param node * the formal parameters list * @return the bound names */ public static List<Name> BoundNames(FormalParameterList node) { return BoundNames(node.getFormals()); } /** * Static Semantics: BoundNames * <ul> * <li>14.1.3 Static Semantics: BoundNames * <li>14.2.2 Static Semantics: BoundNames * </ul> * * @param formals * the formal parameters list * @return the bound names */ public static List<Name> BoundNames(List<FormalParameter> formals) { // TODO: Some callers expect the returned list to be mutable. InlineArrayList<Name> list = new InlineArrayList<>(); for (FormalParameter formalParameter : formals) { formalParameter.accept(BoundNames.INSTANCE, list); } return list; } /** * Static Semantics: BoundNames * <ul> * <li>14.1.3 Static Semantics: BoundNames * <li>14.2.2 Static Semantics: BoundNames * </ul> * * @param node * the formal parameter node * @return the bound names */ public static List<Name> BoundNames(FormalParameter node) { BindingElementItem element = node.getElement(); if (element instanceof BindingElement) { return BoundNames(((BindingElement) element).getBinding()); } return BoundNames(((BindingRestElement) element).getBinding()); } /** * Static Semantics: BoundNames * <ul> * <li>13.3.1.2 Static Semantics: BoundNames * <li>14.1.3 Static Semantics: BoundNames * <li>14.4.2 Static Semantics: BoundNames * <li>14.5.2 Static Semantics: BoundNames * </ul> * * @param node * the declaration node * @return the bound names */ public static List<Name> BoundNames(Declaration node) { if (node instanceof HoistableDeclaration) { return singletonList(BoundName((HoistableDeclaration) node)); } if (node instanceof ClassDeclaration) { return singletonList(BoundName((ClassDeclaration) node)); } if (node instanceof ExportDefaultExpression) { return BoundNames(((ExportDefaultExpression) node).getBinding()); } assert node instanceof LexicalDeclaration; return node.accept(BoundNames.INSTANCE, new InlineArrayList<>()); } /** * 13.3.2.1 Static Semantics: BoundNames * * @param node * the variable statement * @return the bound names */ public static List<Name> BoundNames(VariableStatement node) { return node.accept(BoundNames.INSTANCE, new InlineArrayList<>()); } /** * 13.3.2.1 Static Semantics: BoundNames * * @param node * the variable statement * @return the bound names */ public static List<Name> BoundNames(VariableDeclaration node) { return BoundNames(node.getBinding()); } /** * 15.2.2.2 Static Semantics: BoundNames * * @param node * the import declaration * @return the bound names */ public static List<Name> BoundNames(ImportDeclaration node) { return node.accept(BoundNames.INSTANCE, new InlineArrayList<>()); } /** * 15.2.3.2 Static Semantics: BoundNames * * @param node * the export declaration * @return the bound names */ public static List<Name> BoundNames(ExportDeclaration node) { return node.accept(BoundNames.INSTANCE, new InlineArrayList<>()); } /** * 14.5.3 Static Semantics: ConstructorMethod * * @param node * the class definition node * @return the constructor method if found, otherwise {@code null} */ public static MethodDefinition ConstructorMethod(ClassDefinition node) { return node.getConstructor(); } /** * 14.5.3 Static Semantics: ConstructorMethod * * @param methods * the methods list * @return the constructor method if found, otherwise {@code null} */ public static MethodDefinition ConstructorMethod(List<MethodDefinition> methods) { for (MethodDefinition m : methods) { if (m.isClassConstructor()) { return m; } } return null; } /** * Static Semantics: CallConstructorMethod * * @param methods * the methods list * @return the call constructor method if found, otherwise {@code null} */ public static MethodDefinition CallConstructorMethod(List<MethodDefinition> methods) { for (MethodDefinition m : methods) { if (m.isCallConstructor()) { return m; } } return null; } /** * Static Semantics: ContainsExpression * <ul> * <li>13.3.3.2 Static Semantics: ContainsExpression * <li>14.1.5 Static Semantics: ContainsExpression * <li>14.2.4 Static Semantics: ContainsExpression * </ul> * * @param formals * the formal parameters * @return {@code true} if an expression was found */ public static boolean ContainsExpression(FormalParameterList formals) { return formals.containsExpression(); } /** * Static Semantics: ContainsExpression * <ul> * <li>13.3.3.2 Static Semantics: ContainsExpression * <li>14.1.5 Static Semantics: ContainsExpression * <li>14.2.4 Static Semantics: ContainsExpression * </ul> * * @param formals * the formal parameters * @return {@code true} if an expression was found */ public static boolean ContainsExpression(List<FormalParameter> formals) { for (FormalParameter formal : formals) { BindingElementItem element = formal.getElement(); if (element instanceof BindingElement && ContainsExpression((BindingElement) element)) { return true; } } return false; } /** * 13.3.3.2 Static Semantics: ContainsExpression * * @param element * the binding element node * @return {@code true} if an expression was found */ private static boolean ContainsExpression(BindingElement element) { if (element.getInitializer() != null) { return true; } return ContainsExpression(element.getBinding()); } /** * 13.3.3.2 Static Semantics: ContainsExpression * * @param binding * the binding node * @return {@code true} if an expression was found */ private static boolean ContainsExpression(Binding binding) { if (binding instanceof ArrayBindingPattern) { return ContainsExpression((ArrayBindingPattern) binding); } if (binding instanceof ObjectBindingPattern) { return ContainsExpression((ObjectBindingPattern) binding); } assert binding instanceof BindingIdentifier; return false; } /** * 13.3.3.2 Static Semantics: ContainsExpression * * @param pattern * the array binding pattern node * @return {@code true} if an expression was found */ private static boolean ContainsExpression(ArrayBindingPattern pattern) { for (BindingElementItem item : pattern.getElements()) { if (item instanceof BindingElement && ContainsExpression((BindingElement) item)) { return true; } } return false; } /** * 13.3.3.2 Static Semantics: ContainsExpression * * @param pattern * the object binding pattern node * @return {@code true} if an expression was found */ private static boolean ContainsExpression(ObjectBindingPattern pattern) { for (BindingProperty property : pattern.getProperties()) { if (property.getPropertyName() instanceof ComputedPropertyName) { return true; } if (property.getInitializer() != null) { return true; } if (ContainsExpression(property.getBinding())) { return true; } } return false; } /** * Static Semantics: ExpectedArgumentCount * <ul> * <li>14.1.6 Static Semantics: ExpectedArgumentCount * <li>14.2.5 Static Semantics: ExpectedArgumentCount * <li>14.3.3 Static Semantics: ExpectedArgumentCount * </ul> * * @param formals * the formal parameters list * @return the expected arguments count */ public static int ExpectedArgumentCount(FormalParameterList formals) { int count = 0; for (FormalParameter formal : formals) { BindingElementItem element = formal.getElement(); if (element instanceof BindingRestElement) { break; } if (HasInitializer((BindingElement) element)) { break; } count += 1; } return count; } /** * 13.3.3.3 Static Semantics: HasInitializer * * @param node * the binding element * @return {@code true} if the binding element has an initializer */ private static boolean HasInitializer(BindingElement node) { return node.getInitializer() != null; } /** * 14.1.9 Static Semantics: IsAnonymousFunctionDefinition (production) * * @param node * the expression node * @return {@code true} if the node is an anonymous function definition */ public static boolean IsAnonymousFunctionDefinition(Expression node) { if (node instanceof FunctionNode) { return ((FunctionNode) node).getIdentifier() == null; } if (node instanceof ClassExpression) { return ((ClassExpression) node).getIdentifier() == null; } return false; } /** * Static Semantics: HasName * <ul> * <li>14.1.8 Static Semantics: HasName * <li>14.2.7 Static Semantics: HasName * <li>14.4.7 Static Semantics: HasName * </ul> * * @param <FUNCTION> * the function type * @param node * the function node * @return {@code true} if the function has a binding name */ public static <FUNCTION extends Expression & FunctionNode> boolean HasName(FUNCTION node) { return node.getIdentifier() != null; } /** * 14.5.6 Static Semantics: HasName * * @param node * the function node * @return {@code true} if the function has a binding name */ public static boolean HasName(ClassExpression node) { return node.getIdentifier() != null; } /** * Static Semantics: IsConstantDeclaration * <ul> * <li>13.3.1.3 Static Semantics: IsConstantDeclaration * <li>14.1.10 Static Semantics: IsConstantDeclaration * <li>14.4.8 Static Semantics: IsConstantDeclaration * <li>14.5.7 Static Semantics: IsConstantDeclaration * <li>15.2.3.7 Static Semantics: IsConstantDeclaration * </ul> * * @param node * the declaration node * @return {@code true} if the node is a constant declaration */ public static boolean IsConstantDeclaration(Declaration node) { return node.isConstDeclaration(); } /** * Static Semantics: IsFunctionDefinition * <ul> * <li>12.2.1.3 Static Semantics: IsFunctionDefinition * <li>12.2.10.2 Static Semantics: IsFunctionDefinition * <li>12.3.1.2 Static Semantics: IsFunctionDefinition * <li>12.4.2 Static Semantics: IsFunctionDefinition * <li>12.5.2 Static Semantics: IsFunctionDefinition * <li>12.6.1 Static Semantics: IsFunctionDefinition * <li>12.7.1 Static Semantics: IsFunctionDefinition * <li>12.8.1 Static Semantics: IsFunctionDefinition * <li>12.9.1 Static Semantics: IsFunctionDefinition * <li>12.10.1 Static Semantics: IsFunctionDefinition * <li>12.11.1 Static Semantics: IsFunctionDefinition * <li>12.12.1 Static Semantics: IsFunctionDefinition * <li>12.13.1 Static Semantics: IsFunctionDefinition * <li>12.14.2 Static Semantics: IsFunctionDefinition * <li>12.15.1 Static Semantics: IsFunctionDefinition * <li>14.1.11 Static Semantics: IsFunctionDefinition * <li>14.4.9 Static Semantics: IsFunctionDefinition * <li>14.5.8 Static Semantics: IsFunctionDefinition * </ul> * * @param node * the expression node * @return {@code true} if the node is a function definition */ public static boolean IsFunctionDefinition(Expression node) { return node instanceof FunctionNode || node instanceof ClassExpression; } /** * Static Semantics: IsIdentifierRef * <ul> * <li>12.2.1.4 Static Semantics: IsIdentifierRef * <li>12.3.1.4 Static Semantics: IsIdentifierRef * </ul> * * @param node * the left-hand side expression node * @return {@code true} if node is an identifier */ public static boolean IsIdentifierRef(LeftHandSideExpression node) { return node instanceof IdentifierReference && !node.isParenthesized(); } /** * Static Semantics: IsSimpleParameterList * <ul> * <li>14.1.12 Static Semantics: IsSimpleParameterList * <li>14.2.8 Static Semantics: IsSimpleParameterList * </ul> * * @param formals * the formal parameters list * @return {@code true} if the list is a simple formal parameters list */ public static boolean IsSimpleParameterList(FormalParameterList formals) { return formals.isSimpleParameterList(); } /** * Static Semantics: IsSimpleParameterList * <ul> * <li>14.1.12 Static Semantics: IsSimpleParameterList * <li>14.2.8 Static Semantics: IsSimpleParameterList * </ul> * * @param formals * the formal parameters list * @return {@code true} if the list is a simple formal parameters list */ public static boolean IsSimpleParameterList(List<FormalParameter> formals) { for (FormalParameter formal : formals) { BindingElementItem element = formal.getElement(); if (element instanceof BindingRestElement) { return false; } if (HasInitializer((BindingElement) element)) { return false; } if (((BindingElement) element).getBinding() instanceof BindingPattern) { return false; } } return true; } /** * 15.1.2 Static Semantics: IsStrict * * @param node * the script node * @return {@code true} if the node is strict mode script */ public static boolean IsStrict(Script node) { return node.isStrict(); } /** * 15.2.1.9 Static Semantics: IsStrict * * @param node * the module node * @return {@code true} if the node is strict mode module */ public static boolean IsStrict(Module node) { return true; } /** * 14.1.13 Static Semantics: IsStrict * * @param node * the function node * @return {@code true} if the node is strict mode function */ public static boolean IsStrict(FunctionNode node) { return node.getStrictMode() != FunctionNode.StrictMode.NonStrict; } /** * 13.1.6 Static Semantics: LexicallyScopedDeclarations * * @param node * the block statement node * @return the list of lexically scoped declarations */ public static List<Declaration> LexicallyScopedDeclarations(BlockStatement node) { return node.getScope().lexicallyScopedDeclarations(); } /** * 13.11.6 Static Semantics: LexicallyScopedDeclarations * * @param node * the switch statement node * @return the list of lexically scoped declarations */ public static List<Declaration> LexicallyScopedDeclarations(SwitchStatement node) { return node.getScope().lexicallyScopedDeclarations(); } /** * Static Semantics: LexicallyScopedDeclarations * <ul> * <li>14.1.15 Static Semantics: LexicallyScopedDeclarations * <li>14.2.11 Static Semantics: LexicallyScopedDeclarations * </ul> * * @param node * the function node * @return the list of lexically scoped declarations */ public static List<Declaration> LexicallyScopedDeclarations(FunctionNode node) { return node.getScope().lexicallyScopedDeclarations(); } /** * 15.1.4 Static Semantics: LexicallyScopedDeclarations * * @param node * the script node * @return the list of lexically scoped declarations */ public static List<Declaration> LexicallyScopedDeclarations(Script node) { return node.getScope().lexicallyScopedDeclarations(); } /** * 13.1.5 Static Semantics: LexicallyDeclaredNames * * @param node * the block statement node * @return the set of lexically declared names */ public static Set<Name> LexicallyDeclaredNames(BlockStatement node) { return node.getScope().lexicallyDeclaredNames(); } /** * 13.11.5 Static Semantics: LexicallyDeclaredNames * * @param node * the switch statement node * @return the list of lexically scoped declarations */ public static Set<Name> LexicallyDeclaredNames(SwitchStatement node) { return node.getScope().lexicallyDeclaredNames(); } /** * Static Semantics: LexicallyDeclaredNames * * @param scope * the block scope * @return the set of lexically declared names */ public static Set<Name> LexicallyDeclaredNames(BlockScope scope) { return scope.lexicallyDeclaredNames(); } /** * Static Semantics: LexicallyDeclaredNames * <ul> * <li>14.1.14 Static Semantics: LexicallyDeclaredNames * <li>14.2.10 Static Semantics: LexicallyDeclaredNames * </ul> * * @param node * the script node * @return the set of lexically declared names */ public static Set<Name> LexicallyDeclaredNames(FunctionNode node) { return node.getScope().lexicallyDeclaredNames(); } /** * 15.1.3 Static Semantics: LexicallyDeclaredNames * * @param node * the script node * @return the set of lexically declared names */ public static Set<Name> LexicallyDeclaredNames(Script node) { return node.getScope().lexicallyDeclaredNames(); } /** * Static Semantics: VarDeclaredNames * <ul> * <li>14.1.16 Static Semantics: VarDeclaredNames * <li>14.2.12 Static Semantics: VarDeclaredNames * </ul> * * <pre> * FunctionStatementList : * StatementList * </pre> * * @param node * the function node * @return the set of variable declared names */ public static Set<Name> VarDeclaredNames(FunctionNode node) { return node.getScope().varDeclaredNames(); } /** * 15.1.5 Static Semantics: VarDeclaredNames * * @param node * the script node * @return the set of variable declared names */ public static Set<Name> VarDeclaredNames(Script node) { return node.getScope().varDeclaredNames(); } /** * Static Semantics: VarScopedDeclarations * <ul> * <li>14.1.17 Static Semantics: VarScopedDeclarations * <li>14.2.13 Static Semantics: VarScopedDeclarations * </ul> * * @param node * the function node * @return the list of variable scoped declarations */ public static List<StatementListItem> VarScopedDeclarations(FunctionNode node) { return node.getScope().varScopedDeclarations(); } /** * 15.1.6 Static Semantics: VarScopedDeclarations * * @param node * the script node * @return the list of variable scoped declarations */ public static List<StatementListItem> VarScopedDeclarations(Script node) { return node.getScope().varScopedDeclarations(); } /** * 15.2.1.7 Static Semantics: ExportEntries<br> * 15.2.3.5 Static Semantics: ExportEntries * * @param node * the module node * @return the list of export entries */ public static List<ExportEntry> ExportEntries(Module node) { ArrayList<ExportEntry> entries = new ArrayList<>(); for (ModuleItem item : node.getStatements()) { if (item instanceof ExportDeclaration) { ExportDeclaration exportDecl = (ExportDeclaration) item; switch (exportDecl.getType()) { case All: { String module = exportDecl.getModuleSpecifier(); entries.add(new ExportEntry(item, module, "*", null, null)); break; } case External: { String module = exportDecl.getModuleSpecifier(); ExportEntriesForModule(exportDecl.getExportClause(), module, entries); break; } case Local: ExportEntriesForModule(exportDecl.getExportClause(), null, entries); break; case Variable: for (Name name : BoundNames(exportDecl.getVariableStatement())) { String id = name.getIdentifier(); entries.add(new ExportEntry(item, null, null, id, id)); } break; case Declaration: for (Name name : BoundNames(exportDecl.getDeclaration())) { String id = name.getIdentifier(); entries.add(new ExportEntry(item, null, null, id, id)); } break; case DefaultHoistableDeclaration: { Name localName = BoundName(exportDecl.getHoistableDeclaration()); entries.add(new ExportEntry(item, null, null, localName.getIdentifier(), "default")); break; } case DefaultClassDeclaration: { Name localName = BoundName(exportDecl.getClassDeclaration()); entries.add(new ExportEntry(item, null, null, localName.getIdentifier(), "default")); break; } case DefaultExpression: { Name localName = BoundName(exportDecl.getExpression().getBinding()); entries.add(new ExportEntry(item, null, null, localName.getIdentifier(), "default")); break; } default: throw new AssertionError(); } } } return entries; } /** * 15.2.3.6 Static Semantics: ExportEntriesForModule * * @param node * the exports clause node * @param module * the module name * @param entries * the list of export entries */ private static void ExportEntriesForModule(ExportClause node, String module, List<ExportEntry> entries) { if (module == null) { assert node.getDefaultEntry() == null; assert node.getNameSpace() == null; for (ExportSpecifier specifier : node.getExports()) { String localName = specifier.getSourceName(); String importName = null; String exportName = specifier.getExportName(); entries.add(new ExportEntry(specifier, module, importName, localName, exportName)); } } else { IdentifierName defaultEntry = node.getDefaultEntry(); if (defaultEntry != null) { String exportName = defaultEntry.getName(); entries.add(new ExportEntry(defaultEntry, module, "default", null, exportName)); } IdentifierName nameSpace = node.getNameSpace(); if (nameSpace != null) { String exportName = nameSpace.getName(); entries.add(new ExportEntry(nameSpace, module, "*", null, exportName)); } for (ExportSpecifier specifier : node.getExports()) { String localName = null; String importName = specifier.getSourceName(); String exportName = specifier.getExportName(); entries.add(new ExportEntry(specifier, module, importName, localName, exportName)); } } } /** * 15.2.1.8 Static Semantics: ImportEntries<br> * 15.2.2.3 Static Semantics: ImportEntries * * @param node * the module node * @return the list of import entries */ public static List<ImportEntry> ImportEntries(Module node) { ArrayList<ImportEntry> entries = new ArrayList<>(); for (ModuleItem item : node.getStatements()) { if (item instanceof ImportDeclaration) { ImportDeclaration importDecl = (ImportDeclaration) item; switch (importDecl.getType()) { case ImportFrom: { String module = importDecl.getModuleSpecifier(); ImportEntriesForModule(importDecl.getImportClause(), module, entries); break; } case ImportModule: /* empty */ break; default: throw new AssertionError(); } } } return entries; } /** * 15.2.2.4 Static Semantics: ImportEntriesForModule * * @param node * the import clause node * @param module * the module name * @param entries * the list of import entries */ private static void ImportEntriesForModule(ImportClause node, String module, List<ImportEntry> entries) { BindingIdentifier defaultEntry = node.getDefaultEntry(); if (defaultEntry != null) { String localName = defaultEntry.getName().getIdentifier(); entries.add(new ImportEntry(defaultEntry, module, "default", localName)); } BindingIdentifier nameSpace = node.getNameSpace(); if (nameSpace != null) { String localName = nameSpace.getName().getIdentifier(); entries.add(new ImportEntry(nameSpace, module, "*", localName)); } for (ImportSpecifier specifier : node.getNamedImports()) { String importName = specifier.getImportName(); String localName = specifier.getLocalName().getName().getIdentifier(); entries.add(new ImportEntry(specifier, module, importName, localName)); } } /** * 15.2.1.9 Static Semantics: ImportedLocalNames ( importEntries ) * * @param importEntries * the list of import entry records * @return the list of local names */ public static Map<String, ImportEntry> ImportedLocalNames(List<ImportEntry> importEntries) { HashMap<String, ImportEntry> localNames = new HashMap<>(); for (ImportEntry importEntry : importEntries) { localNames.put(importEntry.getLocalName(), importEntry); } return localNames; } /** * 15.2.1.10 Static Semantics: ModuleRequests<br> * 15.2.2.5 Static Semantics: ModuleRequests<br> * 15.2.3.9 Static Semantics: ModuleRequests * * @param node * the module node * @return the ordered set of module requests */ public static Set<String> ModuleRequests(Module node) { LinkedHashSet<String> requests = new LinkedHashSet<>(); for (ModuleItem item : node.getStatements()) { String moduleSpecifier; if (item instanceof ExportDeclaration) { ExportDeclaration export = (ExportDeclaration) item; switch (export.getType()) { case All: case External: moduleSpecifier = export.getModuleSpecifier(); break; case Local: case Variable: case Declaration: case DefaultHoistableDeclaration: case DefaultClassDeclaration: case DefaultExpression: continue; default: throw new AssertionError(); } } else if (item instanceof ImportDeclaration) { moduleSpecifier = ((ImportDeclaration) item).getModuleSpecifier(); } else { continue; } assert moduleSpecifier != null; requests.add(moduleSpecifier); } return requests; } /** * 15.2.1.11 Static Semantics: LexicallyDeclaredNames * * @param node * the module node * @return the set of lexically declared names */ public static Set<Name> LexicallyDeclaredNames(Module node) { return node.getScope().lexicallyDeclaredNames(); } /** * 15.2.1.12 Static Semantics: LexicallyScopedDeclarations * * @param node * the module node * @return the list of lexically scoped declarations */ public static List<Declaration> LexicallyScopedDeclarations(Module node) { return node.getScope().lexicallyScopedDeclarations(); } /** * 15.2.1.13 Static Semantics: VarDeclaredNames * * @param node * the module node * @return the set of variable declared names */ public static Set<Name> VarDeclaredNames(Module node) { return node.getScope().varDeclaredNames(); } /** * 15.2.1.14 Static Semantics: VarScopedDeclarations * * @param node * the module node * @return the list of variable scoped declarations */ public static List<StatementListItem> VarScopedDeclarations(Module node) { return node.getScope().varScopedDeclarations(); } /** * 12.2.5.6 Static Semantics: PropName<br> * 14.3.6 Static Semantics: PropName * * @param node * the property definition * @return the property name string */ public static String PropName(PropertyDefinition node) { return node.getPropertyName().getName(); } /** * 12.2.5.6 Static Semantics: PropName * * @param node * the property name node * @return the property name string */ public static String PropName(PropertyName node) { return node.getName(); } /** * 14.3.8 Static Semantics: SpecialMethod * * @param node * the method node * @return {@code true} if <var>node</var> is not a simple function */ public static boolean SpecialMethod(MethodDefinition node) { switch (node.getType()) { case AsyncFunction: case AsyncGenerator: case ConstructorGenerator: case Generator: case Getter: case Setter: return true; case BaseConstructor: case DerivedConstructor: case CallConstructor: case Function: return false; default: throw new AssertionError(); } } /** * Returns {@code true} if any method definition of {@code node} has a decorator. * * @param node * the object literal * @return {@code true} if a decorator was found */ public static boolean HasDecorators(ObjectLiteral node) { for (PropertyDefinition property : node.getProperties()) { if (!(property instanceof MethodDefinition)) { continue; } if (!((MethodDefinition) property).getDecorators().isEmpty()) { return true; } } return false; } /** * Returns {@code true} if any method definition of {@code node} has a decorator. * * @param node * the class definition * @return {@code true} if a decorator was found */ public static boolean HasDecorators(ClassDefinition node) { for (PropertyDefinition property : node.getProperties()) { if (property instanceof MethodDefinition && !((MethodDefinition) property).getDecorators().isEmpty()) { return true; } } return false; } /** * 12.2.8.1 Static Semantics: TemplateStrings * * @param node * the template literal * @return the list of template literal strings */ public static List<TemplateCharacters> TemplateStrings(TemplateLiteral node) { List<Expression> elements = node.getElements(); assert (elements.size() & 1) == 1; int numChars = ((elements.size() / 2) + 1); ArrayList<TemplateCharacters> strings = new ArrayList<>(numChars); for (int i = 0, size = elements.size(); i < size; ++i) { if ((i & 1) == 1) { assert !(elements.get(i) instanceof TemplateCharacters); continue; } strings.add((TemplateCharacters) elements.get(i)); } return strings; } /** * Static Semantics: Substitutions (not in spec) * * @param node * the template literal * @return the list of template literal substitutions */ public static List<Expression> Substitutions(TemplateLiteral node) { List<Expression> elements = node.getElements(); assert (elements.size() & 1) == 1; int numSubst = (elements.size() / 2); ArrayList<Expression> substitutions = new ArrayList<>(numSubst); for (int i = 0, size = elements.size(); i < size; ++i) { if ((i & 1) == 0) { assert (elements.get(i) instanceof TemplateCharacters); continue; } substitutions.add(elements.get(i)); } return substitutions; } /** * Static Semantics: TailCallNodes (not in spec) * <p> * 14.6 Tail Position Calls * <ul> * <li>14.6.1 Static Semantics: IsInTailPosition(nonterminal) * <li>14.6.2 Static Semantics: HasProductionInTailPosition * </ul> * * @param expr * the return expression * @return the set of tail call nodes */ public static Set<Expression> TailCallNodes(Expression expr) { while (expr instanceof CommaExpression) { expr = last(((CommaExpression) expr).getOperands()); } if (IsTailCallExpression(expr)) { return singleton(expr); } if (expr instanceof ConditionalExpression || IsLogicalExpression(expr)) { HashSet<Expression> tail = new HashSet<>(8); for (ArrayDeque<Expression> queue = new ArrayDeque<>(singleton(expr)); !queue.isEmpty();) { Expression e = queue.remove(); while (e instanceof CommaExpression) { e = last(((CommaExpression) e).getOperands()); } if (IsTailCallExpression(e)) { tail.add(e); } else if (e instanceof ConditionalExpression) { queue.add(((ConditionalExpression) e).getThen()); queue.add(((ConditionalExpression) e).getOtherwise()); } else if (IsLogicalExpression(e)) { queue.add(((BinaryExpression) e).getRight()); } } return tail; } return emptySet(); } private static boolean IsLogicalExpression(Expression expr) { if (expr instanceof BinaryExpression) { BinaryExpression.Operator op = ((BinaryExpression) expr).getOperator(); return op == BinaryExpression.Operator.AND || op == BinaryExpression.Operator.OR; } return false; } private static boolean IsTailCallExpression(Expression expr) { return expr instanceof CallExpression || expr instanceof TemplateCallExpression; } private static <T> T last(List<T> list) { assert !list.isEmpty(); return list.get(list.size() - 1); } }