Skip to content

Especificação

A especificação da linguagem ECMAScript® (standard vivo) descreve tudo sobre JavaScript, para qualquer um poder implementar um motor próprio.

Capítulos importantes para o nosso parser:

  • Capítulo 5: convenções notacionais
  • Capítulo 11: texto-fonte ECMAScript
  • Capítulo 12: léxico
  • Capítulos 13–16: expressões, declarações, funções, classes, scripts e módulos
  • Anexo B: recursos extras para navegadores
  • Anexo C: modo estrito ECMAScript

Navegar na especificação:

  • Itens clicáveis têm link permanente (âncoras na URL), ex.: #sec-identifiers
  • Passe o mouse para dicas; References mostra referências cruzadas

Convenções notacionais

Leia 5.1.5 Grammar Notation.

Recursão

Listas aparecem assim na gramática:

ArgumentList :
  AssignmentExpression
  ArgumentList , AssignmentExpression

significa:

javascript
a, b = 1, c = 2
^_____________^ ArgumentList
   ^__________^ ArgumentList, AssignmentExpression,
          ^___^ AssignmentExpression

Opcionalidade

Sufixo _opt_: produto opcional.

VariableDeclaration :
  BindingIdentifier Initializer_opt

significa:

javascript
var binding_identifier;
var binding_identifier = Initializer;
                       ______________ Initializer_opt

Parâmetros gramaticais

[Return], [In] etc.

ScriptBody :
    StatementList[~Yield, ~Await, ~Return]

Topo de script não pode yield, await nem return em certos pontos…

Mas:

ModuleItem :
  ImportDeclaration
  ExportDeclaration
  StatementListItem[~Yield, +Await, ~Return]

permite top-level await.

Texto-fonte

11.2 Types of Source Code: diferença enorme entre script e módulo; use strict desativa comportamentos velhos indesejáveis.

Script não é estrito até colocar use strict no topo.

No HTML:

html
<script src="javascript.js"></script>

Módulo é estrito por padrão.

html
<script type="module" src="main.mjs"></script>

Léxico ECMAScript

Mais fundo no blog da V8: Understanding the ECMAScript spec.

Automatic Semicolon Insertion

Regras em que você pode omitir ;. Em essência:

rust
    pub fn asi(&mut self) -> Result<()> {
        if self.eat(Kind::Semicolon) || self.can_insert_semicolon() {
            return Ok(());
        }
        let range = self.prev_node_end..self.cur_token().start;
        Err(SyntaxError::AutoSemicolonInsertion(range.into()))
    }

    pub const fn can_insert_semicolon(&self) -> bool {
        self.cur_token().is_on_new_line || matches!(self.cur_kind(), Kind::RCurly | Kind::Eof)
    }

Chame asi manualmente onde o fim de declaração exige semicolon opcional:

rust
fn parse_debugger_statement(&mut self) -> Result<Statement<'a>> {
    let node = self.start_node();
    self.expect(Kind::Debugger)?;
    self.asi()?; 
    self.ast.debugger_statement(self.finish_node(node))
}

INFO

A ASI presume análise da esquerda para a direita — torna outros modelos pouco viáveis. O autor do jsparagus reclama em automatic-semicolon-insertion:

… o único trecho onde a especificação insinua detalhes de implementação sobre como o texto é interpretado…

Expressões, declarações, funções…

Dominar essa sintaxe cobra tempo; só então vai para o código do parser.