Pegjs: Taquigrafía para acciones semánticas

Creado en 10 sept. 2018  ·  13Comentarios  ·  Fuente: pegjs/pegjs

Sería bueno agregar taquigrafía para acciones semánticas.

Digamos, en lugar de escribir { return value } , escribimos, por ejemplo, { extract } que está definido en el inicializador.

Por ejemplo:

{
  function extract(value) {
    return value;
  }
  function concat(head, tail) {
    return head ? [head].concat(tail) : [];
  }
  function toAddExpr(head, tail) {
    return { type: 'addExpr', expressions: concat(head, tail) };
  }
}

List
  = '(' _ head:Item? tail:( _ ',' _ value:Item { extract } )* _ ')' { concat }

// Another kind of list
Add
  = '(' _ head:Multiply? tail:( _ '+' _ value:Multiply { extract } )* _ ')' { toAddExpr }

Primero, esto nos permitirá reutilizar funciones ... de una manera más agradable: smile:
En segundo lugar, esto hará que nuestra gramática sea un poco más legible.

Creo que también será más útil cuando la expresión contenida en la abreviatura de acción sea una expresión de miembro { foo.bar.baz } lugar de solo un identificador { foo } . Para que los escritores de gramática puedan organizar sus funciones dentro de un objeto o incluso un módulo.

discussion feature

Comentario más útil

En realidad, he estado pensando que estos cambios podrían funcionar:

CodeBlock "code block"
  = "=>" _ expession:CallExpression {
       return `return ${ expession };`;
     }
  / "{" <strong i="6">@Code</strong> "}"
  / "{" { error("Unbalanced brace."); }

// Will be based on ECMAScript's CallExpression
CallExpression
  = ...
  / MemberExpression

// Will be based on ECMAScript's MemberExpression
MemberExpression
  = ...
  / ValidIdentifier

// Change `LabelIdentifier` into `ValidIdentifier`

De esta manera, aún será necesario integrar algunas cosas como las expresiones primarias de ECMAScript (números, valores booleanos, matrices, etc.) para usarlas como argumentos, por lo que deberá averiguar cuidadosamente qué agregar.


soportes de equilibrio y tirantes

Esto no se solucionará hasta que se integre un analizador JavaScript adecuado en el analizador PEG.js, pero, para ser honesto, tengo algunas dudas sobre esto, ya que hay algunos proyectos de complementos que generan analizadores en otros lenguajes (C, PHP, TypeScript , etc.), y también estoy trabajando en un lenguaje informático en el que espero algún día generar analizadores.


Junto con _PEG.js v0.12_, estaré trabajando en OpenPEG , que ofrecerá un paquete NPM que es esencialmente una versión simplificada de PEG.js sin JavaScript ni generación de analizadores involucrados, pero con suficientes características para que proyectos basados ​​en JavaScript como PEG.js puede usarlo como backend. Cuando salga _v0.12_, intentaré asegurarme de que todos los proyectos de complementos que generen analizadores personalizados sean notificados de OpenPEG, y antes de v1 implementar un analizador completo ECMAScript 2015 en el analizador gramatical PEG.js.

Todos 13 comentarios

Interesante idea, pero personalmente no creo que sea una forma más clara, ya que no es obvio qué argumentos se pasan a la función. Además, si necesita pasar un parámetro "personalizado", deberá mezclarlos con llamadas a funciones regulares, para que no se vea tan limpio como en los casos más simples.

Alguien en el # 235 sugirió la sintaxis => para ir junto con las funciones de flecha, que pensé que era bastante clara y concisa.

  = '(' expr:some_expression ')' => expr
  ;

Me inclino por elegir uno de los siguientes para la sintaxis abreviada:

  • => expr; _ (necesita soporte para la sintaxis) _
  • { => expr } _ (utilizable ahora, pero necesita desenvolverse) _
  • { > expr } _ (necesita soporte para la sintaxis) _

Aún no lo he decidido, por lo que está abierto a discusión.

En cuanto a lo que quiere el OP, sería mejor implementar un complemento (después o antes de que se decida la sintaxis abreviada) que use Acorn o @ babel / parser para desenvolver el identificador o expresión de miembro, transformarlo en una expresión de llamada mientras agrega el etiquetas como argumentos y devuelve el código generado.

=> expr;

Mejor en mi opinión.

{ => expr }

Conflictos con la sintaxis de Javascript IMO. Dado que está dentro de { } , esperaría que fuera una función de flecha completa ( () => ).

