Search code examples
grammarpegjsambiguous-grammar

PEGJS predicate grammar


I need to create a grammar with the help of predicate. The below grammar fails for the given case.

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]+;

It fails for the given input as

com.mytest.create();

which should have given "create" as value of "name" key in the result part.

Any help would be great.


Solution

  • There are several things here.

    The most important, is that you must be aware that PEG is greedy. That means that your (DOT id)* rule matches ALL the DOT id sequences, including the one that you have in startRule as DOT b:id.

    That can be solved using lookahead.

    The other thing is that you must remember to use join, since by default it will return each character as the member of an array.

    I also added a rule for semicolons.

    Try this:

    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(''); }
    

    And as far I can tell, I'm parsing that line correctly.