Pegjs: Permitir devolver el resultado de la coincidencia de una expresión específica en una regla sin una acción

Creado en 23 may. 2016  ·  10Comentarios  ·  Fuente: pegjs/pegjs

Es muy común tener que devolver un valor de uno de los no terminales en una regla o dentro de una subregla entre paréntesis. Por ejemplo:

varDecl = type:type id:ID init:( EQ e:expr {return e} )?
                { return scopedAST('VARDECL', {type, id, init}) }

En este caso, necesitaba expr etiquetado como e dentro del nivel de paréntesis init para una frase opcional en el idioma. No necesitaba la "palabra irrelevante" EQ como parte del valor devuelto.

Si el lenguaje PEGjs tuviera un símbolo para ser usado para marcar terminales como expr arriba para que ellos, y solo ellos, sean el valor devuelto por una regla gramatical o subregla, este caso sería más simple.

Para reescribir mi ejemplo anterior:

varDecl = type:type id:ID init:( EQ ^expr )?
                { return scopedAST('VARDECL', {type, id, init}) }

Tenga en cuenta el uso de ^ para marcar el expr dentro de la subregla de frase opcional entre paréntesis init para designar lo que está vinculado a init . Esto simplifica muchas situaciones con y sin la subregla entre paréntesis que se muestra en este ejemplo.

Gracias por hacer una herramienta tan maravillosamente simple, elegante y poderosa. ¡Me encantan los PEGjs! :sonrisa:

feature

Todos 10 comentarios

¡Amo esa idea! ^ es muy intuitivo.

Esto también podría funcionar en reglas no anidadas:

WhiteSpacedIdentifier = WhiteSpace? identifier:Identifier WhiteSpace {return identifier;}
// becomes
WhiteSpacedIdentifier = WhiteSpace? ^Identifier WhiteSpace?

¡Muy legible! Presumiblemente, el uso de varios ^ también funcionaría, de modo que:

a = ^b  c  ^d  e

¿Devolvería [b, d] ? Parece tener sentido.

Del mismo modo, parece tener sentido que si se mezcla con capturas con nombre, se ignoren las reglas ^ , por lo que

x = a ^b foo:c { return foo; }

Volvería solo c.

Oh, esa idea de múltiplos es excelente. La mezcla con capturas con nombre debe ser
un error.

El martes, 5 de julio de 2016, 01:07 Graham Wakefield [email protected]
escribió:

¡Muy legible! Presumiblemente, el uso de múltiples ^ también funcionaría, de modo que:

a = ^ bc ^ de

¿Volvería [b, d]? Parece tener sentido.

Del mismo modo, parece tener sentido que si se mezcla con capturas con nombre, el ^
las reglas se ignoran:

x = a ^ b foo: c {return foo; }

-
Recibes esto porque eres el autor del hilo.

Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/pegjs/pegjs/issues/427#issuecomment -230413015, o silenciar
la amenaza
https://github.com/notifications/unsubscribe/ABC26k8v0DIzuWUlkoDZGm2ep10Y5bcMks5qShDAgaJpZM4IkuA9
.

Estoy totalmente de acuerdo en que el patrón descrito es bastante común. Tener una forma de expresarlo sin una acción tiene sentido.

Lo que no estoy tan seguro acerca de la solución propuesta (el operador ^ ). Usar un carácter especial cuyo significado no es inmediatamente obvio siempre es problemático y se suma a la curva de aprendizaje. También es posible que el personaje se use mejor para algún otro propósito. Por último, pero no menos importante, no me gusta la idea de poner cosas que no influyen directamente en el análisis sintáctico en expresiones. Se puede argumentar que ya existe una instancia de esto, el operador $ , y estoy de acuerdo. Pero no estoy seguro de si la adición de $ no fue un error (pequeño). Si es así, me gustaría evitar hacerlo de nuevo.

Pensaré en esto más profundamente después de 1.0.0.

Un poco más de reflexión: dado que ^ y las expresiones etiquetadas chocan ( @grrrwaaa sugiere ignorar el ^ ), ¿qué tal si en lugar de marcar el resultado, se podrían marcar las expresiones _ignored_, por ejemplo (sugerencia de sintaxis) proporcionando una etiqueta vacía:

WhiteSpacedIdentifier = WhiteSpace? identifier:Identifier WhiteSpace {return identifier;}
// becomes
WhiteSpacedIdentifier = :WhiteSpace? Identifier :WhiteSpace?

