Precedence grouping, you first.. no you (Odata parser)

Published on 2013-4-18

With expression parsing out of the way, there are just a few complications remaining,

I'm still missing a few key parts of this $filter feature, the next one is precedence grouping.

Do all this stuff before you do the other stuff

I don't think this will be too hard to parse given our already built-up knowledge of how to do precedence.

To the test..

test("/some/resource?$filterby=(Price div Price) mul 5 gt 10", "OData", function(result) {
  it("A filter should be present", function() {
     assert.notEqual(result.options.$filterby, null)
  it("Filter should be an instance of 'gt'", function() {
     assert.equal(result.options.$filterby[0], "gt")
  var lexpr = result.options.$filterby[1] 

  it("should be {expr} mul 5", function() {
    assert.equal(lexpr[0], "mul")
    assert.equal(lexpr[2], 5)

  it("should be {Price div Price}", function() {
    assert.equal(lexpr[1][0], "div")
    assert.equal(lexpr[1][1].name, "Price")
    assert.equal(lexpr[1][2].name, "Price" )

  it("rhr should be 10", function() {
     assert.equal(result.options.$filterby[2], 10)

This is actually the same test as in our Arithmetic Operators post, only we've surrounded the div expression because we want that to happen all by itself.

Well, Brackets actually have the highest precedence, so they'll need to go at the very end of our parser.

FilterByValue = 
| Number
| QuotedText
| PropertyPath
| GroupedPrecedenceExpression

GroupedPrecedenceExpression = 
  "(" spaces FilterByExpression:expr spaces ")" -> expr


Yes, it really is that simple. This is what comes of building up the definition of a parse-target out of little building blocks and then making a sequence of them.

If only all programs worked like this.

2015 © Rob Ashton. ALL Rights Reserved.