<?xml version='1.0'?>
<bisongen version='1.0' name='VersaParser' project='Ft.Rdf.Parsers.Versa'>

  <!-- Python modules to import -->
  <modules>
    <import from='Ft.Rdf.Parsers.Versa'>ResourceExpressions</import>
    <import from='Ft.Rdf.Parsers.Versa'>BooleanExpressions</import>
    <import from='Ft.Rdf.Parsers.Versa'>Traversal</import>
    <import from='Ft.Rdf.Parsers.Versa'>Literals</import>
    <import from='Ft.Rdf.Parsers.Versa'>DataTypes</import>
    <import from='Ft.Rdf.Parsers.Versa'>NamedExpressions</import>
    <import from='Ft.Lib'>boolean</import>
  </modules>

  <!-- Token declarations -->
  <tokens>
    <token>QNAME</token>
    <token>PURE_QNAME</token>
    <token>ASTERISK</token>
    <token>COMMA</token>
    <token>SEMICOLON</token>
    <token>DOT</token>
    <token>DASH</token>
    <token>FORWARD_ARROW</token>
    <token>BACKWARD_ARROW</token>
    <token>RIGHT_PAREN</token>
    <token>LEFT_PAREN</token>
    <token>LEFT_SQUARE</token>
    <token>RIGHT_SQUARE</token>
    <token>LEFT_CURLY</token>
    <token>RIGHT_CURLY</token>
    <token>STRING_LITERAL</token>
    <token>NUMBER_LITERAL</token>
    <token>TRUE</token>
    <token>FALSE</token>
    <token>AT</token>
    <token>NOT</token>
    <token>DOLLAR</token>
    <token>PIPE</token>
  </tokens>

  <!-- Parser grammer definition -->
  <grammar start="Query">

    <!--[1] query = traversal | funtion-->
    <production name="1">
      <non-terminal>Query</non-terminal>
      <rule>
        <symbol>Expression</symbol>
      </rule>
      <rule>
        <symbol>Expression</symbol>
        <symbol>SEMICOLON</symbol>
      </rule>
    </production>

    <!--
      [8]  #Traverse away from the context (first set expression) using the second set expression
           #evaluate the boolean expresion for each result of the traversal
           #Ex, all over the age of 17 is
           #all()-ft:age->gt(.,17)

           forward-traversal = set-expression "-" set-expression "->" boolean-expression
    -->
    <production name="4">
      <non-terminal>ForwardTraversal</non-terminal>
      <rule>
        <symbol>Expression</symbol>
        <symbol>DASH</symbol>
        <symbol>Expression</symbol>
        <symbol>FORWARD_ARROW</symbol>
        <symbol>Expression</symbol>
        <code language="c">
          $$ = PyObject_CallMethod(Traversal, "ForwardTraversal", "OOO", $1, $3, $5);
        </code>
        <code language="python">
          $$ = Traversal.ForwardTraversal($1, $3, $5)
        </code>
      </rule>
    </production>

    <production name="4.5">
      <non-terminal>ForwardFilter</non-terminal>
      <rule>
        <symbol>Expression</symbol>
        <symbol>PIPE</symbol>
        <symbol>DASH</symbol>
        <symbol>Expression</symbol>
        <symbol>FORWARD_ARROW</symbol>
        <symbol>Expression</symbol>
        <code language="c">
          $$ = PyObject_CallMethod(Traversal, "ForwardTraversal", "OOOi", $1, $4, $6, 1);
        </code>
        <code language="python">
          $$ = Traversal.ForwardTraversal($1, $4, $6, 1)
        </code>
      </rule>
    </production>

    <!--
      [9]  #Traverse towards the context (first set expression) using the
           #predicates given in the second set expression
           #evaluate the boolean expresion for each result of the traversal
           #Ex, all books written by T. S. Eliot
           #h:teliot<-h:author-*

           backward-traversal = expression "<-" set-expression "-" boolean-expression
    -->
    <production name="5">
      <non-terminal>BackwardTraversal</non-terminal>
      <rule>
        <symbol>Expression</symbol>
        <symbol>BACKWARD_ARROW</symbol>
        <symbol>Expression</symbol>
        <symbol>DASH</symbol>
        <!-- FIXME: we need to be able to specify left association -->
        <symbol>Expression</symbol>
        <code language="c">
          $$ = PyObject_CallMethod(Traversal, "BackwardTraversal", "OOO", $1, $3, $5);
        </code>
        <code language="python">
          $$ = Traversal.BackwardTraversal($1, $3, $5)
        </code>
      </rule>
    </production>

    <!--
       [9.1]  #A traversal
       traversal = forward-traversal | backward-traversal
    -->
    <production name="6">
      <non-terminal>Traversal</non-terminal>
      <rule>
        <symbol>ForwardTraversal</symbol>
      </rule>
      <rule>
        <symbol>ForwardFilter</symbol>
      </rule>
      <rule>
        <symbol>BackwardTraversal</symbol>
      </rule>
    </production>


    <production name="8">
      <non-terminal>Literal</non-terminal>
      <rule>
        <symbol>AT</symbol>
        <symbol>STRING_LITERAL</symbol>
        <code language="c">
          PyObject *str = PySequence_GetSlice($2, 1, PyString_GET_SIZE($2) -1);
          $$ = PyObject_CallMethod(Literals, "ResourceLiteral", "O", str);
          Py_XDECREF(str);
        </code>
        <code language="python">
          $$ = Literals.ResourceLiteral($2[1:-1])
        </code>
      </rule>
      <rule>
        <symbol>LEFT_CURLY</symbol>
        <symbol>STRING_LITERAL</symbol>
        <symbol>RIGHT_CURLY</symbol>
        <code language="c">
          PyObject *str = PySequence_GetSlice($2, 1, PyString_GET_SIZE($2) -1);
          $$ = PyObject_CallMethod(Literals, "ResourceLiteral", "O", str);
          Py_XDECREF(str);
        </code>
        <code language="python">
          $$ = Literals.ResourceLiteral($2[1:-1])
        </code>
      </rule>
      <rule>
        <symbol>PURE_QNAME</symbol>
        <code language="c">
          $$ = PyObject_CallMethod(ResourceExpressions, "PureQNameExpression", "O", $1);
        </code>
        <code language="python">
          $$ = ResourceExpressions.PureQNameExpression($1)
        </code>
      </rule>
      <rule>
        <symbol>STRING_LITERAL</symbol>
        <!-- Remove the ' or " from each end -->
        <code language="c">
          PyObject *str = PySequence_GetSlice($1, 1, PyString_GET_SIZE($1) - 1);
          $$ = PyObject_CallMethod(Literals, "StringLiteral", "O", str);
	  Py_XDECREF(str);
        </code>
        <code language="python">
          $$ = Literals.StringLiteral($1[1:-1])
        </code>