{ > expr}

Un poco ortogonal a cualquier otra sintaxis en PegJS o Javascript, no lee inmediatamente "esto devuelve un valor, taquigrafía" IMO - principalmente porque está entre llaves, creo. El mismo argumento que {=> expr} , espera que Javascript esté allí.


Además, agregar sintaxis que no sea JS en {} es un problema para los resaltadores de sintaxis, linters, etc. No lo recomiendo.

Si puedo sugerir otra opción, quizás > por sí mismo (no dentro de un bloque de predicado). Eso ayuda a mantener las cosas alineadas cuando espacia las reglas verticalmente:

    = foo:bar qux:(' '+ @qix)+
    > {foo, qux}
    ;

así como en línea

some_rule = foo:bar qux:(' '+ @qix)+ > {foo, qux};

¿Por qué se necesita el punto y coma para '=>'? Me gustaría devolver un valor en código anidado en lugar de usar buildList () por ejemplo:

  = "(" _ head:Expression _ tail:("," _ expr:Expression => expr)* ")" {
      return [head, ...tail]
    }

Encuentro esto más limpio que usar un índice mágico (abajo). Otra opción es la posibilidad de hacer referencia a etiquetas anidadas. por ejemplo, ("," _ tail:Expression)* ")"

  = "(" _ head:Expression _ tail:("," _ Expression)* ")" {
      return buildList(head, tail, 2)
    }

Estaba mirando parser.pegjs, y veo alrededor de la línea 434 que hay CodeBlock. ¿Qué se necesitaría hacer para probarlo? El código de la regla simplemente lee SourceCharacter, que es simplemente '.'

CodeBlock "code block"
  = "=>" __ <strong i="13">@Code</strong> // this?
  / "{" <strong i="14">@Code</strong> "}"

@mikeaustin Sí, eso es correcto, pero no hay forma de que sepa dónde terminar esta secuencia entonces, por lo que consumirá todo después de =>

¿Quizás "Code" podría ser un poco más inteligente, equilibrando soportes y tirantes, y manejando LineTerminator? No necesitaría saber acerca de JavaScript completo, pero eso puede ser más difícil de lo que parece.

En realidad, he estado pensando que estos cambios podrían funcionar:

CodeBlock "code block"
  = "=>" _ expession:CallExpression {
       return `return ${ expession };`;
     }
  / "{" <strong i="6">@Code</strong> "}"
  / "{" { error("Unbalanced brace."); }

// Will be based on ECMAScript's CallExpression
CallExpression
  = ...
  / MemberExpression

// Will be based on ECMAScript's MemberExpression
MemberExpression
  = ...
  / ValidIdentifier

// Change `LabelIdentifier` into `ValidIdentifier`

De esta manera, aún será necesario integrar algunas cosas como las expresiones primarias de ECMAScript (números, valores booleanos, matrices, etc.) para usarlas como argumentos, por lo que deberá averiguar cuidadosamente qué agregar.


soportes de equilibrio y tirantes

Esto no se solucionará hasta que se integre un analizador JavaScript adecuado en el analizador PEG.js, pero, para ser honesto, tengo algunas dudas sobre esto, ya que hay algunos proyectos de complementos que generan analizadores en otros lenguajes (C, PHP, TypeScript , etc.), y también estoy trabajando en un lenguaje informático en el que espero algún día generar analizadores.


Junto con _PEG.js v0.12_, estaré trabajando en OpenPEG , que ofrecerá un paquete NPM que es esencialmente una versión simplificada de PEG.js sin JavaScript ni generación de analizadores involucrados, pero con suficientes características para que proyectos basados ​​en JavaScript como PEG.js puede usarlo como backend. Cuando salga _v0.12_, intentaré asegurarme de que todos los proyectos de complementos que generen analizadores personalizados sean notificados de OpenPEG, y antes de v1 implementar un analizador completo ECMAScript 2015 en el analizador gramatical PEG.js.

FWIW, comencé a usar plantillas literales para esto. También me ayuda con el resaltado de sintaxis de JS por mi editor de texto ...

exports = module.exports = functionBodies`${grammarScript}
...
objectText =
    head:word
    rest:(_txt_ word)*
    ${f=>{
        return new Txt(rest.reduce((a,b)=>([...a,...b]),[head]))
        }}
word = ch:(wordCharacter/escapedCharacter)+ ${chJoin}
...
`
function functionBodies(glue, ...fns){
    return glue.map( (str,i) => str + (fns[i]||'').toString().replace(/^[^{]*/,'').replace(/[^}]*$/, '') ).join('')
    }

