Pegjs: Permitir o retorno do resultado da correspondência de uma expressão específica em uma regra sem uma ação

Criado em 23 mai. 2016  ·  10Comentários  ·  Fonte: pegjs/pegjs

É muito comum precisar retornar um valor de um dos não terminais em uma regra ou dentro de uma sub-regra entre parênteses. Por exemplo:

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

Nesse caso, eu precisava do expr rotulado como e dentro do nível de parênteses init para uma frase opcional no idioma. Não precisei da "palavra de ruído" EQ como parte do valor retornado.

Se a linguagem PEGjs tivesse um símbolo a ser usado para marcar terminais como o expr acima para que eles, e somente eles, fossem o valor retornado de uma regra ou sub-regra gramatical, este caso seria mais simples.

Para reescrever meu exemplo acima:

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

Observe o uso de ^ para marcar o expr dentro da sub-regra de frase opcional entre parênteses init para designar o que está vinculado a init . Isso simplifica muitas situações com e sem a sub-regra entre parênteses mostrada neste exemplo.

Obrigado por fazer uma ferramenta tão maravilhosamente simples, elegante e poderosa. Eu amo PEGjs! :sorriso:

feature

Todos 10 comentários

Amei essa ideia! ^ é muito intuitivo.

Isso também pode funcionar em regras não aninhadas:

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

Muito legível! Presumivelmente, o uso de vários ^ também funcionaria, de modo que:

a = ^b  c  ^d  e

Retornaria [b, d] ? Parece fazer sentido.

Da mesma forma, parece fazer sentido que, se misturado com capturas nomeadas, as regras ^ são ignoradas, então

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

Retornaria apenas c.

Oh, essa ideia de múltiplos é excelente. Misturar com capturas nomeadas deve ser
um erro.

Na terça, 5 de julho de 2016, 01:07 Graham Wakefield [email protected]
escreveu:

Muito legível! Presumivelmente, o uso de múltiplos ^ também funcionaria, de modo que:

a = ^ bc ^ de

Retornaria [b, d]? Parece fazer sentido.

Da mesma forma, parece fazer sentido que, se misturado com capturas nomeadas, o ^
regras são ignoradas:

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

-
Você está recebendo isso porque é o autor do tópico.

Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/pegjs/pegjs/issues/427#issuecomment -230413015 ou mudo
o segmento
https://github.com/notifications/unsubscribe/ABC26k8v0DIzuWUlkoDZGm2ep10Y5bcMks5qShDAgaJpZM4IkuA9
.

Concordo totalmente que o padrão descrito é bastante comum. Ter uma maneira de expressá-lo sem uma ação faz sentido.

O que eu não tenho certeza sobre a solução proposta (o operador ^ ). Usar um caractere especial cujo significado não é imediatamente óbvio é sempre problemático e aumenta a curva de aprendizado. Também é possível que o personagem seja melhor usado para algum outro propósito. Por último, mas não menos importante, não gosto da ideia de colocar coisas que não influenciam muito a análise direta nas expressões. Pode-se argumentar que já existe uma instância disso - o operador $ - e eu concordo. Mas não tenho certeza se a adição de $ não foi um (pequeno) erro. Nesse caso, gostaria de evitar fazer isso novamente.

Vou pensar sobre isso mais profundamente após 1.0.0.

Mais um pouco de assunto para reflexão: já que ^ e expressões rotuladas meio que colidem ( @grrrwaaa sugere ignorar ^ ), que tal em vez de marcar o resultado, alguém poderia marcar as expressões _ignored_, por exemplo (sugestão de sintaxe!), fornecendo um rótulo vazio:

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

Lá, nenhuma nova sintaxe (já temos : ), apenas um pouco de extensão na semântica:

  • permitir rótulos vazios (chamar essas expressões "anônimas"?)
  • se houver apenas uma captura não anônima, não gere uma matriz de correspondências de expressão, em vez disso, retorne a única correspondência

Nesse caso, mais consistente marcará com "rótulos" vazios as expressões que precisarão ser retornadas como resultado. É, aliás, para não quebrar a semântica existente: o rótulo existe, mas não tem nome; à medida que rótulos são introduzidos para acesso ao resultado, é bastante lógico que rótulos não nomeados se tornem resultado automaticamente. É proibida a existência simultânea de etiquetas automáticas e de concreto. Se houver apenas um rótulo automático, então o único resultado, mas não uma matriz com um elemento, deve ser retornado, uma vez que tal comportamento é mais exigido.

@Mingun

Por que não devolver qualquer rótulo?
start = "{" :expr "}" // return expr
start = "{" label:expr "}" // return label
Acho que faz sentido que, se você "rotular" algo, você queira fazer algo com ele (por exemplo, devolvê-lo).

Por outro lado, por que regras como start = ex:expr :expr deveriam gerar um erro?
Talvez deva fazer algo semelhante à variável de argumentos de funções do javascript? Por exemplo start = ex:expr :expr deve retornar [ex, expr] . Quando você tem uma ação, deve haver rotulado & arguments variáveis ​​( start = ex:expr :expr { return [ex, arguments[0], ex] } )

@alanmimms eu gosto dessa ideia. Não precisamos criar um nome (uma variável / rótulo) apenas para retornar um valor simples.
Acho que rótulo sem nome ( :expr ) seria melhor do que ^expr

Por que não devolver qualquer rótulo?

@nedzadarek porque se você der um nome à expressão, é mais provável que você o use em alguma expressão não trivial. Pelo menos o nome é importante para você, senão você não o daria, é verdade? Além disso, misturar rótulos com e sem nome mais provavelmente é um erro do que uma ação consciente, então será mais seguro se for proibido. Se você der um nome, por que não fornecer outro?

Infelizmente, é necessário reconhecer que rótulos automáticos em que olham o que são oferecidos por @opatut , são impossíveis de serem implementados, pois criam ambigüidade na gramática. O exemplo elementar:

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

Então, para esse efeito, é necessário selecionar outro personagem. No momento, há uma escolha entre: ~ , (backslash) , @ , # , % , ^ , - , | , \ e , .


Outra solução - introduzir algumas pseudo-ações - um atalho para a criação de funções simples para retorno, por exemplo, {=>[]} pode significar _ "coletar os resultados rotulados da sequência e retorná-los na matriz" _ , e {=>{}} - o mesmo, mas para retornar de um objeto, com as chaves iguais aos nomes dos rótulos. Mas a implementação desse comportamento não requer extensão da gramática e pode ser bastante realizada por plug-ins. Eu diria até que é mais preferível ter essa implementação por plug-ins:

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

@Mingun

porque se você der um nome à expressão, é mais provável que você não o use em alguma expressão não trivial. Pelo menos o nome é importante para você, senão você não o daria, é verdade?

Sim, o nome é importante => quero usar => quero devolvê-lo.
Qual é o problema com expressões não triviais?

Infelizmente, é necessário reconhecer que rótulos automáticos em que olham o que são oferecidos por @opatut , são impossíveis de serem implementados, pois criam ambigüidade na gramática. O exemplo elementar:

sim.
Acho que ::expression é confuso? @dmajda

Fechado como duplicado de # 235

Edit: Adicionada nota ao comentário do OP no nº 235 que faz referência a este problema

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

Questões relacionadas

richb-hanover picture richb-hanover  ·  7Comentários

Coffee2CodeNL picture Coffee2CodeNL  ·  13Comentários

brettz9 picture brettz9  ·  8Comentários

doersino picture doersino  ·  15Comentários

mattkanwisher picture mattkanwisher  ·  5Comentários