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;
Referencesmostra referências cruzadas
Convenções notacionais
Leia 5.1.5 Grammar Notation.
Recursão
Listas aparecem assim na gramática:
ArgumentList :
AssignmentExpression
ArgumentList , AssignmentExpressionsignifica:
a, b = 1, c = 2
^_____________^ ArgumentList
^__________^ ArgumentList, AssignmentExpression,
^___^ AssignmentExpressionOpcionalidade
Sufixo _opt_: produto opcional.
VariableDeclaration :
BindingIdentifier Initializer_optsignifica:
var binding_identifier;
var binding_identifier = Initializer;
______________ Initializer_optParâ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:
<script src="javascript.js"></script>Módulo é estrito por padrão.
<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:
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:
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.