function chJoin(ch){return ch.join('')}

¿Qué tal usar el operador de tubería propuesto (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Pipeline_operator)? ¿Ya que, básicamente, estás pidiendo canalizar los datos?

{
  function extract(value) {
    return value;
  }
  function concat(head, tail) {
    return head ? [head].concat(tail) : [];
  }
  function toAddExpr(head, tail) {
    return { type: 'addExpr', expressions: concat(head, tail) };
  }
}

List
  = '(' _ head:Item? tail:( _ ',' _ value:Item |> extract )* _ ')' |> concat

// Another kind of list
Add
  = '(' _ head:Multiply? tail:( _ '+' _ value:Multiply |> extract  )* _ ')' |> toAddExpr

Nada de esto debería suceder. No debe haber una sintaxis corta.

Nada de esto es necesario si analizamos las flechas normalmente, en lugar de intentar calzarlas hacia los lados.

Si bien esta es una buena idea, establece amplias ambigüedades gramaticales frente a JavaScript. Cualquiera que haya analizado JS y recuerde lo que fue una debacle with sabe que esto básicamente asesinará a un analizador.

En lugar de intentar crear cosas nuevas y sofisticadas, solo deberíamos admitir Javascript. Las funciones de flecha son anteriores a ES6 y ES6 es de 2015. Esto se resolvió hace seis años. Aquí no debería ocurrir ningún invento.

