0

My question is with regards to the ECMAScript specification.

I am currently following the specification to understand how a simple script is evaluated from start to end.

Following on from this question and answer, I am walking through the GlobalDeclarationInstantiation to see how a FunctionDeclaration gets instantiated (identifier added to the Global Environment Record (GER)) and initialized (value added to the identifier in the GER).

That leads me to step 5 of GlobalDeclarationInstantiation: Let varDeclarations be the VarScopedDeclarations of script..

Looking at VarScopedDeclarations, it seems to me that it never returns a Parse Node for FunctionDeclaration. In fact, it returns empty Lists for all syntactic grammar symbols, except for VarDeclarations. Which means that it only returns Parse Nodes for symbols following the var keyword. VarScopedDeclarations of var a = 5 would return a Parse Node containing a = 5.

Questions

  1. Does VarScopedDeclarations ever return a Parse Node for FunctionDeclaration?
  2. If it does not, will step 8.1.i (i. Assert: d is either a FunctionDeclaration...) ever be a positive assertion?
  3. If VarScopedDeclarations returns empty lists for most symbols, why have the spec creators bothered including them? Would it not be cleaner to only include the ones that actually return a Parse Node entry? It is the same in LexicallyScopedDeclarations and a few other operations.
Magnus
  • 6,791
  • 8
  • 53
  • 84
  • Oh they changed this, [previously (ES6) it was spread out all over the spec](https://stackoverflow.com/a/40623284/1048572)… Nice! – Bergi Dec 12 '22 at 15:02

1 Answers1

2

Looking at VarScopedDeclarations, it seems to me that it never returns a Parse Node for FunctionDeclaration. In fact, it returns empty Lists for all syntactic grammar symbols, except for VarDeclarations.

I think you missed a few bits there:

FunctionStatementList : StatementList
  1. Return the TopLevelVarScopedDeclarations of StatementList.

ClassStaticBlockStatementList : StatementList
  1. Return the TopLevelVarScopedDeclarations of StatementList.

ScriptBody : StatementList
  1. Return TopLevelVarScopedDeclarations of StatementList.

And then TopLevelVarScopedDeclarations does indeed return what you expected, the function declarations that should be hoisted:

StatementListItem : Declaration
  1. If Declaration is Declaration : HoistableDeclaration , then
    a. Let declaration be DeclarationPart of HoistableDeclaration.
    b. Return « declaration ».
  2. Return a new empty List.

LabelledItem : FunctionDeclaration
  1. Return « FunctionDeclaration ».

(where a HoistableDeclaration is any of FunctionDeclaration, GeneratorDeclaration, AsyncFunctionDeclaration, AsyncGeneratorDeclaration)


You may have been confused by VarScopedDeclarations' rule

StatementListItem : Declaration
  1. Return a new empty List.

Yes, this does return no function declarations, but this rule applies only to StatementListItems inside a Block or CaseBlock. VarScopedDeclarations does recurse into blocks, but only to find VariableDeclarations in there, not to find function declarations - they do not hoist out of blocks.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks! On your last point: I might be reading the grammar wrong, but it seems to me that *StatementListItem* can occur inside *StatementList* (clause 14.2 Block), and *StatementList* can occur in a wide range of different places (not just within a *Block*). As such, how are you able to conclude that the *StatementListItem* mentioned in * VarScopedDeclarations* is referring to a *StatementListItem* within a *Block*? – Magnus Dec 12 '22 at 16:43
  • 1
    @Magnus Ah, good call, I jumped to the conclusion too early. But it's actually not that a wide range of different places - there's only *Block*, *CaseBlock*, *FunctionStatementList*, *ClassStaticBlockStatementList* and *ScriptBody*. And the last three explicitly delegate to `TopLevelVarScopedDeclarations` which doesn't recurse. Tbh, I think the recursion would be cleaner (and easier to understand) if the respective `…DeclarationInstantiation` algorithms would directly call `TopLevelVarScopedDeclarations`, which then would delegate to a recursive `InnerVarScopedDeclarations` operation. – Bergi Dec 12 '22 at 17:22
  • Indeed, @Bergi. Is this a conflict in *VarScopedDeclarations*: *StatementListItem* can occur in *StatementList*, which can occur in *FunctionStatementList*. Thus, a *Declaration* (eg *FunctionDeclaration*) in a *FunctionStatementList* should return an empty list. However, further down in *VarScopedDeclarations* it says: `FunctionStatementList : StatementList -> Return "FunctionDeclaration"` (through *TopLevelVarScopedDeclarations*). Any idea what I am missing? – Magnus Dec 12 '22 at 18:05
  • 1
    "*Thus, a* Declaration *in a* FunctionStatementList *should return an empty list*" - only if you were to call `VarScopedDeclarations` directly on the *StatementList* of the function. But that doesn't happen, `VarScopedDeclarations` is called on the *FunctionStatementList*, and the rule for that makes it return the declarations (via `TopLevelVarScopedDeclarations`). – Bergi Dec 12 '22 at 18:09
  • Not sure if you got a notification, but I made a room with a couple of follow-up questions, if/when you have time. Perhaps valuable for others too. Link: https://chat.stackoverflow.com/rooms/250378/room-for-magnus-and-bergi – Magnus Dec 13 '22 at 18:45