1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package jdk.nashorn.internal.parser;
  26 
  27 import java.util.HashMap;
  28 import java.util.HashSet;
  29 import java.util.List;
  30 import java.util.Map;
  31 import jdk.nashorn.internal.codegen.Namespace;
  32 import jdk.nashorn.internal.ir.Expression;
  33 import jdk.nashorn.internal.ir.FunctionNode;
  34 import jdk.nashorn.internal.ir.IdentNode;
  35 import jdk.nashorn.internal.ir.Module;
  36 
  37 /**
  38  * ParserContextNode that represents a function that is currently being parsed
  39  */
  40 class ParserContextFunctionNode extends ParserContextBaseNode {
  41 
  42     /** Function name */
  43     private final String name;
  44 
  45     /** Function identifier node */
  46     private final IdentNode ident;
  47 
  48     /** Name space for function */
  49     private final Namespace namespace;
  50 
  51     /** Line number for function declaration */
  52     private final int line;
  53 
  54     /** Function node kind, see {@link FunctionNode.Kind} */
  55     private final FunctionNode.Kind kind;
  56 
  57     /** List of parameter identifiers for function */
  58     private List<IdentNode> parameters;
  59 
  60     /** Token for function start */
  61     private final long token;
  62 
  63     /** Last function token */
  64     private long lastToken;
  65 
  66     /** Opaque node for parser end state, see {@link Parser} */
  67     private Object endParserState;
  68 
  69     private HashSet<String> parameterBoundNames;
  70     private IdentNode duplicateParameterBinding;
  71     private boolean simpleParameterList = true;
  72 
  73     private Module module;
  74 
  75     private int debugFlags;
  76     private Map<IdentNode, Expression> parameterExpressions;
  77 
  78     /**
  79      * @param token The token for the function
  80      * @param ident External function name
  81      * @param name  Internal name of the function
  82      * @param namespace Function's namespace
  83      * @param line  The source line of the function
  84      * @param kind  Function kind
  85      * @param parameters The parameters of the function
  86      */
  87     public ParserContextFunctionNode(final long token, final IdentNode ident, final String name, final Namespace namespace, final int line, final FunctionNode.Kind kind, final List<IdentNode> parameters) {
  88         this.ident      = ident;
  89         this.namespace  = namespace;
  90         this.line       = line;
  91         this.kind       = kind;
  92         this.name       = name;
  93         this.parameters = parameters;
  94         this.token      = token;
  95     }
  96 
  97     /**
  98      * @return Internal name of the function
  99      */
 100     public String getName() {
 101         return name;
 102     }
 103 
 104     /**
 105      * @return The external identifier for the function
 106      */
 107     public IdentNode getIdent() {
 108         return ident;
 109     }
 110 
 111     /**
 112      *
 113      * @return true if function is the program function
 114      */
 115     public boolean isProgram() {
 116         return getFlag(FunctionNode.IS_PROGRAM) != 0;
 117     }
 118 
 119     /**
 120      * @return if function in strict mode
 121      */
 122     public boolean isStrict() {
 123         return getFlag(FunctionNode.IS_STRICT) != 0;
 124     }
 125 
 126     /**
 127      * @return true if the function has nested evals
 128      */
 129     public boolean hasNestedEval() {
 130         return getFlag(FunctionNode.HAS_NESTED_EVAL) != 0;
 131     }
 132 
 133     /**
 134      * Returns true if any of the blocks in this function create their own scope.
 135      * @return true if any of the blocks in this function create their own scope.
 136      */
 137     public boolean hasScopeBlock() {
 138         return getFlag(FunctionNode.HAS_SCOPE_BLOCK) != 0;
 139     }
 140 
 141     /**
 142      * Create a unique name in the namespace of this FunctionNode
 143      * @param base prefix for name
 144      * @return base if no collision exists, otherwise a name prefix with base
 145      */
 146     public String uniqueName(final String base) {
 147         return namespace.uniqueName(base);
 148     }
 149 
 150     /**
 151      * @return line number of the function
 152      */
 153     public int getLineNumber() {
 154         return line;
 155     }
 156 
 157     /**
 158      * @return The kind if function
 159      */
 160     public FunctionNode.Kind getKind() {
 161         return kind;
 162     }
 163 
 164     /**
 165      * Get parameters
 166      * @return The parameters of the function
 167      */
 168     public List<IdentNode> getParameters() {
 169         return parameters;
 170     }
 171 
 172     void setParameters(final List<IdentNode> parameters) {
 173         this.parameters = parameters;
 174     }
 175 
 176     /**
 177      * Return ES6 function parameter expressions
 178      *
 179      * @return ES6 function parameter expressions
 180      */
 181     public Map<IdentNode, Expression> getParameterExpressions() {
 182         return parameterExpressions;
 183     }
 184 
 185     void addParameterExpression(final IdentNode ident, final Expression node) {
 186         if (parameterExpressions == null) {
 187             parameterExpressions = new HashMap<>();
 188         }
 189         parameterExpressions.put(ident, node);
 190     }
 191 
 192     /**
 193      * Set last token
 194      * @param token New last token
 195      */
 196     public void setLastToken(final long token) {
 197         this.lastToken = token;
 198 
 199     }
 200 
 201     /**
 202      * @return lastToken Function's last token
 203      */
 204     public long getLastToken() {
 205         return lastToken;
 206     }
 207 
 208     /**
 209      * Returns the ParserState of when the parsing of this function was ended
 210      * @return endParserState The end parser state
 211      */
 212     public Object getEndParserState() {
 213         return endParserState;
 214     }
 215 
 216     /**
 217      * Sets the ParserState of when the parsing of this function was ended
 218      * @param endParserState The end parser state
 219      */
 220     public void setEndParserState(final Object endParserState) {
 221         this.endParserState = endParserState;
 222     }
 223 
 224     /**
 225      * Returns the if of this function
 226      * @return The function id
 227      */
 228     public int getId() {
 229         return isProgram() ? -1 : Token.descPosition(token);
 230     }
 231 
 232     /**
 233      * Returns the debug flags for this function.
 234      *
 235      * @return the debug flags
 236      */
 237     int getDebugFlags() {
 238         return debugFlags;
 239     }
 240 
 241     /**
 242      * Sets a debug flag for this function.
 243      *
 244      * @param debugFlag the debug flag
 245      */
 246     void setDebugFlag(final int debugFlag) {
 247         debugFlags |= debugFlag;
 248     }
 249 
 250     public boolean isMethod() {
 251         return getFlag(FunctionNode.ES6_IS_METHOD) != 0;
 252     }
 253 
 254     public boolean isClassConstructor() {
 255         return getFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR) != 0;
 256     }
 257 
 258     public boolean isSubclassConstructor() {
 259         return getFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR) != 0;
 260     }
 261 
 262     boolean addParameterBinding(final IdentNode bindingIdentifier) {
 263         if (Parser.isArguments(bindingIdentifier)) {
 264             setFlag(FunctionNode.DEFINES_ARGUMENTS);
 265         }
 266 
 267         if (parameterBoundNames == null) {
 268             parameterBoundNames = new HashSet<>();
 269         }
 270         if (parameterBoundNames.add(bindingIdentifier.getName())) {
 271             return true;
 272         } else {
 273             duplicateParameterBinding = bindingIdentifier;
 274             return false;
 275         }
 276     }
 277 
 278     public IdentNode getDuplicateParameterBinding() {
 279         return duplicateParameterBinding;
 280     }
 281 
 282     public boolean isSimpleParameterList() {
 283         return simpleParameterList;
 284     }
 285 
 286     public void setSimpleParameterList(final boolean simpleParameterList) {
 287         this.simpleParameterList = simpleParameterList;
 288     }
 289 
 290     public Module getModule() {
 291         return module;
 292     }
 293 
 294     public void setModule(final Module module) {
 295         this.module = module;
 296     }
 297 }