From 38b784d672ea6131b632072e7505cc3922536c48 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Mon, 17 Jun 2013 16:17:09 -0600 Subject: [PATCH] Support +/- unary operators for literals --- src/ol/expression/expression.js | 16 +++++ src/ol/expression/parser.js | 32 +++++++-- test/spec/ol/expression/expression.test.js | 77 ++++++++++++++++++---- 3 files changed, 105 insertions(+), 20 deletions(-) diff --git a/src/ol/expression/expression.js b/src/ol/expression/expression.js index a773b6cd8f..be55f011be 100644 --- a/src/ol/expression/expression.js +++ b/src/ol/expression/expression.js @@ -2,11 +2,27 @@ goog.provide('ol.expression'); goog.require('ol.Extent'); goog.require('ol.Feature'); +goog.require('ol.expression.Expression'); goog.require('ol.expression.Parser'); goog.require('ol.extent'); goog.require('ol.geom.GeometryType'); +/** + * Evaluate an expression with a feature. The feature attributes will be used + * as the evaluation scope. The `ol.expression.lib` functions will be used as + * function scope. The feature itself will be used as the `this` argument. + * + * @param {ol.expression.Expression} expr The expression. + * @param {ol.Feature} feature The feature. + * @return {*} The result of the expression. + */ +ol.expression.evaluateFeature = function(expr, feature) { + return expr.evaluate( + feature.getAttributes(), ol.expression.lib, feature); +}; + + /** * Parse an expression * @param {string} source The expression source (e.g. `'foo + 2'`). diff --git a/src/ol/expression/parser.js b/src/ol/expression/parser.js index 57627039b8..5b1544d496 100644 --- a/src/ol/expression/parser.js +++ b/src/ol/expression/parser.js @@ -199,16 +199,33 @@ ol.expression.Parser.prototype.createMemberExpression_ = function(object, /** - * Create a unary expression. + * Create a unary expression. The only true unary operator supported here is + * "!". For +/-, we apply the operator to literal expressions and return + * another literal. * - * @param {string} op Operator. + * @param {ol.expression.Token} op Operator. * @param {ol.expression.Expression} argument Expression. - * @return {ol.expression.Not} The logical not of the input expression. + * @return {ol.expression.Expression} The unary expression. * @private */ ol.expression.Parser.prototype.createUnaryExpression_ = function(op, argument) { - goog.asserts.assert(op === '!'); - return new ol.expression.Not(argument); + goog.asserts.assert(op.value === '!' || op.value === '+' || op.value === '-'); + var expr; + if (op.value === '!') { + expr = new ol.expression.Not(argument); + } else if (!(argument instanceof ol.expression.Literal)) { + throw new ol.expression.UnexpectedToken(op); + } else { + // we've got +/- literal + if (op.value === '+') { + expr = this.createLiteral_( + + /** @type {number|string|boolean|null} */ (argument.evaluate())); + } else { + expr = this.createLiteral_( + - /** @type {number|string|boolean|null} */ (argument.evaluate())); + } + } + return expr; }; @@ -440,10 +457,11 @@ ol.expression.Parser.prototype.parseUnaryExpression_ = function(lexer) { var operator = lexer.peek(); if (operator.type !== ol.expression.TokenType.PUNCTUATOR) { expr = this.parseLeftHandSideExpression_(lexer); - } else if (operator.value === '!') { + } else if (operator.value === '!' || operator.value === '-' || + operator.value === '+') { lexer.skip(); expr = this.parseUnaryExpression_(lexer); - expr = this.createUnaryExpression_('!', expr); + expr = this.createUnaryExpression_(operator, expr); } else { expr = this.parseLeftHandSideExpression_(lexer); } diff --git a/test/spec/ol/expression/expression.test.js b/test/spec/ol/expression/expression.test.js index d29700f31b..ab184ef344 100644 --- a/test/spec/ol/expression/expression.test.js +++ b/test/spec/ol/expression/expression.test.js @@ -524,12 +524,8 @@ describe('ol.expression.parse', function() { describe('ol.expression.lib', function() { - var lib = ol.expression.lib; var parse = ol.expression.parse; - - function evaluate(expression, feature) { - return expression.evaluate(feature.getAttributes(), lib, feature); - } + var evaluate = ol.expression.evaluateFeature; describe('extent()', function() { @@ -550,21 +546,73 @@ describe('ol.expression.lib', function() { var east = parse('extent(80, 100, -50, 50)'); var west = parse('extent(-100, -80, -50, 50)'); - expect(evaluate(north, nw), true); - expect(evaluate(south, nw), false); - expect(evaluate(east, nw), false); - expect(evaluate(west, nw), true); + it('evaluates to true for features within given extent', function() { - expect(evaluate(north, se), false); - expect(evaluate(south, se), true); - expect(evaluate(east, se), true); - expect(evaluate(west, se), false); + expect(evaluate(north, nw), true); + expect(evaluate(south, nw), false); + expect(evaluate(east, nw), false); + expect(evaluate(west, nw), true); + + expect(evaluate(north, se), false); + expect(evaluate(south, se), true); + expect(evaluate(east, se), true); + expect(evaluate(west, se), false); + + }); + + }); + + describe('geometryType()', function() { + + var point = new ol.Feature({ + geom: new ol.geom.Point([0, 0]) + }); + + var line = new ol.Feature({ + geom: new ol.geom.LineString([[180, -90], [-180, 90]]) + }); + + var poly = new ol.Feature({ + geom: new ol.geom.Polygon([[ + [180, -90], [0, -90], [0, 0], [180, 0], [180, -90] + ]]) + }); + + var isPoint = parse('geometryType("point")'); + var isLine = parse('geometryType("linestring")'); + var isPoly = parse('geometryType("polygon")'); + var pointOrPoly = parse('geometryType("point") || geometryType("polygon")'); + + it('distinguishes point features', function() { + expect(evaluate(isPoint, point), true); + expect(evaluate(isPoint, line), false); + expect(evaluate(isPoint, poly), false); + }); + + it('distinguishes line features', function() { + expect(evaluate(isLine, point), false); + expect(evaluate(isLine, line), true); + expect(evaluate(isLine, poly), false); + }); + + it('distinguishes polygon features', function() { + expect(evaluate(isPoly, point), false); + expect(evaluate(isPoly, line), false); + expect(evaluate(isPoly, poly), true); + }); + + it('can be composed in a logical expression', function() { + expect(evaluate(pointOrPoly, point), true); + expect(evaluate(pointOrPoly, line), false); + expect(evaluate(pointOrPoly, poly), true); + }); }); }); +goog.require('ol.Feature'); goog.require('ol.expression'); goog.require('ol.expression.Call'); goog.require('ol.expression.Comparison'); @@ -577,3 +625,6 @@ goog.require('ol.expression.Member'); goog.require('ol.expression.Not'); goog.require('ol.expression.TokenType'); goog.require('ol.expression.UnexpectedToken'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon');