Search code examples
javascriptlanguage-lawyer

In the ECMAScript spec, what are the semantic rules of VarScopedDeclarations and VarDeclaredNames of a non-empty block statement?


I'm studying the ECMAScript spec to find out what the expected behavior of vars statements inside a block is according to the spec:

function test() {
    console.log('before block', bar);
    {
      console.log('in block before declaration', bar);
      var bar = 30;
      console.log('in block after declaration', bar); 
    }
    console.log('after block', bar);
}

test();

I know that var is not block-scoped. But I'm curious about how the spec uses concrete definitions of steps to achieve it.

I've read the semantics of the DeclarationInstantiation of function and global. They take static semantics VarDeclaredNames and VarScopedDeclarations of function body or script to create bindings to the environment record. But I can't find the definition in these static semantics of how to deal with the block statement with the nested StatementList. The spec only defined the production for empty block (without any statement):

VarDeclaredNames in spec

Or should Block: { StatementList } be seen as a StatementList directly?

enter image description here

But in 14.2 it is defined as a single statement?

I found other semantics include instructions for the production Block { statementList }, so I expect to see something like:

Block: { StatementList }
  1. Return VarDeclaredNames of StatementList.

Here's the example defined instructions of production Block { statementList } in evaluation operation: block statement syntax example


Solution

  • I expect to see something like:

    Block: { StatementList }
      1. Return VarDeclaredNames of StatementList.
    

    Your expectation is well-founded, but it would be rather boring and arduous to define VarDeclaredNames for every single syntactic element, doing nothing other than recursing into its descendant element.

    So the spec authors decided to only provide an implicit definition for these Syntax-Directed Operations:

    Unless explicitly specified otherwise, all chain productions have an implicit definition for every operation that might be applied to that production's left-hand side nonterminal. The implicit definition simply reapplies the same operation with the same parameters, if any, to the chain production's sole right-hand side nonterminal and then returns the result.

    See also the example following that paragraph.