Pegjs: Abreviação para ações semânticas

Criado em 10 set. 2018  ·  13Comentários  ·  Fonte: pegjs/pegjs

Seria bom adicionar um atalho para ações semânticas.

Digamos que, em vez de escrever { return value } , escrevamos, por exemplo, { extract } que é definido no inicializador.

Por exemplo:

{
  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 }

Em primeiro lugar, isso nos tornará capazes de reutilizar funções ... de uma forma mais agradável: sorria:
Em segundo lugar, isso tornará nossa gramática um pouco mais legível.

Acredito que também será mais útil quando a expressão contida na abreviação da ação for uma expressão de membro { foo.bar.baz } vez de apenas o identificador { foo } . Para que os escritores de gramática possam organizar suas funções dentro de um objeto ou mesmo de um módulo.

discussion feature

Comentários muito úteis

Na verdade, tenho pensado que essas mudanças podem 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`

Dessa forma, ainda será necessário integrar algumas coisas como as expressões primárias do ECMAScript (números, booleanos, arrays, etc) para serem usados ​​como argumentos, portanto, será necessário descobrir cuidadosamente o que adicionar.


balanceamento de suportes e chaves

Isso não será corrigido até que um analisador JavaScript adequado seja integrado ao analisador PEG.js, mas para ser honesto, estou um pouco hesitante quanto a isso, pois existem alguns projetos de plug-in que geram analisadores em outras linguagens (C, PHP, TypeScript , etc), e também estou trabalhando em uma linguagem de computador na qual espero um dia gerar analisadores.


Junto com _PEG.js v0.12_, estarei trabalhando em OpenPEG , que oferecerá um pacote NPM que é essencialmente uma versão simplificada de PEG.js sem nenhum JavaScript e geração de analisador envolvido, mas recursos suficientes para que projetos baseados em JavaScript como PEG.js pode usá-lo como back-end. Quando _v0.12_ for lançado, tentarei garantir que todos os projetos de plug-in que geram analisadores personalizados sejam notificados do OpenPEG e, antes da v1, implementarei um analisador ECMAScript 2015 completo no analisador gramatical PEG.js.

Todos 13 comentários

Ideia interessante, mas pessoalmente não acho que seria uma maneira mais clara, uma vez que não é óbvio quais argumentos estão sendo passados ​​para a função. Além disso, se você precisar passar um parâmetro "personalizado" - você precisará misturá-los com chamadas de função regulares, para que não pareça tão limpo como nos casos mais simples.

Alguém em # 235 sugeriu a sintaxe => para ir junto com as funções de seta, que eu achei bem claras e concisas.

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

Estou inclinado a escolher um dos seguintes para a sintaxe de abreviações:

  • => expr; _ (precisa de suporte para sintaxe) _
  • { => expr } _ (utilizável agora, mas precisa ser desembrulhado) _
  • { > expr } _ (precisa de suporte para sintaxe) _

Ainda não decidi, então está aberto para discussão.

Quanto ao que o OP deseja, seria melhor implementar um plugin (depois ou antes da sintaxe abreviada ser decidida) que usa Acorn ou @ babel / parser para desembrulhar o identificador ou expressão de membro, transformá-lo em uma expressão de chamada enquanto adiciona o rótulos como argumentos e retornam o código gerado.

=> expr;

Melhor na minha opinião.

{ => expr }

Conflitos com a sintaxe Javascript IMO. Como está dentro de { } você esperaria que fosse uma função de seta completa ( () => ).

{ > expr}

Um pouco ortogonal a qualquer outra sintaxe em PegJS ou Javascript, não lê imediatamente "isso retorna um valor, abreviação" IMO - principalmente porque está entre chaves, eu acho. Mesmo argumento de {=> expr} , você espera que o Javascript esteja lá.


Além disso, adicionar sintaxe não-JS em {} é um problema para realçadores de sintaxe, linters, etc. Eu não recomendo.

Se eu puder sugerir outra opção, talvez > por si só (não dentro de um bloco de predicado). Isso ajuda a manter as coisas alinhadas ao espaçar verticalmente as regras:

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

bem como em linha

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

Por que o ponto-e-vírgula é necessário para '=>'? Eu gostaria de retornar um valor no código aninhado em vez de usar buildList () por exemplo:

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

Acho isso mais limpo do que usar um índice mágico (abaixo). Outra opção é a capacidade de se referir a rótulos aninhados. por exemplo, ("," _ tail:Expression)* ")"

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

Eu estava olhando para parser.pegjs e vejo em torno da linha 434 que há CodeBlock. O que precisa ser feito para experimentá-lo? O código de regra simplesmente lê SourceCharacter, que é apenas '.'

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

@mikeaustin Sim, está certo, mas não há como saber onde terminar esta sequência, então consumirá tudo após =>

Talvez "Code" pudesse ser um pouco mais inteligente, balanceando colchetes e chaves e lidando com LineTerminator? Não seria necessário saber sobre JavaScript completo, mas isso pode ser mais difícil do que parece.

Na verdade, tenho pensado que essas mudanças podem 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`