Allí, no hay nueva sintaxis (ya tenemos : ), solo un poco de extensión en la semántica:

  • permitir etiquetas vacías (¿llamar a estas expresiones "anónimas"?)
  • si solo existe una captura no anónima, no genere una matriz de coincidencias de expresión, en su lugar, devuelva la única coincidencia

En ese caso, más coherente marcará con "etiquetas" vacías aquellas expresiones que deberán devolverse como resultado. Es, por cierto, para no romper la semántica existente: la etiqueta existe, pero no tiene nombre; a medida que se introducen etiquetas para acceder al resultado, es bastante lógico que las etiquetas sin nombre se conviertan automáticamente en resultado. Se prohibirá la existencia simultánea de etiquetas automáticas y de hormigón. Si solo existe una etiqueta automática, entonces se debe devolver el resultado único, pero no una matriz con un elemento, ya que dicho comportamiento es más demandado.

@Mingun

¿Por qué no devolver cualquier etiqueta?
start = "{" :expr "}" // return expr
start = "{" label:expr "}" // return label
Creo que tiene sentido que si "etiquetas" algo, entonces quieras hacer algo con él (por ejemplo, devolverlo).

Por otro lado, ¿por qué reglas como start = ex:expr :expr deberían generar un error?
¿Quizás debería hacer algo similar a la variable de argumentos de las funciones de JavaScript? Por ejemplo, start = ex:expr :expr debería devolver [ex, expr] . Cuando tiene una acción, debe etiquetarse & arguments variables ( start = ex:expr :expr { return [ex, arguments[0], ex] } )

@alanmimms Me gusta esta idea. No tenemos que crear un nombre (una variable / etiqueta) solo para devolver un valor simple.
Creo que una etiqueta sin nombre ( :expr ) sería mejor que ^expr

¿Por qué no devolver cualquier etiqueta?

@nedzadarek porque si le das un nombre a la expresión es más probable que no lo uses en alguna expresión no trivial. Al menos, el nombre es importante para ti, de lo contrario no lo darías, ¿verdad? Además, mezclar etiquetas con nombre y sin nombre es más probable que sea un error que una acción consciente, por lo que será más seguro si se prohíbe. Si da un nombre, ¿por qué no proporcionar otro?

Desafortunadamente, es necesario reconocer que las etiquetas automáticas en ese aspecto en lo que son ofrecidas por @opatut , es imposible de implementar ya que crea ambigüedad en la gramática. El ejemplo elemental:

start = a :b;// `a` - it is rule reference or label?
a = .;
b = .;

Entonces, para este propósito es necesario seleccionar otro personaje. Por el momento, hay una opción entre: ~ , (backslash) , @ , # , % , ^ , - , | , \ y , .


Otra solución - introducir algunas pseudo-acciones - atajos para la creación de funciones simples para retorno, por ejemplo, {=>[]} puede significar _ "recopilar los resultados etiquetados de la secuencia y devolverlos en la matriz" _ , y {=>{}} - lo mismo, pero para devolver un objeto, con las claves iguales a los nombres de las etiquetas. Pero la implementación de este comportamiento no requiere extensión de la gramática y se puede realizar mediante complementos. Incluso diría que es más preferible tener dicha implementación mediante complementos:

start1 = a:'a' b c d:. {=>[]};// returns ['a', <d value>]
start2 = a:'a' b c d:. {=>{}};// returns { a: 'a', d: <d value> }

@Mingun

porque si le das un nombre a una expresión, es más probable que no lo uses en alguna expresión no trivial. Al menos, el nombre es importante para ti, de lo contrario no lo darías, ¿verdad?

Sí, el nombre es importante => Quiero usarlo => Quiero devolverlo.
¿Cuál es el problema con las expresiones no triviales?

Desafortunadamente, es necesario reconocer que las etiquetas automáticas en ese aspecto en lo que son ofrecidas por @opatut , es imposible de implementar ya que crea ambigüedad en la gramática. El ejemplo elemental:

Si.
¿Supongo que ::expression es confuso? @dmajda

Cerrado como duplicado de # 235

Editar: se agregó una nota al comentario de OP en el # 235 que hace referencia a este problema

¿Fue útil esta página
0 / 5 - 0 calificaciones