New ThisIdentifier expression

This allows member expressions to use the 'this' keyword.
This commit is contained in:
ahocevar
2013-08-20 23:15:05 +02:00
parent 89052079b7
commit 4f2d37b6a3
5 changed files with 64 additions and 1 deletions

View File

@@ -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;
};

View File

@@ -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') {

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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');