puntos - ¿Cómo implementar la inserción automática de punto y coma de JavaScript en JavaCC?
punto y coma en javascript (1)
Estoy terminando mi gramática ECMAScript 5.1 / JavaScript para JavaCC . He hecho todos los tokens y producciones de acuerdo con la especificación.
Ahora me estoy enfrentando a una gran pregunta que no sé cómo resolver.
JavaScript tiene esta bonita característica de la inserción automática de punto y coma:
¿Cuáles son las reglas para la inserción automática de punto y coma de JavaScript (ASI)?
Para citar las especificaciones , las reglas son:
Hay tres reglas básicas de inserción de punto y coma:
Cuando, como el programa se analiza de izquierda a derecha, se encuentra un token (llamado token ofensor) que no está permitido por ninguna producción de la gramática, luego se inserta automáticamente un punto y coma antes del token ofensor si uno o más de los siguientes las condiciones son verdaderas:
- El token ofensor está separado del token anterior por al menos un LineTerminator.
- La ficha ofensiva es
}
.Cuando, como el programa se analiza de izquierda a derecha, se encuentra el final de la secuencia de entrada de tokens y el analizador no puede analizar la secuencia de token de entrada como un único programa ECMAScript completo, luego se inserta automáticamente un punto y coma al final de la corriente de entrada.
Cuando, como el programa se analiza de izquierda a derecha, se encuentra un token que está permitido por alguna producción de la gramática, pero la producción es una producción restringida y el token sería el primer token para un terminal o no terminal inmediatamente después de la anotación
[no LineTerminator here]
dentro de la producción restringida (y, por lo tanto, dicho token se llama token restringido), y el token restringido está separado del token anterior por al menos unLineTerminator
, luego se inserta un punto y coma antes del token restringido.Sin embargo, existe una condición anuladora adicional en las reglas anteriores: un punto y coma nunca se inserta automáticamente si el punto y coma se analiza como una declaración vacía o si ese punto y coma se convertiría en uno de los dos puntos y coma en el encabezado de una instrucción for (ver 12.6.3 ).
¿Cómo podría implementar esto con JavaCC?
La conclusión de una respuesta que he encontrado hasta ahora es esta gramática de Dojo toolkit que tiene una parte insertSemiColon
llamada insertSemiColon
dedicada a la tarea. Pero no veo que este método se llame en ninguna parte (ni en la gramática ni en todo el código jslinker ).
¿Cómo podría abordar este problema con JavaCC?
Ver también esta pregunta:
(No hay respuesta allí)
Una pregunta de los comentarios:
¿Es correcto decir que los puntos y comas solo deben insertarse donde los puntos y coma están sintácticamente permitidos?
Creo que sería correcto decir que los puntos y comas solo deben insertarse donde se requieren sintácticamente los puntos y coma.
La parte relevante aquí es §7.9:
7.9 Inserción Automática de Semicolon
Ciertas declaraciones de ECMAScript (instrucción vacía, declaración de variable, declaración de expresión, declaración de hacer, declaración de continuación, declaración de interrupción, declaración de devolución y declaración de lanzamiento) deben terminarse con punto y coma. Tales puntos y comas siempre pueden aparecer de forma explícita en el texto fuente. Por conveniencia, sin embargo, tales puntos y comas pueden omitirse del texto fuente en ciertas situaciones. Estas situaciones se describen diciendo que los puntos y comas se insertan automáticamente en la secuencia de token del código fuente en esas situaciones.
Tomemos la declaración de return
, por ejemplo:
ReturnStatement :
return ;
return [no LineTerminator here] Expression ;
Entonces, desde mi punto de vista, sintácticamente se requiere el punto y coma, no solo permitido (como en su pregunta).
Las 3 reglas para la inserción de punto y coma se pueden encontrar en la sección 7.9.1 del estándar ECMAScript 5.1
Creo que las reglas 1 y 2 del estándar se pueden manejar con un análisis semántico anticipado.
void PossiblyInsertedSemicolon()
{}
{
LOOKAHEAD( {semicolonNeedsInserting()} ) {}
|
";"
}
Entonces, ¿cuándo es necesario insertar un punto y coma? Cuando uno de estos es verdadero
- Cuando el siguiente token no es un punto y coma y está en otra línea (
getToken(1).kind != SEMICOLON && getToken(0).endLine < getToken(1).beginLine
) - Cuando el siguiente token es un corsé derecho.
- Cuando el siguiente token es EOF
Así que necesitamos
boolean semicolonNeedsInserting() {
return (`getToken(1).kind != SEMICOLON && getToken(0).endLine < getToken(1).beginLine`)
|| getToken(1).kind == RBRACE
|| getToken(1).kind == EOF ;
}
Eso se ocupa de las reglas 1 y 2 del estándar.
Para la regla 3 (producciones restringidas), como mencioné en mi respuesta a esta pregunta , podrías hacer lo siguiente
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()
}