El operador de tubería tiene muchos defectos y probablemente no lo convertirá en Javascript, y tanto el lenguaje del que proviene originalmente (F #) como el lenguaje que lo popularizó (Elixir) se están alejando de él. Además, esto no es una tubería en ningún sentido.

La razón por la que PEG tuvo tanto éxito fue que era mínimo y se mantenía cerca del lenguaje, lo que le permitía ser rápido, pequeño y predecible.

Las funciones de flecha son anteriores a ES6 y ES6 es de 2015. Esto se resolvió hace seis años. Aquí no debería ocurrir ningún invento.

Oh. Eso es nuevo para mí. ¿Le importaría expandirse?

La razón por la que PEG tuvo tanto éxito fue que era mínimo y se mantenía cerca del lenguaje, lo que le permitía ser rápido, pequeño y predecible.

La razón por la que PEG (como concepto, no esta biblioteca) tiene éxito es por su capacidad para representar gramáticas complejas (recursivas, etc.) de una manera simplista. Packrat no se inventó con esta biblioteca; no es una sintaxis. Es un algoritmo.

Las funciones de flecha son anteriores a ES6 y ES6 es de 2015. Esto se resolvió hace seis años. Aquí no debería ocurrir ningún invento.

Oh. Eso es nuevo para mí. ¿Le importaría expandirse?

Realmente no sé lo que estás preguntando.

Las funciones de flecha son anteriores a ES6. Esta fue la segunda pelea más grande en ES6, es lo que descarriló ES4 y lo que descarriló ES5 +. Todo el mundo había estado preguntando por ellos, en ese momento, desde mediados de los 90, porque de hecho ya existían en E4X, y se los quitaron porque Google y Apple le lanzaron un ataque a Hixie acerca de que Microsoft alguna vez inventó algo.

Ahora conoce E4X como React y cree que Facebook lo inventó. Facebook cree que robaron Hyperscript. El tipo de Hyperscript tiene claro que solo estaba reimplementando algo útil del antiguo IE.

Iban a quedar fuera de ES6 por completo, al igual que las cadenas de plantillas, pero luego apareció Coffeescript y le dio a la comunidad JS ambos, y luego la comunidad JS gritó hasta que la gente de ECMA se movió. Solo tomó 18 meses

Las funciones de flecha hacen todo lo que debe suceder aquí. Incluso parece ser la persona que los mencionó en este hilo, en 2018, lo que hace que su desacuerdo sea bastante sorprendente; Estaba tratando de respaldarte.

Más importante para mí, si se hace con una función de flecha, no se ha agregado nada.

Las diferencias de Peg con JS son absolutamente mínimas. Apoyar esto simplemente haciendo cosas de ES6 significa que la lista no cambia.

Eso es extremadamente valioso.


La razón por la que PEG (como concepto, no esta biblioteca) tiene éxito es por su capacidad para representar gramáticas complejas (recursivas, etc.) de una manera simplista.

No estoy de acuerdo Muchos analizadores hacen un trabajo mucho mejor con esto, y ni siquiera son un poco populares, incluso entre las personas que los conocen (como Earley).

La explicación tradicional es una combinación de la calidad y la velocidad del mensaje de error, pero tampoco estoy de acuerdo con eso, porque muchos analizadores tienen mejores mensajes de error más rápido (de nuevo, como Earley) y ni siquiera son un poco populares, incluso entre la gente. que saben de ellos

Además, tenga en cuenta que PEG tiene tres techos de complejidad graves.

Uno, cualquier cosa que desee pasar por una gramática de clavija debe tener una expresión combinatoria que no abrume la memoria caché de la máquina local y el rendimiento de evaluación (por ejemplo # 623)

Dos, muchos trabajos comunes, como analizar BNF, son con frecuencia brutalmente difíciles en la vinculación (por ejemplo # 489)

Tres, vale la pena señalar que todas las demás bibliotecas JS PEG, incluso las más poderosas, han fallado. Traté de cambiarme y he regresado muchas veces. En particular, he intentado cambiar a canopy varias veces, porque me permite apuntar a c , ruby y python además hasta javascript

De acuerdo, todo lo que puedo hablar son las dos docenas de personas que conozco que lo están usando. Y puedo, porque pregunté hace un par de días, cuando me di cuenta de que el nuevo no responsable estaba tirando el software y reemplazándolo con algo que hizo desde cero, después de años sin cambios publicados.

Pero todos y cada uno de ellos me dijeron que necesitaban un analizador que no tuviera mucha sobrecarga conceptual nativa o que necesitaban algo rápido y pequeño cuyo comportamiento fuera confiable.

El 0.11 inédito se comporta de manera significativamente diferente en node vs chrome, y el nodo está hecho de chrome. Intente escribir algunas pruebas de propiedad en su contra. Honestamente, es algo aterrador.

.

Packrat no se inventó con esta biblioteca; no es una sintaxis. Es un algoritmo.

No dije nada sobre Packrat, amigo. No estoy seguro de lo que intentas corregir.

Sin embargo, el análisis de Packrat no es un algoritmo, por la misma razón que la ordenación no es un algoritmo. El análisis de Packrat es una tarea y hay muchas formas de hacerlo.

De hecho, la mayoría de los libros introductorios de haskell te obligan a hacer tres o cuatro analizadores de packrat diferentes, porque son una excelente manera de obsesionarte con los problemas de rendimiento del enfoque de haskell sobre las mónadas, y quieren mostrarte cómo cambiar el enfoque de la escritura. packrats (es decir, cambiar el algoritmo) produce mejores resultados.

.

Por favor reconsidere ese pulgar hacia abajo. Esta biblioteca ha estado muerta durante tres años y me gustaría resucitarla ahora.

Parte de la razón por la que la biblioteca está muerta es que la gente sigue tratando de inventar características nuevas, en lugar de realizar un mantenimiento simple, como agregar la función del módulo es() que ha estado en desarrollo durante dos años

Tengo que modificar manualmente mis analizadores PEG cortando líneas y engrapando javascript escrito a mano al final de ellos

Los ojos estrellados deben cerrarse por un momento, y deben comenzar algunos codos grasientos prácticos. PEG es la única biblioteca importante de NPM que he visto con un uso decreciente. Dado que no conozco un reemplazo razonable, eso me resulta extraño y confuso.

image

Tengo correcciones de errores que quiero contribuir en este momento, pero no puedo, porque

  1. 0.10 no se ha publicado desde que se fue dmajda,
  2. 0.11 tiene tres años, nunca se ha publicado y se anunció hace un mes que nunca se publicaría, y
  3. El reemplazo, 0.12 , no está vinculado en absoluto, sino algo que el otro tipo escribió desde cero en un lenguaje de programación diferente, y ninguno de nosotros puede verlo.

Sé que es descortés, pero tenemos que afrontar que esta biblioteca está siendo asesinada

Es hora de afrontar que tenemos que aceptar un proceso de desarrollo normal si esta biblioteca alguna vez volverá a ver actualizaciones. Es 2020. No hemos visto nada desde 2017.

No, la rama de desarrollo no cuenta. Y el nuevo mantenedor tendrá que volver a abrir un montón de problemas, porque 0.11 no tiene la calidad suficiente, y empezar de nuevo desde 10 es mucho menos trabajo que arreglar 11

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