diff --git a/src/ol/expr/expressions.js b/src/ol/expr/expressions.js index f98d595b8e..1b42603ee6 100644 --- a/src/ol/expr/expressions.js +++ b/src/ol/expr/expressions.js @@ -10,6 +10,7 @@ goog.provide('ol.expr.Math'); goog.provide('ol.expr.MathOp'); goog.provide('ol.expr.Member'); goog.provide('ol.expr.Not'); +goog.provide('ol.expr.ThisIdentifier'); @@ -624,3 +625,24 @@ ol.expr.Not.prototype.evaluate = function(opt_scope, opt_fns, opt_this) { ol.expr.Not.prototype.getArgument = function() { return this.argument_; }; + + + +/** + * An identifier for the 'this' keyword. + * + * @constructor + * @extends {ol.expr.Expression} + */ +ol.expr.ThisIdentifier = function() {}; +goog.inherits(ol.expr.ThisIdentifier, ol.expr.Expression); +goog.addSingletonGetter(ol.expr.ThisIdentifier); + + +/** + * @inheritDoc + */ +ol.expr.ThisIdentifier.prototype.evaluate = + function(opt_scope, opt_fns, opt_this) { + return opt_this; +}; diff --git a/src/ol/expr/lexer.js b/src/ol/expr/lexer.js index c1af520c34..41a69eb8c6 100644 --- a/src/ol/expr/lexer.js +++ b/src/ol/expr/lexer.js @@ -85,6 +85,7 @@ ol.expr.TokenType = { NUMERIC_LITERAL: 'Numeric', PUNCTUATOR: 'Punctuator', STRING_LITERAL: 'String', + THIS_IDENTIFIER: 'This', UNKNOWN: 'Unknown' }; @@ -515,7 +516,8 @@ ol.expr.Lexer.prototype.scanIdentifier_ = function(code) { if (id.length === 1) { type = ol.expr.TokenType.IDENTIFIER; } else if (this.isKeyword_(id)) { - type = ol.expr.TokenType.KEYWORD; + type = (id === 'this') ? + ol.expr.TokenType.THIS_IDENTIFIER : ol.expr.TokenType.KEYWORD; } else if (id === 'null') { type = ol.expr.TokenType.NULL_LITERAL; } else if (id === 'true' || id === 'false') { diff --git a/src/ol/expr/parser.js b/src/ol/expr/parser.js index f11cdd5603..03be0dd75b 100644 --- a/src/ol/expr/parser.js +++ b/src/ol/expr/parser.js @@ -30,6 +30,7 @@ goog.require('ol.expr.Math'); goog.require('ol.expr.MathOp'); goog.require('ol.expr.Member'); goog.require('ol.expr.Not'); +goog.require('ol.expr.ThisIdentifier'); goog.require('ol.expr.Token'); goog.require('ol.expr.TokenType'); goog.require('ol.expr.UnexpectedToken'); @@ -198,6 +199,16 @@ ol.expr.Parser.prototype.createMemberExpression_ = function(object, }; +/** + * Create a 'this' identifier. + * @return {ol.expr.ThisIdentifier} The 'this' identifier. + * @private + */ +ol.expr.Parser.prototype.createThisIdentifier_ = function() { + return ol.expr.ThisIdentifier.getInstance(); +}; + + /** * Create a unary expression. The only true unary operator supported here is * "!". For +/-, we apply the operator to literal expressions and return @@ -434,6 +445,8 @@ ol.expr.Parser.prototype.parsePrimaryExpression_ = function(lexer) { expr = this.createLiteral_(token.value === 'true'); } else if (type === ol.expr.TokenType.NULL_LITERAL) { expr = this.createLiteral_(null); + } else if (type === ol.expr.TokenType.THIS_IDENTIFIER) { + expr = this.createThisIdentifier_(); } else { throw new ol.expr.UnexpectedToken(token); } diff --git a/test/spec/ol/expr/expression.test.js b/test/spec/ol/expr/expression.test.js index 9b396897e4..b358ecb848 100644 --- a/test/spec/ol/expr/expression.test.js +++ b/test/spec/ol/expr/expression.test.js @@ -92,6 +92,12 @@ describe('ol.expr.parse()', function() { expect(expr.evaluate(scope)).to.be(42); }); + it('parses member expressions in the \'this\' scope', function() { + var expr = ol.expr.parse('this.foo'); + var thisScope = {foo: 'bar'}; + expect(expr.evaluate(undefined, undefined, thisScope)).to.be('bar'); + }); + it('consumes whitespace as expected', function() { var expr = ol.expr.parse(' foo . bar . baz '); expect(expr).to.be.a(ol.expr.Member); diff --git a/test/spec/ol/expr/expressions.test.js b/test/spec/ol/expr/expressions.test.js index c64ea7cd52..3a6f07a743 100644 --- a/test/spec/ol/expr/expressions.test.js +++ b/test/spec/ol/expr/expressions.test.js @@ -624,6 +624,25 @@ describe('ol.expr.Not', function() { }); +describe('ol.expr.ThisIdentifier', function() { + + describe('#getInstance()', function() { + it('has a getInstance method to return the singleton', function() { + expect(ol.expr.ThisIdentifier.getInstance()) + .to.be.a(ol.expr.ThisIdentifier); + }); + }); + + describe('#evaluate()', function() { + it('evaluates to the passed scope', function() { + expect(ol.expr.ThisIdentifier.getInstance() + .evaluate(undefined, undefined, 'foo')).to.be('foo'); + }); + }); + +}); + + goog.require('ol.expr.Call'); goog.require('ol.expr.Comparison'); goog.require('ol.expr.ComparisonOp'); @@ -636,3 +655,4 @@ goog.require('ol.expr.Math'); goog.require('ol.expr.MathOp'); goog.require('ol.expr.Member'); goog.require('ol.expr.Not'); +goog.require('ol.expr.ThisIdentifier');