Dessa forma, ainda será necessário integrar algumas coisas como as expressões primárias do ECMAScript (números, booleanos, arrays, etc) para serem usados ​​como argumentos, portanto, será necessário descobrir cuidadosamente o que adicionar.


balanceamento de suportes e chaves

Isso não será corrigido até que um analisador JavaScript adequado seja integrado ao analisador PEG.js, mas para ser honesto, estou um pouco hesitante quanto a isso, pois existem alguns projetos de plug-in que geram analisadores em outras linguagens (C, PHP, TypeScript , etc), e também estou trabalhando em uma linguagem de computador na qual espero um dia gerar analisadores.


Junto com _PEG.js v0.12_, estarei trabalhando em OpenPEG , que oferecerá um pacote NPM que é essencialmente uma versão simplificada de PEG.js sem nenhum JavaScript e geração de analisador envolvido, mas recursos suficientes para que projetos baseados em JavaScript como PEG.js pode usá-lo como back-end. Quando _v0.12_ for lançado, tentarei garantir que todos os projetos de plug-in que geram analisadores personalizados sejam notificados do OpenPEG e, antes da v1, implementarei um analisador ECMAScript 2015 completo no analisador gramatical PEG.js.

FWIW, comecei a usar literais de modelo para isso. Também me ajuda a destacar a sintaxe de JS pelo meu 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('')}

Que tal usar o operador de pipe proposto (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Pipeline_operator)? Já que, basicamente, você está pedindo para canalizar os dados?

