Search code examples
javascriptparsingpegpegjs

Save variable value for future use on peg.js


I am implementing a Relational Algebra to SQL converter using Peg.js. I got implementing almost all actions, but I not implement the assigment operator, where a relation is converted to SQL and is saved in a variable for future use. (Ex: A <- Π id (Clients)).

As the original code has more than 200 lines, I'll post a simple example with to explain what I had thought to capture this rule.

Code of the parser:

{
    var variables = [];
    console.log(variables);
    function save(chave, value, rest){
            console.log("save", chave, value);
            variables[chave] = value;
            return rest;
    }

    function get(chave){
        console.log("get", chave);
        return variables[chave];
    }

}


start 
  = _ id:Identificador _ "=" _ val:Integer _ [\n]* _ rest:start
   {save(id,val);}
  / _ val:Integer _ {return val;}
  / _ id:Identificador _ {console.log(id, variables[id]); return get(id);}


Identificador "identificador"
  = [a-zA-Z]+ {return text();}
Integer "integer"
  = [0-9]+ { return parseInt(text(), 10); }

_ "whitespace"
  = [ \t\r]*

Input example:

A = 23
B = 45
A

At the beginning of my parser, I created an array to store the values ​​to be saved, which would be accessed through the variable name.

In my first rule, I stated that every identifier, followed by the assignment operator (in my example, is the equal sign), then by the value to be saved (which in the example is an integer), followed by a line break and Then for the rest of the text, there would be a save in the array, storing the identifier as key and its value, and processing the rest of the query.

In the last line of the first rule, I declared that any line containing only the alphabetic identifier would be replaced by its stored value. In the example, the parser should return the value 23, which was the value assigned to variable A.

However the parser is returning undefined. I checked the web console and saw that the order of execution is incorrect.

Console after running the parser

Is there any way to set the exact order of execution? I wanted the parser to save the found value before processing the rest of the text.


Solution

  • I'm not sure how to make peg reverse the order of evaluation, but you could throw all expressions onto a stack and then evaluate them in reverse order. Try this:

    {
        var stack = [];
        var result = null;
    
        var variables = {};
        console.log(variables);
        function save(chave, value, rest){
                console.log("save", chave, value);
                stack.push(()=>{variables[chave] = value});
                return rest;
        }
    
        function get(chave){
            console.log("get", chave);
            stack.push(()=>{result = variables[chave]});
        }
    
        function evalStack() {
            for (var i = stack.length - 1; 0 <= i; i--) {
                stack[i]()
            }
            return result;
        }
    }
    
    
    start
      = expr
        {return evalStack();}
    
    expr
      = _ id:Identificador _ "=" _ val:Integer _ [\n]* _ rest:expr
       {save(id,val);}
      / _ val:Integer _ {return val;}
      / _ id:Identificador _ {console.log(id, variables[id]); return get(id);}
    
    
    Identificador "identificador"
      = [a-zA-Z]+ {return text();}
    Integer "integer"
      = [0-9]+ { return parseInt(text(), 10); }
    
    _ "whitespace"
      = [ \t\r]*