Comment implémenter l'insertion automatique de point-virgules JavaScript dans JavaCC?

Je termine ma grammaire ECMAScript 5.1 / JavaScript pour JavaCC . J'ai fait tous les tokens et productions selon les spécifications.

Maintenant, je suis confronté à une grande question que je ne sais pas comment résoudre.

JavaScript a cette belle caractéristique de l'insertion automatique du point-virgule:

Quelles sont les règles pour l'insertion automatique de point-virgule (ASI) de JavaScript?

Pour citer les spécifications , les règles sont les suivantes:

Il existe trois règles de base de l'insertion de point-virgule:

  1. Lorsque, à mesure que le programme est analysé de gauche à droite, un jeton (appelé le jeton offensant) est détecté qui n'est autorisé par aucune production de la grammaire, puis un point-virgule est automatiquement inséré avant le jeton offensant si un ou plusieurs des éléments suivants Les conditions sont vraies:

    • Le jeton offensant est séparé du jeton précédent par au moins un LineTerminator.
    • Le jeton offensant est } .
  2. Lorsque, au fur et à mesure que le programme est analysé de gauche à droite, la fin du flux d'entrée des jetons est rencontrée et l'analyseur est incapable d'analyser le flux de jeton d'entrée en tant que programme ECMAScript complet unique, puis un point-virgule est automatiquement inséré à la fin de Le flux d'entrée.

  3. Lorsque, à mesure que le programme est analysé de gauche à droite, on trouve un jeton autorisé par une certaine production de la grammaire, mais la production est une production restreinte et le jeton serait le premier jeton pour un terminal ou un non terminal immédiatement après l'annotation [no LineTerminator here] dans la production restreinte (et donc un tel jeton s'appelle un jeton restreint), et le jeton restreint est séparé du jeton précédent par au moins un LineTerminator , puis un point-virgule est automatiquement inséré avant le jeton restreint.

Cependant, il existe une condition de substitution supplémentaire sur les règles précédentes: un point-virgule n'est jamais inséré automatiquement si le point-virgule serait ensuite analysé comme une instruction vide ou si ce point-virgule deviendrait l'un des deux points-virgules dans l'en-tête d'une déclaration for (voir 12.6.3 ).

Comment puis-je implémenter cela avec JavaCC?

La chose ferme à une réponse que j'ai trouvée jusqu'à présent est cette grammaire de Dojo toolkit qui possède une partie insertSemiColon appelée insertSemiColon dédiée à la tâche. Mais je ne vois pas que cette méthode s'appelle n'importe où (ni dans la grammaire ni dans l'ensemble du code jslinker ).

Comment puis-je aborder ce problème avec JavaCC?

Voir aussi cette question:

Javascript grammaire et insertion automatique de semocolon

(Pas de réponse là-bas.)

Une question des commentaires:

Est-il correct de dire que les points-virgules ne doivent être insérés que si les points-virgules sont syntaxiquement autorisés?

Je pense qu'il serait correct de dire que les points-virgules ne doivent être insérés que si les points-virgules sont syntaxiquement requis .

La partie pertinente ici est §7.9:

7.9 Insertion automatique du point-virgule

Certaines instructions ECMAScript (instruction vide, instruction de variable, déclaration d'expression, déclaration de do-while, instruction de continuité, déclaration de rupture, instruction de retour et instruction de lancement) doivent être terminées avec des points-virgules. Ces points-virgules peuvent toujours apparaître explicitement dans le texte source. Pour plus de commodité, cependant, ces points-virgules peuvent être omises du texte source dans certaines situations. Ces situations sont décrites en disant que les points-virgules sont automatiquement insérés dans le flux de jetons de code source dans ces situations.

Prenons l'énoncé de return par exemple:

 ReturnStatement : return ; return [no LineTerminator here] Expression ; 

Donc (de ma compréhension) syntaxiquement, le point-virgule est requis , non seulement autorisé (comme dans votre question).

Les 3 règles pour l'insertion de point-virgule se trouvent dans la section 7.9.1 de la norme ECMAScript 5.1

Je pense que les règles 1 et 2 de la norme peuvent être manipulées avec un aspect sémantique.

 void PossiblyInsertedSemicolon() {} { LOOKAHEAD( {semicolonNeedsInserting()} ) {} | ";" } 

Alors, quand faut-il insérer un point-virgule? Quand l'un d'eux est vrai

  • Lorsque le jeton suivant n'est pas un point-virgule et se trouve sur une autre ligne ( getToken(1).kind != SEMICOLON && getToken(0).endLine < getToken(1).beginLine )
  • Lorsque le jeton suivant est une orthèse droite.
  • Lorsque le jeton suivant est EOF

Nous avons donc besoin

 boolean semicolonNeedsInserting() { return (`getToken(1).kind != SEMICOLON && getToken(0).endLine < getToken(1).beginLine`) || getToken(1).kind == RBRACE || getToken(1).kind == EOF ; } 

Cela prend en charge les règles 1 et 2 de la norme.

Pour la règle 3 (productions restreintes), comme mentionné dans ma réponse à cette question , vous pouvez faire ce qui suit

 void returnStatement() {} { "return" [ // Parse an expression unless either the next token is a ";", "}" or EOF, or the next token is on another line. LOOKAHEAD( { getToken(1).kind != SEMICOLON && getToken(1).kind != RBRACE && getToken(1).kind != EOF && getToken(0).endLine == getToken(1).beginLine} ) Expression() ] PossiblyInsertedSemicolon() }