{
  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 disso deve acontecer. Não deve haver sintaxe curta.

Nada disso é necessário se apenas analisarmos as setas normalmente, em vez de tentar calçá-las lateralmente.

Embora seja uma ideia bacana, ela cria ambiguidades gramaticais extensas em relação ao JavaScript. Qualquer um que já tenha analisado JS e se lembre de como foi um desastre with sabe que isso basicamente matará um analisador.

Em vez de tentar criar coisas novas e sofisticadas, devemos apenas oferecer suporte a Javascript. As funções de seta são mais antigas do que ES6 e ES6 é de 2015. Isso foi resolvido há seis anos. Nenhuma invenção deve acontecer aqui.

O operador pipe tem muitas falhas e provavelmente não chegará ao Javascript, e tanto a linguagem de onde ele vem originalmente (F #) quanto a linguagem que o popularizou (Elixir) estão se afastando dele. Além disso, isso não é tubulação em nenhum sentido.

O motivo do PEG ter tanto sucesso é que ele era mínimo e permanecia próximo à linguagem, permitindo que fosse rápido, pequeno e previsível.

As funções de seta são mais antigas do que ES6 e ES6 é de 2015. Isso foi resolvido há seis anos. Nenhuma invenção deve acontecer aqui.

Uh. Isso é novidade para mim. Quer expandir?

O motivo do PEG ter tanto sucesso é que ele era mínimo e permanecia próximo à linguagem, permitindo que fosse rápido, pequeno e previsível.

A razão pela qual o PEG (como um conceito, não esta biblioteca) é bem-sucedido é por causa de sua capacidade de representar gramáticas complexas (recursivas, etc.) de uma forma simplista. Packrat não foi inventado com esta biblioteca; não é uma sintaxe. É um algoritmo.

As funções de seta são mais antigas do que ES6 e ES6 é de 2015. Isso foi resolvido há seis anos. Nenhuma invenção deve acontecer aqui.

Uh. Isso é novidade para mim. Quer expandir?

Eu realmente não sei o que você está perguntando.

As funções de seta são mais antigas que ES6. Esta foi a segunda maior luta em ES6, é o que descarrilou ES4, e o que descarrilou ES5 +. Todo mundo tinha perguntado por eles, naquele momento, desde meados dos anos 90, porque eles de fato já existiam na E4X, e foram tirados porque o Google e a Apple brigaram com Hixie sobre a Microsoft ter inventado alguma coisa.

Agora você conhece o E4X como React e acha que o Facebook o inventou. O Facebook acha que roubou o Hyperscript. O cara do Hyperscript deixou claro que estava apenas reimplementando uma coisa útil do antigo IE.

Eles seriam deixados de fora do ES6 inteiramente, assim como strings de template, mas então Coffeescript apareceu e deu à comunidade JS ambos, e então a comunidade JS gritou até que o pessoal da ECMA cedeu. Levou apenas 18 meses

As funções de seta fazem tudo o que precisa acontecer aqui. Você até parece ser a pessoa que os mencionou neste tópico, em 2018, o que torna sua discordância bastante surpreendente; Eu estava tentando te apoiar.

Mais importante para mim, se for feito com uma função de seta, nada foi adicionado.

As diferenças de Peg em relação a JS são absolutamente mínimas. Apoiar isso apenas fazendo coisas do ES6 significa que a lista não muda.

Isso é extremamente valioso.


A razão pela qual o PEG (como um conceito, não esta biblioteca) é bem-sucedido é por causa de sua capacidade de representar gramáticas complexas (recursivas, etc.) de uma forma simplista.

Eu não concordo. Muitos analisadores fazem um trabalho muito melhor nisso e nem são ligeiramente populares, mesmo entre as pessoas que os conhecem (como Earley).

A explicação tradicional é uma combinação de qualidade e velocidade de mensagem de erro, mas também não concordo com isso, porque muitos analisadores têm mensagens de erro melhores e mais rápidas (novamente, como Earley) e não são nem um pouco populares, mesmo com as pessoas quem sabe sobre eles

Além disso, observe que o PEG tem três tetos de grande complexidade.

Um, qualquer coisa que você queira passar por uma gramática de fixação deve ter uma expressão combinatória que não sobrecarregue o cache da máquina local e a taxa de transferência de avaliação (por exemplo # 623)

Dois, muitos trabalhos comuns, como analisar BNF, são frequentemente brutalmente difíceis de rastrear (por exemplo # 489)

Três, é importante notar que todas as outras bibliotecas JS PEG, mesmo as significativamente mais poderosas, falharam. Tentei me desligar e voltei muitas vezes. Em particular, tentei mudar para canopy várias vezes, porque me permite segmentar c , ruby e python além disso para javascript

Certo, só posso falar pelas cerca de duas dúzias de pessoas que conheço que o estão usando. E eu posso, porque perguntei alguns dias atrás, quando percebi que o novo não-mantenedor estava jogando fora o software e substituindo-o por algo que ele fez do zero, após anos sem alterações publicadas

Mas cada um deles me disse que precisava de um analisador que não tivesse muita sobrecarga conceitual nativa ou que precisava de algo rápido e pequeno cujo comportamento fosse confiável

Unreleased 0.11 se comporta de maneira significativamente diferente no node vs chrome, e o node é feito de chrome. Tente escrever alguns testes de propriedade em relação a ele. Honestamente, é meio assustador.

.

Packrat não foi inventado com esta biblioteca; não é uma sintaxe. É um algoritmo.

Não falei nada sobre Packrat, amigo. Não tenho certeza do que você está tentando corrigir.

A análise de Packrat não é, entretanto, um algoritmo, pela mesma razão que a classificação não é um algoritmo. A análise do Packrat é uma tarefa e há muitas maneiras de fazer isso.

Na verdade, a maioria dos livros haskell de introdução faz com que você faça três ou quatro analisadores packrat diferentes, porque eles são uma ótima maneira de ficar realmente preso aos problemas de desempenho da abordagem do haskell às mônadas e querem mostrar como mudar a abordagem da escrita packrats (ou seja, alterar o algoritmo) produz melhores resultados.

.

Por favor, reconsidere isso. Esta biblioteca está morta há três anos e gostaria de ressuscitá-la agora.

Parte da razão pela qual a biblioteca está morta é que as pessoas continuam tentando inventar novos recursos, em vez de realizar uma manutenção simples, como adicionar a função de módulo es() que está parada no desenvolvimento por dois anos

Tenho que modificar manualmente meus analisadores PEG cortando linhas e grampeando javascript escrito à mão no final delas

Os olhos estrelados devem fechar por um momento, e alguns cotovelos gordurosos práticos devem começar. PEG é a única biblioteca NPM importante que já vi com uso em declínio. Visto que não estou ciente de uma substituição razoável, isso é bizarro e confuso para mim.

image

Tenho correções de bugs que quero contribuir agora, mas não posso, porque

  1. 0.10 não foi publicado desde que dmajda saiu,
  2. 0.11 tem três anos, nunca foi publicado e foi anunciado há um mês que nunca seria publicado e
  3. A substituição, 0.12 , não é peg, mas algo que o outro cara escreveu do zero em uma linguagem de programação diferente e nenhum de nós pode ver

Eu sei que é indelicado, mas precisamos enfrentar que esta biblioteca está sendo morta

É hora de reconhecer que precisamos aceitar um processo de desenvolvimento normal se esta biblioteca for receber atualizações novamente. É 2020. Não vimos nada desde 2017.

Não, o branch dev não conta. E o novo mantenedor terá que reabrir um monte de problemas, porque 0.11 não é de qualidade suficiente e começar de 10 é muito menos trabalhoso do que consertar 11

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

pepa65 picture pepa65  ·  24Comentários

lontivero picture lontivero  ·  25Comentários

ceymard picture ceymard  ·  32Comentários

doersino picture doersino  ·  15Comentários

chromaticbum picture chromaticbum  ·  29Comentários