<!--
        <code language="c">
          PyObject *str = PySequence_GetSlice($1, 1, PyString_GET_SIZE($1) - 1);
          $$ = PyObject_CallMethod(Literals, "StringLiteral", "O", str);
          Py_XDECREF(str);
        </code>
        <code language="python">
          $$ = Literals.StringLiteral($1[1:-1])
        </code>
-->
      </rule>
      <rule>
        <symbol>NUMBER_LITERAL</symbol>
        <!-- Turn it into a number -->
        <code language="c">
          PyObject *num = PyNumber_Float($1);
          $$ = PyObject_CallMethod(Literals, "NumberLiteral", "O", num);
          Py_XDECREF(num);
        </code>
        <code language="python">
          $$ = Literals.NumberLiteral(float($1))
        </code>
<!--
        <code language="c">
          PyObject *num = PyNumber_Float($1);
          $$ = PyObject_CallMethod(Literals, "NumberLiteral", "O", num);
          Py_XDECREF(num);
        </code>
        <code language="python">
          $$ = Literals.NumberLiteral(float($1))
        </code>
-->
      </rule>
      <rule>
        <symbol>TRUE</symbol>
        <code language="c">
          PyObject *t = PyObject_GetAttrString(boolean, "true");
          $$ = PyObject_CallMethod(Literals, "BooleanLiteral", "O", t);
          Py_XDECREF(t);
        </code>
        <code language="python">
          $$ = Literals.BooleanLiteral(boolean.true)
        </code>
      </rule>
      <rule>
        <symbol>FALSE</symbol>
        <code language="c">
          PyObject *t = PyObject_GetAttrString(boolean, "false");
          $$ = PyObject_CallMethod(Literals, "BooleanLiteral", "O", t);
          Py_XDECREF(t);
        </code>
        <code language="python">
          $$ = Literals.BooleanLiteral(boolean.false)
        </code>
      </rule>
    </production>


    <production name="9">
      <non-terminal>Particle</non-terminal>
      <!-- special place-holders, AKA syntactic sugar -->
      <rule>
        <symbol>DOT</symbol>
        <code language="c">
          $$ = PyObject_CallMethod(ResourceExpressions, "CurrentExpression", "");
        </code>
        <code language="python">
          $$ = ResourceExpressions.CurrentExpression()
        </code>
      </rule>
      <rule>
        <symbol>ASTERISK</symbol>
        <code language="c">
          PyObject *t = PyObject_GetAttrString(boolean, "true");
          $$ = PyObject_CallMethod(ResourceExpressions, "LiteralExpression", "O", t);
          Py_XDECREF(t);
        </code>
        <code language="python">
          $$ = ResourceExpressions.LiteralExpression(boolean.true)
        </code>
