É 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:
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:
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