PEGJS предикатная грамматика

Мне нужно создать грамматику с помощью предиката. Приведенная ниже грамматика не подходит для данного случая.

startRule = a:namespace DOT b:id OPEN_BRACE CLOSE_BRACE {return {"namespace": a, "name": b}}

namespace = id (DOT id)*
DOT = '.';
OPEN_BRACE = '(';
CLOSE_BRACE = ')';
id = [a-zA-Z]+;

Сбой для данного входа как

com.mytest.create();

который должен был дать "create" как значение ключа "name" в результирующей части.

Любая помощь будет отличной.

1 ответ

Решение

Здесь есть несколько вещей.

Самое главное, что вы должны знать, что PEG является жадным. Это означает, что ваш (DOT id)* правило соответствует ВСЕМ последовательностям идентификатора DOT, включая ту, которая у вас есть в startRule как DOT b:id,

Это может быть решено с помощью Lookahead.

Другое дело, что вы должны помнить, чтобы использовать join, поскольку по умолчанию он будет возвращать каждый символ как член массива.

Я также добавил правило для точек с запятой.

Попробуй это:

start =
  namespace:namespace DOT name:string OPEN_BRACE CLOSE_BRACE SM nl?
    {
      return { namespace : namespace, name : name };
    }

/* Here I'm using the lookahead: (member !OPEN_BRACE)*  */
namespace =
  first:string rest:(member !OPEN_BRACE)* 
    {
      rest = rest.map(function (x) { return x[0]; });
      rest.unshift(first);
      return rest;
    }

member =
  DOT str:string
    { return str; }

DOT =
  '.'

OPEN_BRACE =
  '('

CLOSE_BRACE =
  ')'

SM =
  ';'

nl =
  "\n"

string =
  str:[a-zA-Z]+
    { return str.join(''); }

И, насколько я могу судить, я правильно разбираю эту строку.

Другие вопросы по тегам