5252import com .oracle .js .parser .ir .IdentNode ;
5353import com .oracle .js .parser .ir .Module ;
5454import com .oracle .js .parser .ir .ParameterNode ;
55+ import com .oracle .js .parser .ir .Scope ;
56+ import com .oracle .js .parser .ir .Symbol ;
5557import com .oracle .js .parser .ir .VarNode ;
5658
5759/**
@@ -71,13 +73,14 @@ class ParserContextFunctionNode extends ParserContextBaseNode {
7173 /** Line number for function declaration */
7274 private final int line ;
7375
74- /** Function node kind, see FunctionNode.Kind */
75- private final FunctionNode .Kind kind ;
76+ private final Scope parentScope ;
7677
7778 /** List of parameter identifiers (for simple and rest parameters). */
7879 private List <IdentNode > parameters ;
7980 /** Optional parameter initialization block (replaces parameter list). */
8081 private ParserContextBlockNode parameterBlock ;
82+ /** Function body block. */
83+ private ParserContextBlockNode bodyBlock ;
8184
8285 /** Token for function start */
8386 private final long token ;
@@ -103,19 +106,20 @@ class ParserContextFunctionNode extends ParserContextBaseNode {
103106 * @param name Internal name of the function
104107 * @param namespace Function's namespace
105108 * @param line The source line of the function
106- * @param kind Function kind
107109 * @param parameters The parameters of the function
110+ * @param parentScope The parent scope
108111 */
109- ParserContextFunctionNode (final long token , final IdentNode ident , final String name , final Namespace namespace , final int line , final FunctionNode .Kind kind ,
110- final List <IdentNode > parameters , final int length ) {
112+ ParserContextFunctionNode (final long token , final IdentNode ident , final String name , final Namespace namespace , final int line , final int flags ,
113+ final List <IdentNode > parameters , final int length , Scope parentScope ) {
114+ super (flags );
111115 this .ident = ident ;
112116 this .namespace = namespace ;
113117 this .line = line ;
114- this .kind = kind ;
115118 this .name = name ;
116119 this .parameters = parameters ;
117120 this .token = token ;
118121 this .length = length ;
122+ this .parentScope = parentScope ;
119123 this .parameterCount = parameters == null ? 0 : parameters .size ();
120124 assert calculateLength (parameters ) == length ;
121125 }
@@ -182,13 +186,6 @@ public int getLineNumber() {
182186 return line ;
183187 }
184188
185- /**
186- * @return The kind if function
187- */
188- public FunctionNode .Kind getKind () {
189- return kind ;
190- }
191-
192189 /**
193190 * Get parameters
194191 *
@@ -316,6 +313,7 @@ private boolean addParameterBinding(IdentNode bindingIdentifier) {
316313 parameterBoundNames = new HashSet <>();
317314 }
318315 if (parameterBoundNames .add (bindingIdentifier .getName ())) {
316+ declareParameter (bindingIdentifier .getName ());
319317 return true ;
320318 } else {
321319 duplicateParameterBinding = bindingIdentifier ;
@@ -343,6 +341,18 @@ public boolean isAsync() {
343341 return getFlag (FunctionNode .IS_ASYNC ) != 0 ;
344342 }
345343
344+ public boolean isArrow () {
345+ return getFlag (FunctionNode .IS_ARROW ) != 0 ;
346+ }
347+
348+ public boolean isGenerator () {
349+ return getFlag (FunctionNode .IS_GENERATOR ) != 0 ;
350+ }
351+
352+ public boolean isScriptOrModule () {
353+ return getFlag (FunctionNode .IS_SCRIPT | FunctionNode .IS_MODULE ) != 0 ;
354+ }
355+
346356 public ParserContextBlockNode getParameterBlock () {
347357 return parameterBlock ;
348358 }
@@ -373,7 +383,8 @@ private void ensureParameterBlock() {
373383 }
374384
375385 private void initParameterBlock () {
376- parameterBlock = new ParserContextBlockNode (token );
386+ assert bodyBlock == null ; // parameter block must be created before body block
387+ parameterBlock = new ParserContextBlockNode (token , Scope .createParameter (parentScope ));
377388 parameterBlock .setFlag (Block .IS_PARAMETER_BLOCK );
378389
379390 if (parameters != null ) {
@@ -395,6 +406,37 @@ private void addParameterInit(IdentNode param, int index) {
395406 paramValue = new ParameterNode (paramToken , paramFinish , index );
396407 }
397408 parameterBlock .appendStatement (new VarNode (line , Token .recast (paramToken , TokenType .LET ), paramFinish , param , paramValue , VarNode .IS_LET ));
409+ declareParameter (param .getName ());
410+ }
411+
412+ private void declareParameter (String parameterName ) {
413+ if (parameterBlock != null ) {
414+ // Parameters have a temporal dead zone (unless the parameter list is simple).
415+ parameterBlock .getScope ().putSymbol (new Symbol (parameterName , Symbol .IS_LET | Symbol .IS_PARAM ));
416+ }
417+ }
418+
419+ private void finalizeParameters () {
420+ if (parameterBlock == null ) {
421+ if (parameters != null ) {
422+ for (int i = 0 ; i < parameters .size (); i ++) {
423+ IdentNode parameter = parameters .get (i );
424+ bodyBlock .getScope ().putSymbol (new Symbol (parameter .getName (), Symbol .IS_VAR | Symbol .IS_PARAM ));
425+ }
426+ }
427+ } else {
428+ parameterBlock .getScope ().close ();
429+ }
430+ }
431+
432+ public ParserContextBlockNode getBodyBlock () {
433+ return bodyBlock ;
434+ }
435+
436+ public void setBodyBlock (ParserContextBlockNode bodyBlock ) {
437+ assert this .bodyBlock == null ;
438+ this .bodyBlock = bodyBlock ;
439+ finalizeParameters ();
398440 }
399441
400442 private static int calculateLength (final List <IdentNode > parameters ) {
0 commit comments