<!--
        <code language="c">
          PyObject *t = PyObject_GetAttrString(boolean, "true");
    	  Py_INCREF(t);
          $$ = t;
        </code>
        <code language="python">
          $$ = boolean.true
        </code>
-->
      </rule>
    </production>


    <!--[13] #Expressions are generally params to functions
             expression = query | literal | resource-expression
     -->

    <production name="10">
      <non-terminal>Expression</non-terminal>
      <rule>
        <symbol>LEFT_PAREN</symbol>
        <symbol>Expression</symbol>
        <symbol>RIGHT_PAREN</symbol>
        <code language="c">
          $$ = $2;
          Py_INCREF($2);
        </code>
        <code language="python">
          $$ = $2
        </code>
      </rule>
      <rule>
        <symbol>Particle</symbol>
      </rule>
      <rule>
        <symbol>Literal</symbol>
      </rule>
      <rule>
        <symbol>QNAME</symbol>
        <symbol>LEFT_PAREN</symbol>
        <symbol>ExpressionList</symbol>
        <symbol>RIGHT_PAREN</symbol>
        <code language="c">
          $$ = PyObject_CallMethod(NamedExpressions, "FunctionCallExprConstructor", "OO", $1, $3);
        </code>
        <code language="python">
          $$ = NamedExpressions.FunctionCallExprConstructor($1, $3)
        </code>
      </rule>
      <rule>
        <symbol>QNAME</symbol>
        <symbol>LEFT_PAREN</symbol>
        <symbol>RIGHT_PAREN</symbol>
        <code language="c">
          $$ = PyObject_CallMethod(NamedExpressions, "FunctionCallExprConstructor", "O", $1);
        </code>
        <code language="python">
          $$ = NamedExpressions.FunctionCallExprConstructor($1)
        </code>
      </rule>
      <rule>
        <symbol>DOLLAR</symbol>
        <symbol>QNAME</symbol>
        <code language="c">
          $$ = PyObject_CallMethod(NamedExpressions, "VariableReference", "O", $2);
        </code>
        <code language="python">
          $$ = NamedExpressions.VariableReference($2)
        </code>
      </rule>
      <rule>
        <symbol>Traversal</symbol>
      </rule>
    </production>


  <production name="12">
    <non-terminal>ExpressionList</non-terminal>
    <rule>
      <symbol>Expression</symbol>
      <code language="c">
          $$ = PyList_New(1);
          /* Steals a reference */
          PyList_SET_ITEM($$, 0, $1);
          Py_INCREF($1);
      </code>
      <code language="python">
          $$ = [$1]
      </code>
    </rule>
    <rule>
      <symbol>ExpressionList</symbol>
      <symbol>COMMA</symbol>
      <symbol>Expression</symbol>
      <code language="c">
          PyList_Append($1, $3);
          Py_INCREF($1);
          $$ = $1;
      </code>
      <code language="python">
          $1.append($3)
          $$ = $1
      </code>
    </rule>
  </production>

  </grammar>

  <!-- Lexical scanner definition -->
  <lexer>
    <defines>
      <define name='S'>[\t\n\r ]+</define>

      <!-- An NCName is supposed to allow a '-' as the last char.  However,
          it breaks our cute -wname-> grammer.
      <define name='NCName'>[a-zA-Z_][a-zA-Z0-9\.\-_]*</define>
      -->
      <define name='NCName'>[a-zA-Z_]([a-zA-Z0-9\.\-_]*[a-zA-Z0-9\._])?</define>
      <define name='QName'>({NCName}:)?{NCName}</define>
      <define name='PureQName'>{NCName}:{NCName}</define>
      <define name='StringLiteral'>('((\\')|[^'])*')|(\"((\\\")|[^"])*\")</define>
      <define name='FArrow'>\-></define>
      <define name='BArrow'>&lt;\-</define>
      <define name='Digit'>[0-9]</define>
    </defines>

    <pattern expression='\$'>
      <token>DOLLAR</token>
    </pattern>
    <pattern expression='{FArrow}'>
      <token>FORWARD_ARROW</token>
    </pattern>
    <pattern expression='{BArrow}'>
      <token>BACKWARD_ARROW</token>
    </pattern>
    <pattern expression='-'>
      <token>DASH</token>
    </pattern>
    <pattern expression='\|'>
      <token>PIPE</token>
    </pattern>
    <pattern expression='\('>
      <token>LEFT_PAREN</token>
    </pattern>
    <pattern expression='\)'>
      <token>RIGHT_PAREN</token>
    </pattern>
    <pattern expression='\['>
      <token>LEFT_SQUARE</token>
    </pattern>
    <pattern expression='\]'>
      <token>RIGHT_SQUARE</token>
    </pattern>
    <pattern expression='\{'>
      <token>LEFT_CURLY</token>
    </pattern>
    <pattern expression='\}'>
      <token>RIGHT_CURLY</token>
    </pattern>

    <pattern expression='\*'>
      <token>ASTERISK</token>
    </pattern>

    <pattern expression='\.'>
      <token>DOT</token>
    </pattern>

    <pattern expression='@'>
      <token>AT</token>
    </pattern>

    <pattern expression=','>
      <token>COMMA</token>
    </pattern>

    <pattern expression=';'>
      <token>SEMICOLON</token>
    </pattern>

    <pattern expression='{PureQName}'>
      <token>PURE_QNAME</token>
    </pattern>

    <pattern expression='{QName}'>
      <token>QNAME</token>
    </pattern>

    <pattern expression='{StringLiteral}'>
      <token>STRING_LITERAL</token>
    </pattern>

    <pattern expression='{Digit}+(\.{Digit}+)?([Ee][-+]?{Digit}+)?'>
      <token>NUMBER_LITERAL</token>
    </pattern>

    <pattern expression='true'>
      <token>TRUE</token>
    </pattern>

    <pattern expression='false'>
      <token>FALSE</token>
    </pattern>

    <!-- ignore all whitespace -->
    <pattern expression='{S}'/>

    <pattern expression='.'>
      <token>@ASCII@</token>
    </pattern>

  </lexer>

</bisongen>
