@@ -1,11 +1,8 @@
|
||||
goog.require('ol.Expression');
|
||||
goog.require('ol.Map');
|
||||
goog.require('ol.RendererHint');
|
||||
goog.require('ol.View2D');
|
||||
goog.require('ol.control.defaults');
|
||||
goog.require('ol.filter.Filter');
|
||||
goog.require('ol.filter.Geometry');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.parser.GeoJSON');
|
||||
goog.require('ol.proj');
|
||||
@@ -19,21 +16,17 @@ goog.require('ol.style.Text');
|
||||
|
||||
var style = new ol.style.Style({rules: [
|
||||
new ol.style.Rule({
|
||||
filter: new ol.filter.Filter(function(feature) {
|
||||
return feature.get('where') == 'outer';
|
||||
}),
|
||||
filter: 'where == "outer"',
|
||||
symbolizers: [
|
||||
new ol.style.Line({
|
||||
strokeColor: new ol.Expression('color'),
|
||||
strokeColor: ol.expr.parse('color'),
|
||||
strokeWidth: 4,
|
||||
opacity: 1
|
||||
})
|
||||
]
|
||||
}),
|
||||
new ol.style.Rule({
|
||||
filter: new ol.filter.Filter(function(feature) {
|
||||
return feature.get('where') == 'inner';
|
||||
}),
|
||||
filter: 'where == "inner"',
|
||||
symbolizers: [
|
||||
new ol.style.Line({
|
||||
strokeColor: '#013',
|
||||
@@ -41,14 +34,14 @@ var style = new ol.style.Style({rules: [
|
||||
opacity: 1
|
||||
}),
|
||||
new ol.style.Line({
|
||||
strokeColor: new ol.Expression('color'),
|
||||
strokeColor: ol.expr.parse('color'),
|
||||
strokeWidth: 2,
|
||||
opacity: 1
|
||||
})
|
||||
]
|
||||
}),
|
||||
new ol.style.Rule({
|
||||
filter: new ol.filter.Geometry(ol.geom.GeometryType.POINT),
|
||||
filter: 'geometryType("point")',
|
||||
symbolizers: [
|
||||
new ol.style.Shape({
|
||||
size: 40,
|
||||
@@ -56,7 +49,7 @@ var style = new ol.style.Style({rules: [
|
||||
}),
|
||||
new ol.style.Text({
|
||||
color: '#bada55',
|
||||
text: new ol.Expression('label'),
|
||||
text: ol.expr.parse('label'),
|
||||
fontFamily: 'Calibri,sans-serif',
|
||||
fontSize: 14
|
||||
})
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
goog.require('ol.Expression');
|
||||
goog.require('ol.Map');
|
||||
goog.require('ol.RendererHint');
|
||||
goog.require('ol.View2D');
|
||||
goog.require('ol.filter.Filter');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.layer.TileLayer');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.parser.GeoJSON');
|
||||
@@ -19,6 +18,11 @@ var raster = new ol.layer.TileLayer({
|
||||
source: new ol.source.MapQuestOpenAerial()
|
||||
});
|
||||
|
||||
// TODO: discuss scale dependent rules
|
||||
ol.expr.register('resolution', function() {
|
||||
return map.getView().getView2D().getResolution();
|
||||
});
|
||||
|
||||
var vector = new ol.layer.Vector({
|
||||
source: new ol.source.Vector({
|
||||
projection: ol.proj.get('EPSG:4326')
|
||||
@@ -32,13 +36,11 @@ var vector = new ol.layer.Vector({
|
||||
]
|
||||
}),
|
||||
new ol.style.Rule({
|
||||
filter: new ol.filter.Filter(function() {
|
||||
return map.getView().getResolution() < 5000;
|
||||
}),
|
||||
filter: 'resolution() < 5000',
|
||||
symbolizers: [
|
||||
new ol.style.Text({
|
||||
color: '#bada55',
|
||||
text: new ol.Expression('name'),
|
||||
text: ol.expr.parse('name'),
|
||||
fontFamily: 'Calibri,sans-serif',
|
||||
fontSize: 12
|
||||
})
|
||||
|
||||
@@ -519,53 +519,54 @@
|
||||
|
||||
/**
|
||||
* @typedef {Object} ol.style.IconOptions
|
||||
* @property {string|ol.Expression} url Icon image url.
|
||||
* @property {number|ol.Expression|undefined} width Width of the icon in pixels.
|
||||
* Default is the width of the icon image.
|
||||
* @property {number|ol.Expression|undefined} height Height of the icon in
|
||||
* pixels. Default is the height of the icon image.
|
||||
* @property {number|ol.Expression|undefined} opacity Icon opacity (0-1).
|
||||
* @property {number|ol.Expression|undefined} rotation Rotation in degrees
|
||||
* (0-360).
|
||||
* @property {string|ol.expr.Expression} url Icon image url.
|
||||
* @property {number|ol.expr.Expression|undefined} width Width of the icon
|
||||
* in pixels. Default is the width of the icon image.
|
||||
* @property {number|ol.expr.Expression|undefined} height Height of the
|
||||
* icon in pixels. Default is the height of the icon image.
|
||||
* @property {number|ol.expr.Expression|undefined} opacity Icon opacity
|
||||
* (0-1).
|
||||
* @property {number|ol.expr.Expression|undefined} rotation Rotation in
|
||||
* degrees (0-360).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ol.style.LineOptions
|
||||
* @property {string|ol.Expression|undefined} strokeColor Stroke color as hex
|
||||
* color code.
|
||||
* @property {number|ol.Expression|undefined} strokeWidth Stroke width in
|
||||
* pixels.
|
||||
* @property {number|ol.Expression|undefined} opacity Opacity (0-1).
|
||||
* @property {string|ol.expr.Expression|undefined} strokeColor Stroke
|
||||
* color as hex color code.
|
||||
* @property {number|ol.expr.Expression|undefined} strokeWidth Stroke
|
||||
* width in pixels.
|
||||
* @property {number|ol.expr.Expression|undefined} opacity Opacity (0-1).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ol.style.PolygonOptions
|
||||
* @property {string|ol.Expression|undefined} fillColor Fill color as hex color
|
||||
* code.
|
||||
* @property {string|ol.Expression|undefined} strokeColor Stroke color as hex
|
||||
* color code.
|
||||
* @property {number|ol.Expression|undefined} strokeWidth Stroke width in
|
||||
* pixels.
|
||||
* @property {number|ol.Expression|undefined} opacity Opacity (0-1).
|
||||
* @property {string|ol.expr.Expression|undefined} fillColor Fill color as
|
||||
* hex color code.
|
||||
* @property {string|ol.expr.Expression|undefined} strokeColor Stroke
|
||||
* color as hex color code.
|
||||
* @property {number|ol.expr.Expression|undefined} strokeWidth Stroke
|
||||
* width in pixels.
|
||||
* @property {number|ol.expr.Expression|undefined} opacity Opacity (0-1).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ol.style.RuleOptions
|
||||
* @property {ol.filter.Filter|undefined} filter Filter.
|
||||
* @property {ol.expr.Expression|string|undefined} filter Filter.
|
||||
* @property {Array.<ol.style.Symbolizer>|undefined} symbolizers Symbolizers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ol.style.ShapeOptions
|
||||
* @property {ol.style.ShapeType|undefined} type Type.
|
||||
* @property {number|ol.Expression|undefined} size Size in pixels.
|
||||
* @property {string|ol.Expression|undefined} fillColor Fill color as hex color
|
||||
* code.
|
||||
* @property {string|ol.Expression|undefined} strokeColor Stroke color as hex
|
||||
* color code.
|
||||
* @property {number|ol.Expression|undefined} strokeWidth Stroke width in
|
||||
* pixels.
|
||||
* @property {number|ol.Expression|undefined} opacity Opacity (0-1).
|
||||
* @property {number|ol.expr.Expression|undefined} size Size in pixels.
|
||||
* @property {string|ol.expr.Expression|undefined} fillColor Fill color as
|
||||
* hex color code.
|
||||
* @property {string|ol.expr.Expression|undefined} strokeColor Stroke
|
||||
* color as hex color code.
|
||||
* @property {number|ol.expr.Expression|undefined} strokeWidth Stroke
|
||||
* width in pixels.
|
||||
* @property {number|ol.expr.Expression|undefined} opacity Opacity (0-1).
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -575,11 +576,11 @@
|
||||
|
||||
/**
|
||||
* @typedef {Object} ol.style.TextOptions
|
||||
* @property {string|ol.Expression|undefined} color Color.
|
||||
* @property {string|ol.Expression|undefined} fontFamily Font family.
|
||||
* @property {number|ol.Expression|undefined} fontSize Font size in pixels.
|
||||
* @property {string|ol.Expression} text Text for the label.
|
||||
* @property {number|ol.Expression|undefined} opacity Opacity (0-1).
|
||||
* @property {string|ol.expr.Expression|undefined} color Color.
|
||||
* @property {string|ol.expr.Expression|undefined} fontFamily Font family.
|
||||
* @property {number|ol.expr.Expression|undefined} fontSize Font size in pixels.
|
||||
* @property {string|ol.expr.Expression} text Text for the label.
|
||||
* @property {number|ol.expr.Expression|undefined} opacity Opacity (0-1).
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
3
src/ol/expr.jsdoc
Normal file
3
src/ol/expr.jsdoc
Normal file
@@ -0,0 +1,3 @@
|
||||
/**
|
||||
* @namespace ol.expr
|
||||
*/
|
||||
2
src/ol/expr/expression.exports
Normal file
2
src/ol/expr/expression.exports
Normal file
@@ -0,0 +1,2 @@
|
||||
@exportSymbol ol.expr.parse
|
||||
@exportSymbol ol.expr.register
|
||||
158
src/ol/expr/expression.js
Normal file
158
src/ol/expr/expression.js
Normal file
@@ -0,0 +1,158 @@
|
||||
goog.provide('ol.expr');
|
||||
goog.provide('ol.expr.functions');
|
||||
|
||||
goog.require('ol.Extent');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.expr.Call');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Identifier');
|
||||
goog.require('ol.expr.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.expr.lib` functions will be used as
|
||||
* function scope. The feature itself will be used as the `this` argument.
|
||||
*
|
||||
* @param {ol.expr.Expression} expr The expression.
|
||||
* @param {ol.Feature=} opt_feature The feature.
|
||||
* @return {*} The result of the expression.
|
||||
*/
|
||||
ol.expr.evaluateFeature = function(expr, opt_feature) {
|
||||
var result;
|
||||
if (goog.isDef(opt_feature)) {
|
||||
result = expr.evaluate(
|
||||
opt_feature.getAttributes(), ol.expr.lib, opt_feature);
|
||||
} else {
|
||||
result = expr.evaluate();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse an expression.
|
||||
* @param {string} source The expression source (e.g. `'foo + 2'`).
|
||||
* @return {ol.expr.Expression} An expression instance that can be
|
||||
* evaluated within some scope to provide a value.
|
||||
*/
|
||||
ol.expr.parse = function(source) {
|
||||
var parser = new ol.expr.Parser();
|
||||
return parser.parse(source);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Register a library function to be used in expressions.
|
||||
* @param {string} name The function name (e.g. 'myFunc').
|
||||
* @param {function(this:ol.Feature)} func The function to be called in an
|
||||
* expression. This function will be called with a feature as the `this`
|
||||
* argument when the expression is evaluated in the context of a features.
|
||||
*/
|
||||
ol.expr.register = function(name, func) {
|
||||
ol.expr.lib[name] = func;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether an expression is a call expression that calls one of the
|
||||
* `ol.expr.lib` functions.
|
||||
*
|
||||
* @param {ol.expr.Expression} expr The candidate expression.
|
||||
* @return {string|undefined} If the candidate expression is a call to a lib
|
||||
* function, the return will be the function name. If not, the return will be
|
||||
* `undefined`.
|
||||
*/
|
||||
ol.expr.isLibCall = function(expr) {
|
||||
var name;
|
||||
if (expr instanceof ol.expr.Call) {
|
||||
var callee = expr.getCallee();
|
||||
if (callee instanceof ol.expr.Identifier) {
|
||||
name = callee.getName();
|
||||
if (!ol.expr.lib.hasOwnProperty(name)) {
|
||||
name = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Library of well-known functions. These are available to expressions parsed
|
||||
* with `ol.expr.parse`.
|
||||
*
|
||||
* @type {Object.<string, function(...)>}
|
||||
*/
|
||||
ol.expr.lib = {};
|
||||
|
||||
|
||||
/**
|
||||
* Enumeration of library function names.
|
||||
*
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.expr.functions = {
|
||||
EXTENT: 'extent',
|
||||
FID: 'fid',
|
||||
GEOMETRY_TYPE: 'geometryType'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a feature's extent intersects the provided extent.
|
||||
* @param {number} minX Minimum x-coordinate value.
|
||||
* @param {number} maxX Maximum x-coordinate value.
|
||||
* @param {number} minY Minimum y-coordinate value.
|
||||
* @param {number} maxY Maximum y-coordinate value.
|
||||
* @return {boolean} The provided extent intersects the feature's extent.
|
||||
* @this {ol.Feature}
|
||||
*/
|
||||
ol.expr.lib[ol.expr.functions.EXTENT] = function(minX, maxX, minY, maxY) {
|
||||
var intersects = false;
|
||||
var geometry = this.getGeometry();
|
||||
if (geometry) {
|
||||
intersects = ol.extent.intersects(geometry.getBounds(),
|
||||
[minX, maxX, minY, maxY]);
|
||||
}
|
||||
return intersects;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the feature identifier matches any of the provided values.
|
||||
* @param {...string} var_args Feature identifiers.
|
||||
* @return {boolean} The feature's identifier matches one of the given values.
|
||||
* @this {ol.Feature}
|
||||
*/
|
||||
ol.expr.lib[ol.expr.functions.FID] = function(var_args) {
|
||||
var matches = false;
|
||||
var id = this.getFeatureId();
|
||||
if (goog.isDef(id)) {
|
||||
for (var i = 0, ii = arguments.length; i < ii; ++i) {
|
||||
if (arguments[i] === id) {
|
||||
matches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a feature's default geometry is of the given type.
|
||||
* @param {ol.geom.GeometryType} type Geometry type.
|
||||
* @return {boolean} The feature's default geometry is of the given type.
|
||||
* @this {ol.Feature}
|
||||
*/
|
||||
ol.expr.lib[ol.expr.functions.GEOMETRY_TYPE] = function(type) {
|
||||
var same = false;
|
||||
var geometry = this.getGeometry();
|
||||
if (geometry) {
|
||||
same = geometry.getType() === type;
|
||||
}
|
||||
return same;
|
||||
};
|
||||
631
src/ol/expr/expressions.js
Normal file
631
src/ol/expr/expressions.js
Normal file
@@ -0,0 +1,631 @@
|
||||
goog.provide('ol.expr.Call');
|
||||
goog.provide('ol.expr.Comparison');
|
||||
goog.provide('ol.expr.ComparisonOp');
|
||||
goog.provide('ol.expr.Expression');
|
||||
goog.provide('ol.expr.Identifier');
|
||||
goog.provide('ol.expr.Literal');
|
||||
goog.provide('ol.expr.Logical');
|
||||
goog.provide('ol.expr.LogicalOp');
|
||||
goog.provide('ol.expr.Math');
|
||||
goog.provide('ol.expr.MathOp');
|
||||
goog.provide('ol.expr.Member');
|
||||
goog.provide('ol.expr.Not');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Base class for all expressions. Instances of ol.expr.Expression
|
||||
* correspond to a limited set of ECMAScript 5.1 expressions.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11
|
||||
*
|
||||
* This base class should not be constructed directly. Instead, use one of
|
||||
* the subclass constructors.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
ol.expr.Expression = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate the expression and return the result.
|
||||
*
|
||||
* @param {Object=} opt_scope Evaluation scope. All properties of this object
|
||||
* will be available as variables when evaluating the expression. If not
|
||||
* provided, `null` will be used.
|
||||
* @param {Object=} opt_fns Optional scope for looking up functions. If not
|
||||
* provided, functions will be looked in the evaluation scope.
|
||||
* @param {Object=} opt_this Object to use as this when evaluating call
|
||||
* expressions. If not provided, `this` will resolve to a new object.
|
||||
* @return {*} Result of the expression.
|
||||
*/
|
||||
ol.expr.Expression.prototype.evaluate = goog.abstractMethod;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A call expression (e.g. `foo(bar)`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {ol.expr.Expression} callee An expression that resolves to a
|
||||
* function.
|
||||
* @param {Array.<ol.expr.Expression>} args Arguments.
|
||||
*/
|
||||
ol.expr.Call = function(callee, args) {
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.callee_ = callee;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.expr.Expression>}
|
||||
* @private
|
||||
*/
|
||||
this.args_ = args;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Call, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Call.prototype.evaluate = function(opt_scope, opt_fns, opt_this) {
|
||||
var fnScope = goog.isDefAndNotNull(opt_fns) ? opt_fns : opt_scope;
|
||||
var fn = this.callee_.evaluate(fnScope);
|
||||
if (!fn || !goog.isFunction(fn)) {
|
||||
throw new Error('Expected function but found ' + fn);
|
||||
}
|
||||
var thisArg = goog.isDef(opt_this) ? opt_this : {};
|
||||
|
||||
var len = this.args_.length;
|
||||
var values = new Array(len);
|
||||
for (var i = 0; i < len; ++i) {
|
||||
values[i] = this.args_[i].evaluate(opt_scope, opt_fns, opt_this);
|
||||
}
|
||||
return fn.apply(thisArg, values);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the argument list.
|
||||
* @return {Array.<ol.expr.Expression>} The argument.
|
||||
*/
|
||||
ol.expr.Call.prototype.getArgs = function() {
|
||||
return this.args_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the callee expression.
|
||||
* @return {ol.expr.Expression} The callee expression.
|
||||
*/
|
||||
ol.expr.Call.prototype.getCallee = function() {
|
||||
return this.callee_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.expr.ComparisonOp = {
|
||||
EQ: '==',
|
||||
NEQ: '!=',
|
||||
STRICT_EQ: '===',
|
||||
STRICT_NEQ: '!==',
|
||||
GT: '>',
|
||||
LT: '<',
|
||||
GTE: '>=',
|
||||
LTE: '<='
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A comparison expression (e.g. `foo >= 42`, `bar != "chicken"`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {ol.expr.ComparisonOp} operator Comparison operator.
|
||||
* @param {ol.expr.Expression} left Left expression.
|
||||
* @param {ol.expr.Expression} right Right expression.
|
||||
*/
|
||||
ol.expr.Comparison = function(operator, left, right) {
|
||||
|
||||
/**
|
||||
* @type {ol.expr.ComparisonOp}
|
||||
* @private
|
||||
*/
|
||||
this.operator_ = operator;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.left_ = left;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.right_ = right;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Comparison, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a given string is a valid comparison operator.
|
||||
* @param {string} candidate Operator to test.
|
||||
* @return {boolean} The operator is valid.
|
||||
*/
|
||||
ol.expr.Comparison.isValidOp = (function() {
|
||||
var valid = {};
|
||||
for (var key in ol.expr.ComparisonOp) {
|
||||
valid[ol.expr.ComparisonOp[key]] = true;
|
||||
}
|
||||
return function isValidOp(candidate) {
|
||||
return !!valid[candidate];
|
||||
};
|
||||
}());
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Comparison.prototype.evaluate = function(opt_scope, opt_fns, opt_this) {
|
||||
var result;
|
||||
var rightVal = this.right_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
var leftVal = this.left_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
|
||||
var op = this.operator_;
|
||||
if (op === ol.expr.ComparisonOp.EQ) {
|
||||
result = leftVal == rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.NEQ) {
|
||||
result = leftVal != rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.STRICT_EQ) {
|
||||
result = leftVal === rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.STRICT_NEQ) {
|
||||
result = leftVal !== rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.GT) {
|
||||
result = leftVal > rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.LT) {
|
||||
result = leftVal < rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.GTE) {
|
||||
result = leftVal >= rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.LTE) {
|
||||
result = leftVal <= rightVal;
|
||||
} else {
|
||||
throw new Error('Unsupported comparison operator: ' + this.operator_);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the comparison operator.
|
||||
* @return {string} The comparison operator.
|
||||
*/
|
||||
ol.expr.Comparison.prototype.getOperator = function() {
|
||||
return this.operator_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the left expression.
|
||||
* @return {ol.expr.Expression} The left expression.
|
||||
*/
|
||||
ol.expr.Comparison.prototype.getLeft = function() {
|
||||
return this.left_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the right expression.
|
||||
* @return {ol.expr.Expression} The right expression.
|
||||
*/
|
||||
ol.expr.Comparison.prototype.getRight = function() {
|
||||
return this.right_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An identifier expression (e.g. `foo`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {string} name An identifier name.
|
||||
*/
|
||||
ol.expr.Identifier = function(name) {
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.name_ = name;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Identifier, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Identifier.prototype.evaluate = function(opt_scope) {
|
||||
if (!goog.isDefAndNotNull(opt_scope)) {
|
||||
throw new Error('Attempt to evaluate identifier with no scope');
|
||||
}
|
||||
return opt_scope[this.name_];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the identifier name.
|
||||
* @return {string} The identifier name.
|
||||
*/
|
||||
ol.expr.Identifier.prototype.getName = function() {
|
||||
return this.name_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A literal expression (e.g. `"chicken"`, `42`, `true`, `null`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {string|number|boolean|null} value A literal value.
|
||||
*/
|
||||
ol.expr.Literal = function(value) {
|
||||
|
||||
/**
|
||||
* @type {string|number|boolean|null}
|
||||
* @private
|
||||
*/
|
||||
this.value_ = value;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Literal, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Literal.prototype.evaluate = function() {
|
||||
return this.value_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the literal value.
|
||||
* @return {string|number|boolean|null} The literal value.
|
||||
*/
|
||||
ol.expr.Literal.prototype.getValue = function() {
|
||||
return this.value_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.expr.LogicalOp = {
|
||||
AND: '&&',
|
||||
OR: '||'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A binary logical expression (e.g. `foo && bar`, `bar || "chicken"`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {ol.expr.LogicalOp} operator Logical operator.
|
||||
* @param {ol.expr.Expression} left Left expression.
|
||||
* @param {ol.expr.Expression} right Right expression.
|
||||
*/
|
||||
ol.expr.Logical = function(operator, left, right) {
|
||||
|
||||
/**
|
||||
* @type {ol.expr.LogicalOp}
|
||||
* @private
|
||||
*/
|
||||
this.operator_ = operator;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.left_ = left;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.right_ = right;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Logical, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a given string is a valid logical operator.
|
||||
* @param {string} candidate Operator to test.
|
||||
* @return {boolean} The operator is valid.
|
||||
*/
|
||||
ol.expr.Logical.isValidOp = (function() {
|
||||
var valid = {};
|
||||
for (var key in ol.expr.LogicalOp) {
|
||||
valid[ol.expr.LogicalOp[key]] = true;
|
||||
}
|
||||
return function isValidOp(candidate) {
|
||||
return !!valid[candidate];
|
||||
};
|
||||
}());
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Logical.prototype.evaluate = function(opt_scope, opt_fns,
|
||||
opt_this) {
|
||||
var result;
|
||||
var rightVal = this.right_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
var leftVal = this.left_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
|
||||
if (this.operator_ === ol.expr.LogicalOp.AND) {
|
||||
result = leftVal && rightVal;
|
||||
} else if (this.operator_ === ol.expr.LogicalOp.OR) {
|
||||
result = leftVal || rightVal;
|
||||
} else {
|
||||
throw new Error('Unsupported logical operator: ' + this.operator_);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the logical operator.
|
||||
* @return {string} The logical operator.
|
||||
*/
|
||||
ol.expr.Logical.prototype.getOperator = function() {
|
||||
return this.operator_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the left expression.
|
||||
* @return {ol.expr.Expression} The left expression.
|
||||
*/
|
||||
ol.expr.Logical.prototype.getLeft = function() {
|
||||
return this.left_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the right expression.
|
||||
* @return {ol.expr.Expression} The right expression.
|
||||
*/
|
||||
ol.expr.Logical.prototype.getRight = function() {
|
||||
return this.right_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.expr.MathOp = {
|
||||
ADD: '+',
|
||||
SUBTRACT: '-',
|
||||
MULTIPLY: '*',
|
||||
DIVIDE: '/',
|
||||
MOD: '%'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A math expression (e.g. `foo + 42`, `bar % 10`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {ol.expr.MathOp} operator Math operator.
|
||||
* @param {ol.expr.Expression} left Left expression.
|
||||
* @param {ol.expr.Expression} right Right expression.
|
||||
*/
|
||||
ol.expr.Math = function(operator, left, right) {
|
||||
|
||||
/**
|
||||
* @type {ol.expr.MathOp}
|
||||
* @private
|
||||
*/
|
||||
this.operator_ = operator;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.left_ = left;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.right_ = right;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Math, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a given string is a valid math operator.
|
||||
* @param {string} candidate Operator to test.
|
||||
* @return {boolean} The operator is valid.
|
||||
*/
|
||||
ol.expr.Math.isValidOp = (function() {
|
||||
var valid = {};
|
||||
for (var key in ol.expr.MathOp) {
|
||||
valid[ol.expr.MathOp[key]] = true;
|
||||
}
|
||||
return function isValidOp(candidate) {
|
||||
return !!valid[candidate];
|
||||
};
|
||||
}());
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Math.prototype.evaluate = function(opt_scope, opt_fns, opt_this) {
|
||||
var result;
|
||||
var rightVal = this.right_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
var leftVal = this.left_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
/**
|
||||
* TODO: throw if rightVal, leftVal not numbers - this would require the use
|
||||
* of a concat function for strings but it would let us serialize these as
|
||||
* math functions where available elsewhere
|
||||
*/
|
||||
|
||||
var op = this.operator_;
|
||||
if (op === ol.expr.MathOp.ADD) {
|
||||
result = leftVal + rightVal;
|
||||
} else if (op === ol.expr.MathOp.SUBTRACT) {
|
||||
result = Number(leftVal) - Number(rightVal);
|
||||
} else if (op === ol.expr.MathOp.MULTIPLY) {
|
||||
result = Number(leftVal) * Number(rightVal);
|
||||
} else if (op === ol.expr.MathOp.DIVIDE) {
|
||||
result = Number(leftVal) / Number(rightVal);
|
||||
} else if (op === ol.expr.MathOp.MOD) {
|
||||
result = Number(leftVal) % Number(rightVal);
|
||||
} else {
|
||||
throw new Error('Unsupported math operator: ' + this.operator_);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the math operator.
|
||||
* @return {string} The math operator.
|
||||
*/
|
||||
ol.expr.Math.prototype.getOperator = function() {
|
||||
return this.operator_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the left expression.
|
||||
* @return {ol.expr.Expression} The left expression.
|
||||
*/
|
||||
ol.expr.Math.prototype.getLeft = function() {
|
||||
return this.left_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the right expression.
|
||||
* @return {ol.expr.Expression} The right expression.
|
||||
*/
|
||||
ol.expr.Math.prototype.getRight = function() {
|
||||
return this.right_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A member expression (e.g. `foo.bar`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {ol.expr.Expression} object An expression that resolves to an
|
||||
* object.
|
||||
* @param {ol.expr.Identifier} property Identifier with name of property.
|
||||
*/
|
||||
ol.expr.Member = function(object, property) {
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.object_ = object;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Identifier}
|
||||
* @private
|
||||
*/
|
||||
this.property_ = property;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Member, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Member.prototype.evaluate = function(opt_scope, opt_fns,
|
||||
opt_this) {
|
||||
var obj = this.object_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
if (!goog.isObject(obj)) {
|
||||
throw new Error('Expected member expression to evaluate to an object ' +
|
||||
'but got ' + obj);
|
||||
}
|
||||
return this.property_.evaluate(/** @type {Object} */ (obj));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the object expression.
|
||||
* @return {ol.expr.Expression} The object.
|
||||
*/
|
||||
ol.expr.Member.prototype.getObject = function() {
|
||||
return this.object_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the property expression.
|
||||
* @return {ol.expr.Identifier} The property.
|
||||
*/
|
||||
ol.expr.Member.prototype.getProperty = function() {
|
||||
return this.property_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A logical not expression (e.g. `!foo`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {ol.expr.Expression} argument Expression to negate.
|
||||
*/
|
||||
ol.expr.Not = function(argument) {
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.argument_ = argument;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Not, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Not.prototype.evaluate = function(opt_scope, opt_fns, opt_this) {
|
||||
return !this.argument_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the argument (the negated expression).
|
||||
* @return {ol.expr.Expression} The argument.
|
||||
*/
|
||||
ol.expr.Not.prototype.getArgument = function() {
|
||||
return this.argument_;
|
||||
};
|
||||
900
src/ol/expr/lexer.js
Normal file
900
src/ol/expr/lexer.js
Normal file
@@ -0,0 +1,900 @@
|
||||
/**
|
||||
* The logic and naming of methods here are inspired by Esprima (BSD Licensed).
|
||||
* Esprima (http://esprima.org) includes the following copyright notices:
|
||||
*
|
||||
* Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
* Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
|
||||
* Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
* Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
|
||||
* Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
|
||||
* Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
|
||||
* Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
|
||||
* Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
|
||||
* Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
*/
|
||||
|
||||
goog.provide('ol.expr.Char'); // TODO: remove this - see #785
|
||||
goog.provide('ol.expr.Lexer');
|
||||
goog.provide('ol.expr.Token');
|
||||
goog.provide('ol.expr.TokenType');
|
||||
goog.provide('ol.expr.UnexpectedToken');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.debug.Error');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
ol.expr.Char = {
|
||||
AMPERSAND: 38,
|
||||
BACKSLASH: 92,
|
||||
BANG: 33, // !
|
||||
CARRIAGE_RETURN: 13,
|
||||
COMMA: 44,
|
||||
DIGIT_0: 48,
|
||||
DIGIT_7: 55,
|
||||
DIGIT_9: 57,
|
||||
DOLLAR: 36,
|
||||
DOUBLE_QUOTE: 34,
|
||||
DOT: 46,
|
||||
EQUAL: 61,
|
||||
FORM_FEED: 0xC,
|
||||
GREATER: 62,
|
||||
LEFT_PAREN: 40,
|
||||
LESS: 60,
|
||||
LINE_FEED: 10,
|
||||
LINE_SEPARATOR: 0x2028,
|
||||
LOWER_A: 97,
|
||||
LOWER_E: 101,
|
||||
LOWER_F: 102,
|
||||
LOWER_X: 120,
|
||||
LOWER_Z: 122,
|
||||
MINUS: 45,
|
||||
NONBREAKING_SPACE: 0xA0,
|
||||
PARAGRAPH_SEPARATOR: 0x2029,
|
||||
PERCENT: 37,
|
||||
PIPE: 124,
|
||||
PLUS: 43,
|
||||
RIGHT_PAREN: 41,
|
||||
SINGLE_QUOTE: 39,
|
||||
SLASH: 47,
|
||||
SPACE: 32,
|
||||
STAR: 42,
|
||||
TAB: 9,
|
||||
TILDE: 126,
|
||||
UNDERSCORE: 95,
|
||||
UPPER_A: 65,
|
||||
UPPER_E: 69,
|
||||
UPPER_F: 70,
|
||||
UPPER_X: 88,
|
||||
UPPER_Z: 90,
|
||||
VERTICAL_TAB: 0xB
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.expr.TokenType = {
|
||||
BOOLEAN_LITERAL: 'Boolean',
|
||||
EOF: '<end>',
|
||||
IDENTIFIER: 'Identifier',
|
||||
KEYWORD: 'Keyword',
|
||||
NULL_LITERAL: 'Null',
|
||||
NUMERIC_LITERAL: 'Numeric',
|
||||
PUNCTUATOR: 'Punctuator',
|
||||
STRING_LITERAL: 'String',
|
||||
UNKNOWN: 'Unknown'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {{type: (ol.expr.TokenType),
|
||||
* value: (string|number|boolean|null),
|
||||
* index: (number)}}
|
||||
*/
|
||||
ol.expr.Token;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Lexer constructor. Provides a tokenizer for a limited subset of ECMAScript
|
||||
* 5.1 expressions (http://www.ecma-international.org/ecma-262/5.1/#sec-11).
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} source Source code.
|
||||
*/
|
||||
ol.expr.Lexer = function(source) {
|
||||
|
||||
/**
|
||||
* Source code.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.source_ = source;
|
||||
|
||||
/**
|
||||
* Source length.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.length_ = source.length;
|
||||
|
||||
/**
|
||||
* Current character index.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.index_ = 0;
|
||||
|
||||
/**
|
||||
* Next character index (only set after `peek`ing).
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.nextIndex_ = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan the next token and throw if it isn't a punctuator that matches input.
|
||||
* @param {string} value Token value.
|
||||
*/
|
||||
ol.expr.Lexer.prototype.expect = function(value) {
|
||||
var match = this.match(value);
|
||||
if (!match) {
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: this.getCurrentChar_(),
|
||||
index: this.index_
|
||||
});
|
||||
}
|
||||
this.skip();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Increment the current character index.
|
||||
*
|
||||
* @param {number} delta Delta by which the index is advanced.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.increment_ = function(delta) {
|
||||
this.index_ += delta;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.3
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is a decimal digit.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isDecimalDigit_ = function(code) {
|
||||
return (
|
||||
code >= ol.expr.Char.DIGIT_0 &&
|
||||
code <= ol.expr.Char.DIGIT_9);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6.1.2
|
||||
*
|
||||
* @param {string} id A string identifier.
|
||||
* @return {boolean} The identifier is a future reserved word.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isFutureReservedWord_ = function(id) {
|
||||
return (
|
||||
id === 'class' ||
|
||||
id === 'enum' ||
|
||||
id === 'export' ||
|
||||
id === 'extends' ||
|
||||
id === 'import' ||
|
||||
id === 'super');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.3
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is a hex digit.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isHexDigit_ = function(code) {
|
||||
return this.isDecimalDigit_(code) ||
|
||||
(code >= ol.expr.Char.LOWER_A &&
|
||||
code <= ol.expr.Char.LOWER_F) ||
|
||||
(code >= ol.expr.Char.UPPER_A &&
|
||||
code <= ol.expr.Char.UPPER_F);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6
|
||||
* Doesn't deal with non-ascii identifiers.
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is a valid identifier part.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isIdentifierPart_ = function(code) {
|
||||
return this.isIdentifierStart_(code) ||
|
||||
(code >= ol.expr.Char.DIGIT_0 &&
|
||||
code <= ol.expr.Char.DIGIT_9);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6
|
||||
* Doesn't yet deal with non-ascii identifiers.
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is a valid identifier start.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isIdentifierStart_ = function(code) {
|
||||
return (code === ol.expr.Char.DOLLAR) ||
|
||||
(code === ol.expr.Char.UNDERSCORE) ||
|
||||
(code >= ol.expr.Char.UPPER_A &&
|
||||
code <= ol.expr.Char.UPPER_Z) ||
|
||||
(code >= ol.expr.Char.LOWER_A &&
|
||||
code <= ol.expr.Char.LOWER_Z);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the given identifier is an ECMAScript keyword. These cannot
|
||||
* be used as identifiers in programs. There is no real reason these could not
|
||||
* be used in ol.exprs - but they are reserved for future use.
|
||||
*
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6.1.1
|
||||
*
|
||||
* @param {string} id Identifier.
|
||||
* @return {boolean} The identifier is a keyword.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isKeyword_ = function(id) {
|
||||
return (
|
||||
id === 'break' ||
|
||||
id === 'case' ||
|
||||
id === 'catch' ||
|
||||
id === 'continue' ||
|
||||
id === 'debugger' ||
|
||||
id === 'default' ||
|
||||
id === 'delete' ||
|
||||
id === 'do' ||
|
||||
id === 'else' ||
|
||||
id === 'finally' ||
|
||||
id === 'for' ||
|
||||
id === 'function' ||
|
||||
id === 'if' ||
|
||||
id === 'in' ||
|
||||
id === 'instanceof' ||
|
||||
id === 'new' ||
|
||||
id === 'return' ||
|
||||
id === 'switch' ||
|
||||
id === 'this' ||
|
||||
id === 'throw' ||
|
||||
id === 'try' ||
|
||||
id === 'typeof' ||
|
||||
id === 'var' ||
|
||||
id === 'void' ||
|
||||
id === 'while' ||
|
||||
id === 'with');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.3
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is a line terminator.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isLineTerminator_ = function(code) {
|
||||
return (code === ol.expr.Char.LINE_FEED) ||
|
||||
(code === ol.expr.Char.CARRIAGE_RETURN) ||
|
||||
(code === ol.expr.Char.LINE_SEPARATOR) ||
|
||||
(code === ol.expr.Char.PARAGRAPH_SEPARATOR);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.3
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is an octal digit.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isOctalDigit_ = function(code) {
|
||||
return (
|
||||
code >= ol.expr.Char.DIGIT_0 &&
|
||||
code <= ol.expr.Char.DIGIT_7);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.2
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is whitespace.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isWhitespace_ = function(code) {
|
||||
return (code === ol.expr.Char.SPACE) ||
|
||||
(code === ol.expr.Char.TAB) ||
|
||||
(code === ol.expr.Char.VERTICAL_TAB) ||
|
||||
(code === ol.expr.Char.FORM_FEED) ||
|
||||
(code === ol.expr.Char.NONBREAKING_SPACE) ||
|
||||
(code >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005' +
|
||||
'\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'
|
||||
.indexOf(String.fromCharCode(code)) > 0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the unicode of the character at the given offset from the current index.
|
||||
*
|
||||
* @param {number} delta Offset from current index.
|
||||
* @return {number} The character code.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.getCharCode_ = function(delta) {
|
||||
return this.source_.charCodeAt(this.index_ + delta);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the character at the current index.
|
||||
*
|
||||
* @return {string} The current character.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.getCurrentChar_ = function() {
|
||||
return this.source_[this.index_];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the unicode of the character at the current index.
|
||||
*
|
||||
* @return {number} The current character code.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.getCurrentCharCode_ = function() {
|
||||
return this.getCharCode_(0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the upcoming token matches the given punctuator.
|
||||
* @param {string} value Punctuator value.
|
||||
* @return {boolean} The token matches.
|
||||
*/
|
||||
ol.expr.Lexer.prototype.match = function(value) {
|
||||
var token = this.peek();
|
||||
return (
|
||||
token.type === ol.expr.TokenType.PUNCTUATOR &&
|
||||
token.value === value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan the next token.
|
||||
*
|
||||
* @return {ol.expr.Token} Next token.
|
||||
*/
|
||||
ol.expr.Lexer.prototype.next = function() {
|
||||
var code = this.skipWhitespace_();
|
||||
|
||||
if (this.index_ >= this.length_) {
|
||||
return {
|
||||
type: ol.expr.TokenType.EOF,
|
||||
value: null,
|
||||
index: this.index_
|
||||
};
|
||||
}
|
||||
|
||||
// check for common punctuation
|
||||
if (code === ol.expr.Char.LEFT_PAREN ||
|
||||
code === ol.expr.Char.RIGHT_PAREN) {
|
||||
return this.scanPunctuator_(code);
|
||||
}
|
||||
|
||||
// check for string literal
|
||||
if (code === ol.expr.Char.SINGLE_QUOTE ||
|
||||
code === ol.expr.Char.DOUBLE_QUOTE) {
|
||||
return this.scanStringLiteral_(code);
|
||||
}
|
||||
|
||||
// check for identifier
|
||||
if (this.isIdentifierStart_(code)) {
|
||||
return this.scanIdentifier_(code);
|
||||
}
|
||||
|
||||
// check dot punctuation or decimal
|
||||
if (code === ol.expr.Char.DOT) {
|
||||
if (this.isDecimalDigit_(this.getCharCode_(1))) {
|
||||
return this.scanNumericLiteral_(code);
|
||||
}
|
||||
return this.scanPunctuator_(code);
|
||||
}
|
||||
|
||||
// check for numeric literal
|
||||
if (this.isDecimalDigit_(code)) {
|
||||
return this.scanNumericLiteral_(code);
|
||||
}
|
||||
|
||||
// all the rest is punctuation
|
||||
return this.scanPunctuator_(code);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Peek at the next token, but don't advance the index.
|
||||
*
|
||||
* @return {ol.expr.Token} The upcoming token.
|
||||
*/
|
||||
ol.expr.Lexer.prototype.peek = function() {
|
||||
var currentIndex = this.index_;
|
||||
var token = this.next();
|
||||
this.nextIndex_ = this.index_;
|
||||
this.index_ = currentIndex;
|
||||
return token;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan hex literal as numeric token.
|
||||
*
|
||||
* @param {number} code The current character code.
|
||||
* @return {ol.expr.Token} Numeric literal token.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.scanHexLiteral_ = function(code) {
|
||||
var str = '';
|
||||
var start = this.index_ - 2;
|
||||
|
||||
while (this.index_ < this.length_) {
|
||||
if (!this.isHexDigit_(code)) {
|
||||
break;
|
||||
}
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
code = this.getCurrentCharCode_();
|
||||
}
|
||||
|
||||
if (str.length === 0 || this.isIdentifierStart_(code)) {
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: String.fromCharCode(code),
|
||||
index: this.index_
|
||||
});
|
||||
}
|
||||
|
||||
goog.asserts.assert(!isNaN(parseInt('0x' + str, 16)), 'Valid hex: ' + str);
|
||||
|
||||
return {
|
||||
type: ol.expr.TokenType.NUMERIC_LITERAL,
|
||||
value: parseInt('0x' + str, 16),
|
||||
index: start
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan identifier token.
|
||||
*
|
||||
* @param {number} code The current character code.
|
||||
* @return {ol.expr.Token} Identifier token.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.scanIdentifier_ = function(code) {
|
||||
goog.asserts.assert(this.isIdentifierStart_(code),
|
||||
'Must be called with a valid identifier');
|
||||
|
||||
var start = this.index_;
|
||||
this.increment_(1);
|
||||
|
||||
while (this.index_ < this.length_) {
|
||||
code = this.getCurrentCharCode_();
|
||||
if (this.isIdentifierPart_(code)) {
|
||||
this.increment_(1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var id = this.source_.slice(start, this.index_);
|
||||
|
||||
var type;
|
||||
if (id.length === 1) {
|
||||
type = ol.expr.TokenType.IDENTIFIER;
|
||||
} else if (this.isKeyword_(id)) {
|
||||
type = ol.expr.TokenType.KEYWORD;
|
||||
} else if (id === 'null') {
|
||||
type = ol.expr.TokenType.NULL_LITERAL;
|
||||
} else if (id === 'true' || id === 'false') {
|
||||
type = ol.expr.TokenType.BOOLEAN_LITERAL;
|
||||
} else {
|
||||
type = ol.expr.TokenType.IDENTIFIER;
|
||||
}
|
||||
|
||||
return {
|
||||
type: type,
|
||||
value: id,
|
||||
index: start
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan numeric literal token.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.3
|
||||
*
|
||||
* @param {number} code The current character code.
|
||||
* @return {ol.expr.Token} Numeric literal token.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.scanNumericLiteral_ = function(code) {
|
||||
goog.asserts.assert(
|
||||
code === ol.expr.Char.DOT || this.isDecimalDigit_(code),
|
||||
'Valid start for numeric literal: ' + String.fromCharCode(code));
|
||||
|
||||
// start assembling numeric string
|
||||
var str = '';
|
||||
var start = this.index_;
|
||||
|
||||
if (code !== ol.expr.Char.DOT) {
|
||||
|
||||
if (code === ol.expr.Char.DIGIT_0) {
|
||||
var nextCode = this.getCharCode_(1);
|
||||
|
||||
// hex literals start with 0X or 0x
|
||||
if (nextCode === ol.expr.Char.UPPER_X ||
|
||||
nextCode === ol.expr.Char.LOWER_X) {
|
||||
this.increment_(2);
|
||||
return this.scanHexLiteral_(this.getCurrentCharCode_());
|
||||
}
|
||||
|
||||
// octals start with 0
|
||||
if (this.isOctalDigit_(nextCode)) {
|
||||
this.increment_(1);
|
||||
return this.scanOctalLiteral_(nextCode);
|
||||
}
|
||||
|
||||
// numbers like 09 not allowed
|
||||
if (this.isDecimalDigit_(nextCode)) {
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: String.fromCharCode(nextCode),
|
||||
index: this.index_
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// scan all decimal chars
|
||||
while (this.isDecimalDigit_(code)) {
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
code = this.getCurrentCharCode_();
|
||||
}
|
||||
}
|
||||
|
||||
// scan fractional part
|
||||
if (code === ol.expr.Char.DOT) {
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
code = this.getCurrentCharCode_();
|
||||
|
||||
// scan all decimal chars
|
||||
while (this.isDecimalDigit_(code)) {
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
code = this.getCurrentCharCode_();
|
||||
}
|
||||
}
|
||||
|
||||
// scan exponent
|
||||
if (code === ol.expr.Char.UPPER_E ||
|
||||
code === ol.expr.Char.LOWER_E) {
|
||||
str += 'E';
|
||||
this.increment_(1);
|
||||
|
||||
code = this.getCurrentCharCode_();
|
||||
if (code === ol.expr.Char.PLUS ||
|
||||
code === ol.expr.Char.MINUS) {
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
code = this.getCurrentCharCode_();
|
||||
}
|
||||
|
||||
if (!this.isDecimalDigit_(code)) {
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: String.fromCharCode(code),
|
||||
index: this.index_
|
||||
});
|
||||
}
|
||||
|
||||
// scan all decimal chars (TODO: unduplicate this)
|
||||
while (this.isDecimalDigit_(code)) {
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
code = this.getCurrentCharCode_();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isIdentifierStart_(code)) {
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: String.fromCharCode(code),
|
||||
index: this.index_
|
||||
});
|
||||
}
|
||||
|
||||
goog.asserts.assert(!isNaN(parseFloat(str)), 'Valid number: ' + str);
|
||||
|
||||
return {
|
||||
type: ol.expr.TokenType.NUMERIC_LITERAL,
|
||||
value: parseFloat(str),
|
||||
index: start
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan octal literal as numeric token.
|
||||
*
|
||||
* @param {number} code The current character code.
|
||||
* @return {ol.expr.Token} Numeric literal token.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.scanOctalLiteral_ = function(code) {
|
||||
goog.asserts.assert(this.isOctalDigit_(code));
|
||||
|
||||
var str = '0' + String.fromCharCode(code);
|
||||
var start = this.index_ - 1;
|
||||
this.increment_(1);
|
||||
|
||||
while (this.index_ < this.length_) {
|
||||
code = this.getCurrentCharCode_();
|
||||
if (!this.isOctalDigit_(code)) {
|
||||
break;
|
||||
}
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
}
|
||||
|
||||
code = this.getCurrentCharCode_();
|
||||
if (this.isIdentifierStart_(code) ||
|
||||
this.isDecimalDigit_(code)) {
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: String.fromCharCode(code),
|
||||
index: this.index_
|
||||
});
|
||||
}
|
||||
|
||||
goog.asserts.assert(!isNaN(parseInt(str, 8)), 'Valid octal: ' + str);
|
||||
|
||||
return {
|
||||
type: ol.expr.TokenType.NUMERIC_LITERAL,
|
||||
value: parseInt(str, 8),
|
||||
index: start
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan punctuator token (a subset of allowed tokens in 7.7).
|
||||
*
|
||||
* @param {number} code The current character code.
|
||||
* @return {ol.expr.Token} Punctuator token.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.scanPunctuator_ = function(code) {
|
||||
var start = this.index_;
|
||||
|
||||
// single char punctuation that also doesn't start longer punctuation
|
||||
// (we disallow assignment, so no += etc.)
|
||||
if (code === ol.expr.Char.DOT ||
|
||||
code === ol.expr.Char.LEFT_PAREN ||
|
||||
code === ol.expr.Char.RIGHT_PAREN ||
|
||||
code === ol.expr.Char.COMMA ||
|
||||
code === ol.expr.Char.PLUS ||
|
||||
code === ol.expr.Char.MINUS ||
|
||||
code === ol.expr.Char.STAR ||
|
||||
code === ol.expr.Char.SLASH ||
|
||||
code === ol.expr.Char.PERCENT ||
|
||||
code === ol.expr.Char.TILDE) {
|
||||
|
||||
this.increment_(1);
|
||||
return {
|
||||
type: ol.expr.TokenType.PUNCTUATOR,
|
||||
value: String.fromCharCode(code),
|
||||
index: start
|
||||
};
|
||||
}
|
||||
|
||||
// check for 2-character punctuation
|
||||
var nextCode = this.getCharCode_(1);
|
||||
|
||||
// assignment or comparison (and we don't allow assignment)
|
||||
if (nextCode === ol.expr.Char.EQUAL) {
|
||||
if (code === ol.expr.Char.BANG || code === ol.expr.Char.EQUAL) {
|
||||
// we're looking at !=, ==, !==, or ===
|
||||
this.increment_(2);
|
||||
|
||||
// check for triple
|
||||
if (this.getCurrentCharCode_() === ol.expr.Char.EQUAL) {
|
||||
this.increment_(1);
|
||||
return {
|
||||
type: ol.expr.TokenType.PUNCTUATOR,
|
||||
value: String.fromCharCode(code) + '==',
|
||||
index: start
|
||||
};
|
||||
} else {
|
||||
// != or ==
|
||||
return {
|
||||
type: ol.expr.TokenType.PUNCTUATOR,
|
||||
value: String.fromCharCode(code) + '=',
|
||||
index: start
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (code === ol.expr.Char.GREATER ||
|
||||
code === ol.expr.Char.LESS) {
|
||||
this.increment_(2);
|
||||
return {
|
||||
type: ol.expr.TokenType.PUNCTUATOR,
|
||||
value: String.fromCharCode(code) + '=',
|
||||
index: start
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// remaining 2-charcter punctuators are || and &&
|
||||
if (code === nextCode &&
|
||||
(code === ol.expr.Char.PIPE ||
|
||||
code === ol.expr.Char.AMPERSAND)) {
|
||||
|
||||
this.increment_(2);
|
||||
var str = String.fromCharCode(code);
|
||||
return {
|
||||
type: ol.expr.TokenType.PUNCTUATOR,
|
||||
value: str + str,
|
||||
index: start
|
||||
};
|
||||
}
|
||||
|
||||
// we don't allow 4-character punctuator (>>>=)
|
||||
// and the allowed 3-character punctuators (!==, ===) are already consumed
|
||||
|
||||
// other single character punctuators
|
||||
if (code === ol.expr.Char.GREATER ||
|
||||
code === ol.expr.Char.LESS ||
|
||||
code === ol.expr.Char.BANG ||
|
||||
code === ol.expr.Char.AMPERSAND ||
|
||||
code === ol.expr.Char.PIPE) {
|
||||
|
||||
this.increment_(1);
|
||||
return {
|
||||
type: ol.expr.TokenType.PUNCTUATOR,
|
||||
value: String.fromCharCode(code),
|
||||
index: start
|
||||
};
|
||||
}
|
||||
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: String.fromCharCode(code),
|
||||
index: this.index_
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan string literal token.
|
||||
*
|
||||
* @param {number} quote The current character code.
|
||||
* @return {ol.expr.Token} String literal token.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.scanStringLiteral_ = function(quote) {
|
||||
goog.asserts.assert(quote === ol.expr.Char.SINGLE_QUOTE ||
|
||||
quote === ol.expr.Char.DOUBLE_QUOTE,
|
||||
'Strings must start with a quote: ' + String.fromCharCode(quote));
|
||||
|
||||
var start = this.index_;
|
||||
this.increment_(1);
|
||||
|
||||
var str = '';
|
||||
var code;
|
||||
while (this.index_ < this.length_) {
|
||||
code = this.getCurrentCharCode_();
|
||||
this.increment_(1);
|
||||
if (code === quote) {
|
||||
quote = 0;
|
||||
break;
|
||||
}
|
||||
// look for escaped quote or backslash
|
||||
if (code === ol.expr.Char.BACKSLASH) {
|
||||
str += this.getCurrentChar_();
|
||||
this.increment_(1);
|
||||
} else {
|
||||
str += String.fromCharCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
if (quote !== 0) {
|
||||
// unterminated string literal
|
||||
throw new ol.expr.UnexpectedToken(this.peek());
|
||||
}
|
||||
|
||||
return {
|
||||
type: ol.expr.TokenType.STRING_LITERAL,
|
||||
value: str,
|
||||
index: start
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* After peeking, skip may be called to advance the cursor without re-scanning.
|
||||
*/
|
||||
ol.expr.Lexer.prototype.skip = function() {
|
||||
this.index_ = this.nextIndex_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Skip all whitespace.
|
||||
* @return {number} The character code of the first non-whitespace character.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.skipWhitespace_ = function() {
|
||||
var code = NaN;
|
||||
while (this.index_ < this.length_) {
|
||||
code = this.getCurrentCharCode_();
|
||||
if (this.isWhitespace_(code)) {
|
||||
this.increment_(1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return code;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Error object for unexpected tokens.
|
||||
* @param {ol.expr.Token} token The unexpected token.
|
||||
* @param {string=} opt_message Custom error message.
|
||||
* @constructor
|
||||
* @extends {goog.debug.Error}
|
||||
*/
|
||||
ol.expr.UnexpectedToken = function(token, opt_message) {
|
||||
var message = goog.isDef(opt_message) ? opt_message :
|
||||
'Unexpected token ' + token.value + ' at index ' + token.index;
|
||||
|
||||
goog.debug.Error.call(this, message);
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Token}
|
||||
*/
|
||||
this.token = token;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.UnexpectedToken, goog.debug.Error);
|
||||
|
||||
|
||||
/** @override */
|
||||
ol.expr.UnexpectedToken.prototype.name = 'UnexpectedToken';
|
||||
478
src/ol/expr/parser.js
Normal file
478
src/ol/expr/parser.js
Normal file
@@ -0,0 +1,478 @@
|
||||
/**
|
||||
* The logic and naming of methods here are inspired by Esprima (BSD Licensed).
|
||||
* Esprima (http://esprima.org) includes the following copyright notices:
|
||||
*
|
||||
* Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
* Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
|
||||
* Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
* Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
|
||||
* Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
|
||||
* Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
|
||||
* Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
|
||||
* Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
|
||||
* Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
*/
|
||||
|
||||
goog.provide('ol.expr.Parser');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
|
||||
goog.require('ol.expr.Call');
|
||||
goog.require('ol.expr.Comparison');
|
||||
goog.require('ol.expr.ComparisonOp');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Identifier');
|
||||
goog.require('ol.expr.Lexer');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.expr.Logical');
|
||||
goog.require('ol.expr.LogicalOp');
|
||||
goog.require('ol.expr.Math');
|
||||
goog.require('ol.expr.MathOp');
|
||||
goog.require('ol.expr.Member');
|
||||
goog.require('ol.expr.Not');
|
||||
goog.require('ol.expr.Token');
|
||||
goog.require('ol.expr.TokenType');
|
||||
goog.require('ol.expr.UnexpectedToken');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Instances of ol.expr.Parser parse a very limited set of ECMAScript
|
||||
* expressions (http://www.ecma-international.org/ecma-262/5.1/#sec-11).
|
||||
*
|
||||
* - Primary Expression (11.1):
|
||||
* - Identifier (e.g. `foo`)
|
||||
* - Literal (e.g. `"some string"` or `42`)
|
||||
* - Grouped (e.g. `(foo)`)
|
||||
* - Left-Hand-Side Expression (11.2):
|
||||
* - Property Accessors
|
||||
* - Dot notation only
|
||||
* - Function Calls
|
||||
* - Identifier with arguments only (e.g. `foo(bar, 42)`)
|
||||
* - Unary Operators (11.4)
|
||||
* - Logical Not (e.g. `!foo`)
|
||||
* - Multiplicitave Operators (11.5)
|
||||
* - Additive Operators (11.6)
|
||||
* - Relational Operators (11.8)
|
||||
* - <, >, <=, and >= only
|
||||
* - Equality Operators (11.9)
|
||||
* - Binary Logical Operators (11.11)
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
ol.expr.Parser = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine the precedence for the given token.
|
||||
*
|
||||
* @param {ol.expr.Token} token A token.
|
||||
* @return {number} The precedence for the given token. Higher gets more
|
||||
* precedence.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.binaryPrecedence_ = function(token) {
|
||||
var precedence = 0;
|
||||
if (token.type !== ol.expr.TokenType.PUNCTUATOR) {
|
||||
return precedence;
|
||||
}
|
||||
|
||||
switch (token.value) {
|
||||
case ol.expr.LogicalOp.OR:
|
||||
precedence = 1;
|
||||
break;
|
||||
case ol.expr.LogicalOp.AND:
|
||||
precedence = 2;
|
||||
break;
|
||||
case ol.expr.ComparisonOp.EQ:
|
||||
case ol.expr.ComparisonOp.NEQ:
|
||||
case ol.expr.ComparisonOp.STRICT_EQ:
|
||||
case ol.expr.ComparisonOp.STRICT_NEQ:
|
||||
precedence = 3;
|
||||
break;
|
||||
case ol.expr.ComparisonOp.GT:
|
||||
case ol.expr.ComparisonOp.LT:
|
||||
case ol.expr.ComparisonOp.GTE:
|
||||
case ol.expr.ComparisonOp.LTE:
|
||||
precedence = 4;
|
||||
break;
|
||||
case ol.expr.MathOp.ADD:
|
||||
case ol.expr.MathOp.SUBTRACT:
|
||||
precedence = 5;
|
||||
break;
|
||||
case ol.expr.MathOp.MULTIPLY:
|
||||
case ol.expr.MathOp.DIVIDE:
|
||||
case ol.expr.MathOp.MOD:
|
||||
precedence = 6;
|
||||
break;
|
||||
default:
|
||||
// punctuator is not a supported binary operator, that's fine
|
||||
break;
|
||||
}
|
||||
|
||||
return precedence;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a binary expression.
|
||||
*
|
||||
* @param {string} operator Operator.
|
||||
* @param {ol.expr.Expression} left Left expression.
|
||||
* @param {ol.expr.Expression} right Right expression.
|
||||
* @return {ol.expr.Expression} The expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.createBinaryExpression_ = function(operator,
|
||||
left, right) {
|
||||
var expr;
|
||||
if (ol.expr.Comparison.isValidOp(operator)) {
|
||||
expr = new ol.expr.Comparison(
|
||||
/** @type {ol.expr.ComparisonOp.<string>} */ (operator),
|
||||
left, right);
|
||||
} else if (ol.expr.Logical.isValidOp(operator)) {
|
||||
expr = new ol.expr.Logical(
|
||||
/** @type {ol.expr.LogicalOp.<string>} */ (operator),
|
||||
left, right);
|
||||
} else if (ol.expr.Math.isValidOp(operator)) {
|
||||
expr = new ol.expr.Math(
|
||||
/** @type {ol.expr.MathOp.<string>} */ (operator),
|
||||
left, right);
|
||||
} else {
|
||||
throw new Error('Unsupported binary operator: ' + operator);
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a call expression.
|
||||
*
|
||||
* @param {ol.expr.Expression} callee Expression for function.
|
||||
* @param {Array.<ol.expr.Expression>} args Arguments array.
|
||||
* @return {ol.expr.Call} Call expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.createCallExpression_ = function(callee, args) {
|
||||
return new ol.expr.Call(callee, args);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create an identifier expression.
|
||||
*
|
||||
* @param {string} name Identifier name.
|
||||
* @return {ol.expr.Identifier} Identifier expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.createIdentifier_ = function(name) {
|
||||
return new ol.expr.Identifier(name);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a literal expression.
|
||||
*
|
||||
* @param {string|number|boolean|null} value Literal value.
|
||||
* @return {ol.expr.Literal} The literal expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.createLiteral_ = function(value) {
|
||||
return new ol.expr.Literal(value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a member expression.
|
||||
*
|
||||
* // TODO: make exp {ol.expr.Member|ol.expr.Identifier}
|
||||
* @param {ol.expr.Expression} object Expression.
|
||||
* @param {ol.expr.Identifier} property Member name.
|
||||
* @return {ol.expr.Member} The member expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.createMemberExpression_ = function(object,
|
||||
property) {
|
||||
return new ol.expr.Member(object, property);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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 {ol.expr.Token} op Operator.
|
||||
* @param {ol.expr.Expression} argument Expression.
|
||||
* @return {ol.expr.Expression} The unary expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.createUnaryExpression_ = function(op, argument) {
|
||||
goog.asserts.assert(op.value === '!' || op.value === '+' || op.value === '-');
|
||||
var expr;
|
||||
if (op.value === '!') {
|
||||
expr = new ol.expr.Not(argument);
|
||||
} else if (!(argument instanceof ol.expr.Literal)) {
|
||||
throw new ol.expr.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;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse an expression.
|
||||
*
|
||||
* @param {string} source Expression source.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
*/
|
||||
ol.expr.Parser.prototype.parse = function(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var expr = this.parseExpression_(lexer);
|
||||
var token = lexer.peek();
|
||||
if (token.type !== ol.expr.TokenType.EOF) {
|
||||
throw new ol.expr.UnexpectedToken(token);
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse call arguments
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {Array.<ol.expr.Expression>} Arguments.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseArguments_ = function(lexer) {
|
||||
var args = [];
|
||||
|
||||
lexer.expect('(');
|
||||
|
||||
if (!lexer.match(')')) {
|
||||
while (true) {
|
||||
args.push(this.parseBinaryExpression_(lexer));
|
||||
if (lexer.match(')')) {
|
||||
break;
|
||||
}
|
||||
lexer.expect(',');
|
||||
}
|
||||
}
|
||||
lexer.skip();
|
||||
|
||||
return args;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a binary expression. Supported binary expressions:
|
||||
*
|
||||
* - Multiplicative Operators (`*`, `/`, `%`)
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.5
|
||||
|
||||
* - Additive Operators (`+`, `-`)
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.6
|
||||
*
|
||||
* - Relational Operators (`<`, `>`, `<=`, `>=`)
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.8
|
||||
*
|
||||
* - Equality Operators (`==`, `!=`, `===`, `!==`)
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.9
|
||||
*
|
||||
* - Binary Logical Operators (`&&`, `||`)
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.11
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseBinaryExpression_ = function(lexer) {
|
||||
var left = this.parseUnaryExpression_(lexer);
|
||||
|
||||
var operator = lexer.peek();
|
||||
var precedence = this.binaryPrecedence_(operator);
|
||||
if (precedence === 0) {
|
||||
// not a supported binary operator
|
||||
return left;
|
||||
}
|
||||
lexer.skip();
|
||||
|
||||
var right = this.parseUnaryExpression_(lexer);
|
||||
var stack = [left, operator, right];
|
||||
|
||||
precedence = this.binaryPrecedence_(lexer.peek());
|
||||
while (precedence > 0) {
|
||||
// TODO: cache operator precedence in stack
|
||||
while (stack.length > 2 &&
|
||||
(precedence <= this.binaryPrecedence_(stack[stack.length - 2]))) {
|
||||
right = stack.pop();
|
||||
operator = stack.pop();
|
||||
left = stack.pop();
|
||||
stack.push(this.createBinaryExpression_(operator.value, left, right));
|
||||
}
|
||||
stack.push(lexer.next());
|
||||
stack.push(this.parseUnaryExpression_(lexer));
|
||||
precedence = this.binaryPrecedence_(lexer.peek());
|
||||
}
|
||||
|
||||
var i = stack.length - 1;
|
||||
var expr = stack[i];
|
||||
while (i > 1) {
|
||||
expr = this.createBinaryExpression_(stack[i - 1].value, stack[i - 2], expr);
|
||||
i -= 2;
|
||||
}
|
||||
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a group expression.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.6
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseGroupExpression_ = function(lexer) {
|
||||
lexer.expect('(');
|
||||
var expr = this.parseExpression_(lexer);
|
||||
lexer.expect(')');
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse left-hand-side expression. Limited to Member Expressions
|
||||
* and Call Expressions.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.2
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseLeftHandSideExpression_ = function(lexer) {
|
||||
var expr = this.parsePrimaryExpression_(lexer);
|
||||
var token = lexer.peek();
|
||||
if (token.value === '(') {
|
||||
// only allow calls on identifiers (e.g. `foo()` not `foo.bar()`)
|
||||
if (!(expr instanceof ol.expr.Identifier)) {
|
||||
// TODO: more helpful error messages for restricted syntax
|
||||
throw new ol.expr.UnexpectedToken(token);
|
||||
}
|
||||
var args = this.parseArguments_(lexer);
|
||||
expr = this.createCallExpression_(expr, args);
|
||||
} else {
|
||||
// TODO: throw if not Identifier
|
||||
while (token.value === '.') {
|
||||
var property = this.parseNonComputedMember_(lexer);
|
||||
expr = this.createMemberExpression_(expr, property);
|
||||
token = lexer.peek();
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse non-computed member.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.2
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Identifier} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseNonComputedMember_ = function(lexer) {
|
||||
lexer.expect('.');
|
||||
|
||||
var token = lexer.next();
|
||||
if (token.type !== ol.expr.TokenType.IDENTIFIER &&
|
||||
token.type !== ol.expr.TokenType.KEYWORD &&
|
||||
token.type !== ol.expr.TokenType.BOOLEAN_LITERAL &&
|
||||
token.type !== ol.expr.TokenType.NULL_LITERAL) {
|
||||
throw new ol.expr.UnexpectedToken(token);
|
||||
}
|
||||
|
||||
return this.createIdentifier_(String(token.value));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse primary expression.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.1
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parsePrimaryExpression_ = function(lexer) {
|
||||
var token = lexer.peek();
|
||||
if (token.value === '(') {
|
||||
return this.parseGroupExpression_(lexer);
|
||||
}
|
||||
lexer.skip();
|
||||
var expr;
|
||||
var type = token.type;
|
||||
if (type === ol.expr.TokenType.IDENTIFIER) {
|
||||
expr = this.createIdentifier_(/** @type {string} */ (token.value));
|
||||
} else if (type === ol.expr.TokenType.STRING_LITERAL ||
|
||||
type === ol.expr.TokenType.NUMERIC_LITERAL) {
|
||||
// numeric and string literals are already the correct type
|
||||
expr = this.createLiteral_(token.value);
|
||||
} else if (type === ol.expr.TokenType.BOOLEAN_LITERAL) {
|
||||
// because booleans are valid member properties, tokens are still string
|
||||
expr = this.createLiteral_(token.value === 'true');
|
||||
} else if (type === ol.expr.TokenType.NULL_LITERAL) {
|
||||
expr = this.createLiteral_(null);
|
||||
} else {
|
||||
throw new ol.expr.UnexpectedToken(token);
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse expression with a unary operator. Limited to logical not operator.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.4
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseUnaryExpression_ = function(lexer) {
|
||||
var expr;
|
||||
var operator = lexer.peek();
|
||||
if (operator.type !== ol.expr.TokenType.PUNCTUATOR) {
|
||||
expr = this.parseLeftHandSideExpression_(lexer);
|
||||
} else if (operator.value === '!' || operator.value === '-' ||
|
||||
operator.value === '+') {
|
||||
lexer.skip();
|
||||
expr = this.parseUnaryExpression_(lexer);
|
||||
expr = this.createUnaryExpression_(operator, expr);
|
||||
} else {
|
||||
expr = this.parseLeftHandSideExpression_(lexer);
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse an expression.
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseExpression_ = function(lexer) {
|
||||
return this.parseBinaryExpression_(lexer);
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
@exportSymbol ol.Expression
|
||||
@@ -1,80 +0,0 @@
|
||||
goog.provide('ol.Expression');
|
||||
goog.provide('ol.ExpressionLiteral');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new expression. Expressions are used for instance to bind
|
||||
* symbolizer properties to feature attributes.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* // take the color from the color attribute
|
||||
* color: new ol.Expression('color');
|
||||
* // take the strokeWidth from the width attribute and multiply by 2.
|
||||
* strokeWidth: new ol.Expression('width*2');
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} source Expression to be evaluated.
|
||||
*/
|
||||
ol.Expression = function(source) {
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.source_ = source;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate the expression and return the result.
|
||||
*
|
||||
* @param {Object=} opt_thisArg Object to use as this when evaluating the
|
||||
* expression. If not provided, the global object will be used.
|
||||
* @param {Object=} opt_scope Evaluation scope. All properties of this object
|
||||
* will be available as variables when evaluating the expression. If not
|
||||
* provided, the global object will be used.
|
||||
* @return {*} Result of the expression.
|
||||
*/
|
||||
ol.Expression.prototype.evaluate = function(opt_thisArg, opt_scope) {
|
||||
var thisArg = goog.isDef(opt_thisArg) ? opt_thisArg : goog.global,
|
||||
scope = goog.isDef(opt_scope) ? opt_scope : goog.global,
|
||||
names = [],
|
||||
values = [];
|
||||
|
||||
for (var name in scope) {
|
||||
names.push(name);
|
||||
values.push(scope[name]);
|
||||
}
|
||||
|
||||
var evaluator = new Function(names.join(','), 'return ' + this.source_);
|
||||
return evaluator.apply(thisArg, values);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.Expression}
|
||||
* @param {*} value Literal value.
|
||||
*/
|
||||
ol.ExpressionLiteral = function(value) {
|
||||
|
||||
/**
|
||||
* @type {*}
|
||||
* @private
|
||||
*/
|
||||
this.value_ = value;
|
||||
|
||||
};
|
||||
goog.inherits(ol.ExpressionLiteral, ol.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.ExpressionLiteral.prototype.evaluate = function(opt_thisArg, opt_scope) {
|
||||
return this.value_;
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
@exportSymbol ol.filter.Filter
|
||||
@exportSymbol ol.filter.Geometry
|
||||
@exportSymbol ol.filter.Logical
|
||||
|
||||
@exportSymbol ol.filter.LogicalOperator
|
||||
@exportProperty ol.filter.LogicalOperator.AND
|
||||
@exportProperty ol.filter.LogicalOperator.OR
|
||||
@@ -1,3 +0,0 @@
|
||||
/**
|
||||
* @namespace ol.filter
|
||||
*/
|
||||
@@ -1,39 +0,0 @@
|
||||
goog.provide('ol.filter.Extent');
|
||||
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.filter.Filter');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.filter.Filter}
|
||||
* @param {ol.Extent} extent The extent.
|
||||
*/
|
||||
ol.filter.Extent = function(extent) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @type {ol.Extent}
|
||||
* @private
|
||||
*/
|
||||
this.extent_ = extent;
|
||||
|
||||
};
|
||||
goog.inherits(ol.filter.Extent, ol.filter.Filter);
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.Extent} The filter extent.
|
||||
*/
|
||||
ol.filter.Extent.prototype.getExtent = function() {
|
||||
return this.extent_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.filter.Extent.prototype.applies = function(feature) {
|
||||
return ol.extent.intersects(feature.getGeometry().getBounds(), this.extent_);
|
||||
};
|
||||
@@ -1,36 +0,0 @@
|
||||
goog.provide('ol.filter.Filter');
|
||||
|
||||
goog.require('ol.Feature');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new filter which can be used to filter features based on a
|
||||
* function.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* new ol.style.Rule({
|
||||
* filter: new ol.filter.Filter(function(feature) {
|
||||
* return feature.get('where') == 'outer';
|
||||
* }),
|
||||
* symbolizers: [
|
||||
* ...
|
||||
*
|
||||
* @constructor
|
||||
* @param {function(this:ol.filter.Filter, ol.Feature)=} opt_filterFunction
|
||||
* Filter function. Should return true if the passed feature passes the
|
||||
* filter, false otherwise.
|
||||
*/
|
||||
ol.filter.Filter = function(opt_filterFunction) {
|
||||
if (goog.isDef(opt_filterFunction)) {
|
||||
this.applies = opt_filterFunction;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Feature} feature Feature to evaluate the filter against.
|
||||
* @return {boolean} The provided feature passes this filter.
|
||||
*/
|
||||
ol.filter.Filter.prototype.applies = goog.abstractMethod;
|
||||
@@ -1,42 +0,0 @@
|
||||
goog.provide('ol.filter.Geometry');
|
||||
goog.provide('ol.filter.GeometryType');
|
||||
|
||||
goog.require('ol.filter.Filter');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Filter features by geometry type.
|
||||
* @constructor
|
||||
* @extends {ol.filter.Filter}
|
||||
* @param {ol.geom.GeometryType} type The geometry type.
|
||||
*/
|
||||
ol.filter.Geometry = function(type) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @type {ol.geom.GeometryType}
|
||||
* @private
|
||||
*/
|
||||
this.type_ = type;
|
||||
|
||||
};
|
||||
goog.inherits(ol.filter.Geometry, ol.filter.Filter);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.filter.Geometry.prototype.applies = function(feature) {
|
||||
var geometry = feature.getGeometry();
|
||||
return goog.isNull(geometry) ? false : geometry.getType() === this.type_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.geom.GeometryType} The geometry type.
|
||||
*/
|
||||
ol.filter.Geometry.prototype.getType = function() {
|
||||
return this.type_;
|
||||
};
|
||||
@@ -1,128 +0,0 @@
|
||||
goog.provide('ol.filter.Logical');
|
||||
goog.provide('ol.filter.LogicalOperator');
|
||||
goog.provide('ol.filter.and');
|
||||
goog.provide('ol.filter.not');
|
||||
goog.provide('ol.filter.or');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.filter.Filter');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A filter to group (a) subfilter(s) by a logical operator (AND/OR/NOT).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* var f1 = new ol.filter.Filter(myFunc1);
|
||||
* var f2 = new ol.filter.Filter(myFunc2);
|
||||
* // match one of the two filters above
|
||||
* var logical = new ol.filter.Logical([f1, f2],
|
||||
* ol.filter.LogicalOperator.OR);
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.filter.Filter}
|
||||
* @param {Array.<ol.filter.Filter>} filters Filters to combine.
|
||||
* @param {ol.filter.LogicalOperator} operator Operator.
|
||||
*/
|
||||
ol.filter.Logical = function(filters, operator) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.filter.Filter>}
|
||||
* @private
|
||||
*/
|
||||
this.filters_ = filters;
|
||||
goog.asserts.assert(filters.length > 0, 'Must supply at least one filter');
|
||||
|
||||
/**
|
||||
* @type {ol.filter.LogicalOperator}
|
||||
*/
|
||||
this.operator = operator;
|
||||
|
||||
};
|
||||
goog.inherits(ol.filter.Logical, ol.filter.Filter);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.filter.Logical.prototype.applies = function(feature) {
|
||||
var filters = this.filters_,
|
||||
i = 0, ii = filters.length,
|
||||
result;
|
||||
switch (this.operator) {
|
||||
case ol.filter.LogicalOperator.AND:
|
||||
result = true;
|
||||
while (result && i < ii) {
|
||||
result = result && filters[i].applies(feature);
|
||||
++i;
|
||||
}
|
||||
break;
|
||||
case ol.filter.LogicalOperator.OR:
|
||||
result = false;
|
||||
while (!result && i < ii) {
|
||||
result = result || filters[i].applies(feature);
|
||||
++i;
|
||||
}
|
||||
break;
|
||||
case ol.filter.LogicalOperator.NOT:
|
||||
result = !filters[i].applies(feature);
|
||||
break;
|
||||
default:
|
||||
goog.asserts.assert(false, 'Unsupported operation: ' + this.operator);
|
||||
}
|
||||
return !!result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<ol.filter.Filter>} The filter's filters.
|
||||
*/
|
||||
ol.filter.Logical.prototype.getFilters = function() {
|
||||
return this.filters_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.filter.LogicalOperator = {
|
||||
AND: '&&',
|
||||
OR: '||',
|
||||
NOT: '!'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a filter that evaluates to true if all of the provided filters
|
||||
* evaluate to true.
|
||||
* @param {...ol.filter.Filter} var_args Filters.
|
||||
* @return {ol.filter.Logical} A logical AND filter.
|
||||
*/
|
||||
ol.filter.and = function(var_args) {
|
||||
var filters = Array.prototype.slice.call(arguments);
|
||||
return new ol.filter.Logical(filters, ol.filter.LogicalOperator.AND);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a new filter that is the logical compliment of another.
|
||||
* @param {ol.filter.Filter} filter The filter to negate.
|
||||
* @return {ol.filter.Logical} A logical NOT filter.
|
||||
*/
|
||||
ol.filter.not = function(filter) {
|
||||
return new ol.filter.Logical([filter], ol.filter.LogicalOperator.NOT);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a filter that evaluates to true if any of the provided filters
|
||||
* evaluate to true.
|
||||
* @param {...ol.filter.Filter} var_args Filters.
|
||||
* @return {ol.filter.Logical} A logical OR filter.
|
||||
*/
|
||||
ol.filter.or = function(var_args) {
|
||||
var filters = Array.prototype.slice.call(arguments);
|
||||
return new ol.filter.Logical(filters, ol.filter.LogicalOperator.OR);
|
||||
};
|
||||
@@ -5,6 +5,11 @@ goog.require('goog.asserts');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.expr.Logical');
|
||||
goog.require('ol.expr.LogicalOp');
|
||||
goog.require('ol.expr.functions');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.SharedVertices');
|
||||
goog.require('ol.layer.Layer');
|
||||
@@ -79,35 +84,65 @@ ol.layer.FeatureCache.prototype.add = function(feature) {
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.filter.Filter=} opt_filter Optional filter.
|
||||
* @param {ol.expr.Expression=} opt_expr Expression for filtering.
|
||||
* @return {Object.<string, ol.Feature>} Object of features, keyed by id.
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.getFeaturesObject = function(opt_filter) {
|
||||
var i, features;
|
||||
if (!goog.isDef(opt_filter)) {
|
||||
ol.layer.FeatureCache.prototype.getFeaturesObject = function(opt_expr) {
|
||||
var features;
|
||||
if (!goog.isDef(opt_expr)) {
|
||||
features = this.idLookup_;
|
||||
} else {
|
||||
if (opt_filter instanceof ol.filter.Geometry) {
|
||||
features = this.geometryTypeIndex_[opt_filter.getType()];
|
||||
} else if (opt_filter instanceof ol.filter.Extent) {
|
||||
features = this.rTree_.searchReturningObject(opt_filter.getExtent());
|
||||
} else if (opt_filter instanceof ol.filter.Logical &&
|
||||
opt_filter.operator === ol.filter.LogicalOperator.AND) {
|
||||
var filters = opt_filter.getFilters();
|
||||
if (filters.length === 2) {
|
||||
var filter, geometryFilter, extentFilter;
|
||||
for (i = 0; i <= 1; ++i) {
|
||||
filter = filters[i];
|
||||
if (filter instanceof ol.filter.Geometry) {
|
||||
geometryFilter = filter;
|
||||
} else if (filter instanceof ol.filter.Extent) {
|
||||
extentFilter = filter;
|
||||
// check for geometryType or extent expression
|
||||
var name = ol.expr.isLibCall(opt_expr);
|
||||
if (name === ol.expr.functions.GEOMETRY_TYPE) {
|
||||
var args = /** @type {ol.expr.Call} */ (opt_expr).getArgs();
|
||||
goog.asserts.assert(args.length === 1);
|
||||
goog.asserts.assert(args[0] instanceof ol.expr.Literal);
|
||||
var type = /** @type {ol.expr.Literal } */ (args[0]).evaluate();
|
||||
goog.asserts.assertString(type);
|
||||
features = this.geometryTypeIndex_[type];
|
||||
} else if (name === ol.expr.functions.EXTENT) {
|
||||
var args = /** @type {ol.expr.Call} */ (opt_expr).getArgs();
|
||||
goog.asserts.assert(args.length === 4);
|
||||
var extent = [];
|
||||
for (var i = 0; i < 4; ++i) {
|
||||
goog.asserts.assert(args[i] instanceof ol.expr.Literal);
|
||||
extent[i] = /** @type {ol.expr.Literal} */ (args[i]).evaluate();
|
||||
goog.asserts.assertNumber(extent[i]);
|
||||
}
|
||||
features = this.rTree_.searchReturningObject(extent);
|
||||
} else {
|
||||
// not a call expression, check logical
|
||||
if (opt_expr instanceof ol.expr.Logical) {
|
||||
var op = /** @type {ol.expr.Logical} */ (opt_expr).getOperator();
|
||||
if (op === ol.expr.LogicalOp.AND) {
|
||||
var expressions = [opt_expr.getLeft(), opt_expr.getRight()];
|
||||
var expr, args, type, extent;
|
||||
for (var i = 0; i <= 1; ++i) {
|
||||
expr = expressions[i];
|
||||
name = ol.expr.isLibCall(expr);
|
||||
if (name === ol.expr.functions.GEOMETRY_TYPE) {
|
||||
args = /** @type {ol.expr.Call} */ (expr).getArgs();
|
||||
goog.asserts.assert(args.length === 1);
|
||||
goog.asserts.assert(args[0] instanceof ol.expr.Literal);
|
||||
type = /** @type {ol.expr.Literal } */ (args[0]).evaluate();
|
||||
goog.asserts.assertString(type);
|
||||
} else if (name === ol.expr.functions.EXTENT) {
|
||||
args = /** @type {ol.expr.Call} */ (expr).getArgs();
|
||||
goog.asserts.assert(args.length === 4);
|
||||
extent = [];
|
||||
for (var j = 0; j < 4; ++j) {
|
||||
goog.asserts.assert(args[j] instanceof ol.expr.Literal);
|
||||
extent[j] =
|
||||
/** @type {ol.expr.Literal} */ (args[j]).evaluate();
|
||||
goog.asserts.assertNumber(extent[j]);
|
||||
}
|
||||
}
|
||||
if (extentFilter && geometryFilter) {
|
||||
var type = geometryFilter.getType();
|
||||
features = goog.object.isEmpty(this.geometryTypeIndex_[type]) ? {} :
|
||||
this.rTree_.searchReturningObject(extentFilter.getExtent(), type);
|
||||
}
|
||||
if (type && extent) {
|
||||
features = this.getFeaturesObjectForExtent(extent,
|
||||
/** @type {ol.geom.GeometryType} */ (type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,7 +153,7 @@ ol.layer.FeatureCache.prototype.getFeaturesObject = function(opt_filter) {
|
||||
features = {};
|
||||
for (i in candidates) {
|
||||
feature = candidates[i];
|
||||
if (opt_filter.applies(feature) === true) {
|
||||
if (ol.expr.evaluateFeature(opt_expr, feature)) {
|
||||
features[i] = feature;
|
||||
}
|
||||
}
|
||||
@@ -129,12 +164,22 @@ ol.layer.FeatureCache.prototype.getFeaturesObject = function(opt_filter) {
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.filter.Geometry} filter Geometry type filter.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
* @private
|
||||
* Get all features whose bounding box intersects the provided extent.
|
||||
*
|
||||
* @param {ol.Extent} extent Bounding extent.
|
||||
* @param {ol.geom.GeometryType=} opt_type Optional geometry type.
|
||||
* @return {Object.<string, ol.Feature>} Features.
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.getFeaturesByGeometryType_ = function(filter) {
|
||||
return goog.object.getValues(this.geometryTypeIndex_[filter.getType()]);
|
||||
ol.layer.FeatureCache.prototype.getFeaturesObjectForExtent = function(extent,
|
||||
opt_type) {
|
||||
var features;
|
||||
if (goog.isDef(opt_type) &&
|
||||
goog.object.isEmpty(this.geometryTypeIndex_[opt_type])) {
|
||||
features = {};
|
||||
} else {
|
||||
features = this.rTree_.searchReturningObject(extent, opt_type);
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
@@ -234,21 +279,34 @@ ol.layer.Vector.prototype.getVectorSource = function() {
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.filter.Filter=} opt_filter Optional filter.
|
||||
* @param {ol.expr.Expression=} opt_expr Expression for filtering.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getFeatures = function(opt_filter) {
|
||||
ol.layer.Vector.prototype.getFeatures = function(opt_expr) {
|
||||
return goog.object.getValues(
|
||||
this.featureCache_.getFeaturesObject(opt_filter));
|
||||
this.featureCache_.getFeaturesObject(opt_expr));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.filter.Filter=} opt_filter Optional filter.
|
||||
* @param {ol.expr.Expression=} opt_expr Expression for filtering.
|
||||
* @return {Object.<string, ol.Feature>} Features.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getFeaturesObject = function(opt_filter) {
|
||||
return this.featureCache_.getFeaturesObject(opt_filter);
|
||||
ol.layer.Vector.prototype.getFeaturesObject = function(opt_expr) {
|
||||
return this.featureCache_.getFeaturesObject(opt_expr);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get all features whose bounding box intersects the provided extent.
|
||||
*
|
||||
* @param {ol.Extent} extent Bounding extent.
|
||||
* @param {ol.geom.GeometryType=} opt_type Optional geometry type.
|
||||
* @return {Object.<string, ol.Feature>} Features.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getFeaturesObjectForExtent = function(extent,
|
||||
opt_type) {
|
||||
return this.featureCache_.getFeaturesObjectForExtent(extent, opt_type);
|
||||
};
|
||||
|
||||
|
||||
@@ -415,10 +473,3 @@ ol.layer.Vector.uidTransformFeatureInfo = function(features) {
|
||||
function(feature) { return goog.getUid(feature); });
|
||||
return featureIds.join(', ');
|
||||
};
|
||||
|
||||
|
||||
goog.require('ol.filter.Extent');
|
||||
goog.require('ol.filter.Geometry');
|
||||
goog.require('ol.filter.Logical');
|
||||
goog.require('ol.filter.LogicalOperator');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
|
||||
@@ -12,10 +12,6 @@ goog.require('ol.TileCoord');
|
||||
goog.require('ol.TileRange');
|
||||
goog.require('ol.ViewHint');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.filter.Extent');
|
||||
goog.require('ol.filter.Geometry');
|
||||
goog.require('ol.filter.Logical');
|
||||
goog.require('ol.filter.LogicalOperator');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.renderer.canvas.Layer');
|
||||
@@ -101,18 +97,18 @@ ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
|
||||
this.tileArchetype_ = null;
|
||||
|
||||
/**
|
||||
* Geometry filters in rendering order.
|
||||
* Geometry types in rendering order.
|
||||
* TODO: these will go away shortly (in favor of one call per symbolizer type)
|
||||
* @private
|
||||
* @type {Array.<ol.filter.Geometry>}
|
||||
* @type {Array.<ol.geom.GeometryType>}
|
||||
*/
|
||||
this.geometryFilters_ = [
|
||||
new ol.filter.Geometry(ol.geom.GeometryType.POINT),
|
||||
new ol.filter.Geometry(ol.geom.GeometryType.MULTIPOINT),
|
||||
new ol.filter.Geometry(ol.geom.GeometryType.LINESTRING),
|
||||
new ol.filter.Geometry(ol.geom.GeometryType.MULTILINESTRING),
|
||||
new ol.filter.Geometry(ol.geom.GeometryType.POLYGON),
|
||||
new ol.filter.Geometry(ol.geom.GeometryType.MULTIPOLYGON)
|
||||
this.geometryTypes_ = [
|
||||
ol.geom.GeometryType.POINT,
|
||||
ol.geom.GeometryType.MULTIPOINT,
|
||||
ol.geom.GeometryType.LINESTRING,
|
||||
ol.geom.GeometryType.MULTILINESTRING,
|
||||
ol.geom.GeometryType.POLYGON,
|
||||
ol.geom.GeometryType.MULTIPOLYGON
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -251,13 +247,12 @@ ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel =
|
||||
var locationMin = [location[0] - halfMaxWidth, location[1] - halfMaxHeight];
|
||||
var locationMax = [location[0] + halfMaxWidth, location[1] + halfMaxHeight];
|
||||
var locationBbox = ol.extent.boundingExtent([locationMin, locationMax]);
|
||||
var filter = new ol.filter.Extent(locationBbox);
|
||||
var candidates = layer.getFeatures(filter);
|
||||
var candidates = layer.getFeaturesObjectForExtent(locationBbox);
|
||||
|
||||
var candidate, geom, type, symbolBounds, symbolSize, halfWidth, halfHeight,
|
||||
coordinates, j;
|
||||
for (var i = 0, ii = candidates.length; i < ii; ++i) {
|
||||
candidate = candidates[i];
|
||||
for (var id in candidates) {
|
||||
candidate = candidates[id];
|
||||
geom = candidate.getGeometry();
|
||||
type = geom.getType();
|
||||
if (type === ol.geom.GeometryType.POINT ||
|
||||
@@ -445,11 +440,11 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
||||
var tileGutter = 15 * tileResolution;
|
||||
var tile, tileCoord, key, x, y;
|
||||
// render features by geometry type
|
||||
var filters = this.geometryFilters_,
|
||||
numFilters = filters.length,
|
||||
var types = this.geometryTypes_,
|
||||
numTypes = types.length,
|
||||
deferred = false,
|
||||
dirty = false,
|
||||
i, geomFilter, tileExtent, extentFilter, type,
|
||||
i, type, tileExtent,
|
||||
groups, group, j, numGroups, featuresObject, tileHasFeatures;
|
||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
||||
@@ -463,16 +458,13 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
||||
tileExtent[1] += tileGutter;
|
||||
tileExtent[2] -= tileGutter;
|
||||
tileExtent[3] += tileGutter;
|
||||
extentFilter = new ol.filter.Extent(tileExtent);
|
||||
tileHasFeatures = false;
|
||||
for (i = 0; i < numFilters; ++i) {
|
||||
geomFilter = filters[i];
|
||||
type = geomFilter.getType();
|
||||
for (i = 0; i < numTypes; ++i) {
|
||||
type = types[i];
|
||||
if (!goog.isDef(featuresToRender[type])) {
|
||||
featuresToRender[type] = {};
|
||||
}
|
||||
featuresObject = layer.getFeaturesObject(new ol.filter.Logical(
|
||||
[geomFilter, extentFilter], ol.filter.LogicalOperator.AND));
|
||||
featuresObject = layer.getFeaturesObjectForExtent(tileExtent, type);
|
||||
tileHasFeatures = tileHasFeatures ||
|
||||
!goog.object.isEmpty(featuresObject);
|
||||
goog.object.extend(featuresToRender[type], featuresObject);
|
||||
|
||||
@@ -272,22 +272,12 @@ ol.renderer.canvas.VectorRenderer.prototype.renderPointFeatures_ =
|
||||
ol.renderer.canvas.VectorRenderer.prototype.renderText_ =
|
||||
function(features, text, texts) {
|
||||
var context = this.context_,
|
||||
fontArray = [],
|
||||
color = text.color,
|
||||
vecs, vec;
|
||||
|
||||
if (color) {
|
||||
context.fillStyle = color;
|
||||
}
|
||||
if (goog.isDef(text.fontSize)) {
|
||||
fontArray.push(text.fontSize + 'px');
|
||||
}
|
||||
if (goog.isDef(text.fontFamily)) {
|
||||
fontArray.push(text.fontFamily);
|
||||
}
|
||||
if (fontArray.length) {
|
||||
context.font = fontArray.join(' ');
|
||||
if (context.fillStyle !== text.color) {
|
||||
context.fillStyle = text.color;
|
||||
}
|
||||
context.font = text.fontSize + 'px ' + text.fontFamily;
|
||||
context.globalAlpha = text.opacity;
|
||||
|
||||
// TODO: make alignments configurable
|
||||
|
||||
@@ -3,8 +3,9 @@ goog.provide('ol.style.IconLiteral');
|
||||
goog.provide('ol.style.IconType');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Expression');
|
||||
goog.require('ol.ExpressionLiteral');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.style.Point');
|
||||
goog.require('ol.style.PointLiteral');
|
||||
|
||||
@@ -69,47 +70,47 @@ ol.style.Icon = function(options) {
|
||||
goog.asserts.assert(options.url, 'url must be set');
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.url_ = (options.url instanceof ol.Expression) ?
|
||||
options.url : new ol.ExpressionLiteral(options.url);
|
||||
this.url_ = (options.url instanceof ol.expr.Expression) ?
|
||||
options.url : new ol.expr.Literal(options.url);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.width_ = !goog.isDef(options.width) ?
|
||||
null :
|
||||
(options.width instanceof ol.Expression) ?
|
||||
options.width : new ol.ExpressionLiteral(options.width);
|
||||
(options.width instanceof ol.expr.Expression) ?
|
||||
options.width : new ol.expr.Literal(options.width);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.height_ = !goog.isDef(options.height) ?
|
||||
null :
|
||||
(options.height instanceof ol.Expression) ?
|
||||
options.height : new ol.ExpressionLiteral(options.height);
|
||||
(options.height instanceof ol.expr.Expression) ?
|
||||
options.height : new ol.expr.Literal(options.height);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.opacity_ = !goog.isDef(options.opacity) ?
|
||||
new ol.ExpressionLiteral(ol.style.IconDefaults.opacity) :
|
||||
(options.opacity instanceof ol.Expression) ?
|
||||
options.opacity : new ol.ExpressionLiteral(options.opacity);
|
||||
new ol.expr.Literal(ol.style.IconDefaults.opacity) :
|
||||
(options.opacity instanceof ol.expr.Expression) ?
|
||||
options.opacity : new ol.expr.Literal(options.opacity);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.rotation_ = !goog.isDef(options.rotation) ?
|
||||
new ol.ExpressionLiteral(ol.style.IconDefaults.rotation) :
|
||||
(options.rotation instanceof ol.Expression) ?
|
||||
options.rotation : new ol.ExpressionLiteral(options.rotation);
|
||||
new ol.expr.Literal(ol.style.IconDefaults.rotation) :
|
||||
(options.rotation instanceof ol.expr.Expression) ?
|
||||
options.rotation : new ol.expr.Literal(options.rotation);
|
||||
|
||||
};
|
||||
|
||||
@@ -118,27 +119,28 @@ ol.style.Icon = function(options) {
|
||||
* @inheritDoc
|
||||
* @return {ol.style.IconLiteral} Literal shape symbolizer.
|
||||
*/
|
||||
ol.style.Icon.prototype.createLiteral = function(feature) {
|
||||
var attrs = feature && feature.getAttributes();
|
||||
ol.style.Icon.prototype.createLiteral = function(opt_feature) {
|
||||
|
||||
var url = /** @type {string} */ (this.url_.evaluate(feature, attrs));
|
||||
goog.asserts.assert(goog.isString(url) && url != '#', 'url must be a string');
|
||||
var url = ol.expr.evaluateFeature(this.url_, opt_feature);
|
||||
goog.asserts.assertString(url, 'url must be a string');
|
||||
goog.asserts.assert(url != '#', 'url must not be "#"');
|
||||
|
||||
var width = /** @type {number|undefined} */ (goog.isNull(this.width_) ?
|
||||
undefined : this.width_.evaluate(feature, attrs));
|
||||
goog.asserts.assert(!goog.isDef(width) || goog.isNumber(width),
|
||||
'width must be undefined or a number');
|
||||
var width;
|
||||
if (!goog.isNull(this.width_)) {
|
||||
width = ol.expr.evaluateFeature(this.width_, opt_feature);
|
||||
goog.asserts.assertNumber(width, 'width must be a number');
|
||||
}
|
||||
|
||||
var height = /** @type {number|undefined} */ (goog.isNull(this.height_) ?
|
||||
undefined : this.height_.evaluate(feature, attrs));
|
||||
goog.asserts.assert(!goog.isDef(height) || goog.isNumber(height),
|
||||
'height must be undefined or a number');
|
||||
var height;
|
||||
if (!goog.isNull(this.height_)) {
|
||||
height = ol.expr.evaluateFeature(this.height_, opt_feature);
|
||||
goog.asserts.assertNumber(height, 'height must be a number');
|
||||
}
|
||||
|
||||
var opacity = /** {@type {number} */ (this.opacity_.evaluate(feature, attrs));
|
||||
var opacity = ol.expr.evaluateFeature(this.opacity_, opt_feature);
|
||||
goog.asserts.assertNumber(opacity, 'opacity must be a number');
|
||||
|
||||
var rotation =
|
||||
/** {@type {number} */ (this.rotation_.evaluate(feature, attrs));
|
||||
var rotation = ol.expr.evaluateFeature(this.rotation_, opt_feature);
|
||||
goog.asserts.assertNumber(rotation, 'rotation must be a number');
|
||||
|
||||
return new ol.style.IconLiteral({
|
||||
|
||||
@@ -2,8 +2,9 @@ goog.provide('ol.style.Line');
|
||||
goog.provide('ol.style.LineLiteral');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Expression');
|
||||
goog.require('ol.ExpressionLiteral');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.style.Symbolizer');
|
||||
goog.require('ol.style.SymbolizerLiteral');
|
||||
|
||||
@@ -63,31 +64,31 @@ ol.style.Line = function(options) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.strokeColor_ = !goog.isDef(options.strokeColor) ?
|
||||
new ol.ExpressionLiteral(ol.style.LineDefaults.strokeColor) :
|
||||
(options.strokeColor instanceof ol.Expression) ?
|
||||
options.strokeColor : new ol.ExpressionLiteral(options.strokeColor);
|
||||
new ol.expr.Literal(ol.style.LineDefaults.strokeColor) :
|
||||
(options.strokeColor instanceof ol.expr.Expression) ?
|
||||
options.strokeColor : new ol.expr.Literal(options.strokeColor);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.strokeWidth_ = !goog.isDef(options.strokeWidth) ?
|
||||
new ol.ExpressionLiteral(ol.style.LineDefaults.strokeWidth) :
|
||||
(options.strokeWidth instanceof ol.Expression) ?
|
||||
options.strokeWidth : new ol.ExpressionLiteral(options.strokeWidth);
|
||||
new ol.expr.Literal(ol.style.LineDefaults.strokeWidth) :
|
||||
(options.strokeWidth instanceof ol.expr.Expression) ?
|
||||
options.strokeWidth : new ol.expr.Literal(options.strokeWidth);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.opacity_ = !goog.isDef(options.opacity) ?
|
||||
new ol.ExpressionLiteral(ol.style.LineDefaults.opacity) :
|
||||
(options.opacity instanceof ol.Expression) ?
|
||||
options.opacity : new ol.ExpressionLiteral(options.opacity);
|
||||
new ol.expr.Literal(ol.style.LineDefaults.opacity) :
|
||||
(options.opacity instanceof ol.expr.Expression) ?
|
||||
options.opacity : new ol.expr.Literal(options.opacity);
|
||||
|
||||
};
|
||||
goog.inherits(ol.style.Line, ol.style.Symbolizer);
|
||||
@@ -98,19 +99,16 @@ goog.inherits(ol.style.Line, ol.style.Symbolizer);
|
||||
* @return {ol.style.LineLiteral} Literal line symbolizer.
|
||||
*/
|
||||
ol.style.Line.prototype.createLiteral = function(opt_feature) {
|
||||
var attrs,
|
||||
feature = opt_feature;
|
||||
if (goog.isDef(feature)) {
|
||||
attrs = feature.getAttributes();
|
||||
}
|
||||
|
||||
var strokeColor = this.strokeColor_.evaluate(feature, attrs);
|
||||
var strokeColor = ol.expr.evaluateFeature(
|
||||
this.strokeColor_, opt_feature);
|
||||
goog.asserts.assertString(strokeColor, 'strokeColor must be a string');
|
||||
|
||||
var strokeWidth = this.strokeWidth_.evaluate(feature, attrs);
|
||||
var strokeWidth = ol.expr.evaluateFeature(
|
||||
this.strokeWidth_, opt_feature);
|
||||
goog.asserts.assertNumber(strokeWidth, 'strokeWidth must be a number');
|
||||
|
||||
var opacity = this.opacity_.evaluate(feature, attrs);
|
||||
var opacity = ol.expr.evaluateFeature(this.opacity_, opt_feature);
|
||||
goog.asserts.assertNumber(opacity, 'opacity must be a number');
|
||||
|
||||
return new ol.style.LineLiteral({
|
||||
|
||||
@@ -2,8 +2,9 @@ goog.provide('ol.style.Polygon');
|
||||
goog.provide('ol.style.PolygonLiteral');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Expression');
|
||||
goog.require('ol.ExpressionLiteral');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.style.Symbolizer');
|
||||
goog.require('ol.style.SymbolizerLiteral');
|
||||
|
||||
@@ -80,13 +81,13 @@ ol.style.Polygon = function(options) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.fillColor_ = !goog.isDefAndNotNull(options.fillColor) ?
|
||||
null :
|
||||
(options.fillColor instanceof ol.Expression) ?
|
||||
options.fillColor : new ol.ExpressionLiteral(options.fillColor);
|
||||
(options.fillColor instanceof ol.expr.Expression) ?
|
||||
options.fillColor : new ol.expr.Literal(options.fillColor);
|
||||
|
||||
// stroke handling - if any stroke property is supplied, use defaults
|
||||
var strokeColor = null,
|
||||
@@ -95,25 +96,33 @@ ol.style.Polygon = function(options) {
|
||||
if (goog.isDefAndNotNull(options.strokeColor) ||
|
||||
goog.isDefAndNotNull(options.strokeWidth)) {
|
||||
|
||||
strokeColor = !goog.isDefAndNotNull(options.strokeColor) ?
|
||||
new ol.ExpressionLiteral(ol.style.PolygonDefaults.strokeColor) :
|
||||
(options.strokeColor instanceof ol.Expression) ?
|
||||
options.strokeColor : new ol.ExpressionLiteral(options.strokeColor);
|
||||
if (goog.isDefAndNotNull(options.strokeColor)) {
|
||||
strokeColor = (options.strokeColor instanceof ol.expr.Expression) ?
|
||||
options.strokeColor :
|
||||
new ol.expr.Literal(options.strokeColor);
|
||||
} else {
|
||||
strokeColor = new ol.expr.Literal(
|
||||
/** @type {string} */ (ol.style.PolygonDefaults.strokeColor));
|
||||
}
|
||||
|
||||
strokeWidth = !goog.isDef(options.strokeWidth) ?
|
||||
new ol.ExpressionLiteral(ol.style.PolygonDefaults.strokeWidth) :
|
||||
(options.strokeWidth instanceof ol.Expression) ?
|
||||
options.strokeWidth : new ol.ExpressionLiteral(options.strokeWidth);
|
||||
if (goog.isDefAndNotNull(options.strokeWidth)) {
|
||||
strokeWidth = (options.strokeWidth instanceof ol.expr.Expression) ?
|
||||
options.strokeWidth :
|
||||
new ol.expr.Literal(options.strokeWidth);
|
||||
} else {
|
||||
strokeWidth = new ol.expr.Literal(
|
||||
/** @type {number} */ (ol.style.PolygonDefaults.strokeWidth));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.strokeColor_ = strokeColor;
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.strokeWidth_ = strokeWidth;
|
||||
@@ -124,13 +133,13 @@ ol.style.Polygon = function(options) {
|
||||
'Stroke or fill properties must be provided');
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.opacity_ = !goog.isDef(options.opacity) ?
|
||||
new ol.ExpressionLiteral(ol.style.PolygonDefaults.opacity) :
|
||||
(options.opacity instanceof ol.Expression) ?
|
||||
options.opacity : new ol.ExpressionLiteral(options.opacity);
|
||||
new ol.expr.Literal(ol.style.PolygonDefaults.opacity) :
|
||||
(options.opacity instanceof ol.expr.Expression) ?
|
||||
options.opacity : new ol.expr.Literal(options.opacity);
|
||||
|
||||
};
|
||||
goog.inherits(ol.style.Polygon, ol.style.Symbolizer);
|
||||
@@ -141,33 +150,31 @@ goog.inherits(ol.style.Polygon, ol.style.Symbolizer);
|
||||
* @return {ol.style.PolygonLiteral} Literal shape symbolizer.
|
||||
*/
|
||||
ol.style.Polygon.prototype.createLiteral = function(opt_feature) {
|
||||
var attrs,
|
||||
feature = opt_feature;
|
||||
if (goog.isDef(feature)) {
|
||||
attrs = feature.getAttributes();
|
||||
|
||||
var fillColor;
|
||||
if (!goog.isNull(this.fillColor_)) {
|
||||
fillColor = ol.expr.evaluateFeature(this.fillColor_, opt_feature);
|
||||
goog.asserts.assertString(fillColor, 'fillColor must be a string');
|
||||
}
|
||||
|
||||
var fillColor = goog.isNull(this.fillColor_) ?
|
||||
undefined :
|
||||
/** @type {string} */ (this.fillColor_.evaluate(feature, attrs));
|
||||
goog.asserts.assert(!goog.isDef(fillColor) || goog.isString(fillColor));
|
||||
var strokeColor;
|
||||
if (!goog.isNull(this.strokeColor_)) {
|
||||
strokeColor = ol.expr.evaluateFeature(this.strokeColor_, opt_feature);
|
||||
goog.asserts.assertString(strokeColor, 'strokeColor must be a string');
|
||||
}
|
||||
|
||||
var strokeColor = goog.isNull(this.strokeColor_) ?
|
||||
undefined :
|
||||
/** @type {string} */ (this.strokeColor_.evaluate(feature, attrs));
|
||||
goog.asserts.assert(!goog.isDef(strokeColor) || goog.isString(strokeColor));
|
||||
|
||||
var strokeWidth = goog.isNull(this.strokeWidth_) ?
|
||||
undefined :
|
||||
/** @type {number} */ (this.strokeWidth_.evaluate(feature, attrs));
|
||||
goog.asserts.assert(!goog.isDef(strokeWidth) || goog.isNumber(strokeWidth));
|
||||
var strokeWidth;
|
||||
if (!goog.isNull(this.strokeWidth_)) {
|
||||
strokeWidth = ol.expr.evaluateFeature(this.strokeWidth_, opt_feature);
|
||||
goog.asserts.assertNumber(strokeWidth, 'strokeWidth must be a number');
|
||||
}
|
||||
|
||||
goog.asserts.assert(
|
||||
goog.isDef(fillColor) ||
|
||||
(goog.isDef(strokeColor) && goog.isDef(strokeWidth)),
|
||||
'either fill style or strokeColor and strokeWidth must be defined');
|
||||
'either fillColor or strokeColor and strokeWidth must be defined');
|
||||
|
||||
var opacity = this.opacity_.evaluate(feature, attrs);
|
||||
var opacity = ol.expr.evaluateFeature(this.opacity_, opt_feature);
|
||||
goog.asserts.assertNumber(opacity, 'opacity must be a number');
|
||||
|
||||
return new ol.style.PolygonLiteral({
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
goog.provide('ol.style.Rule');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.filter.Filter');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.style.Symbolizer');
|
||||
|
||||
|
||||
@@ -12,11 +15,22 @@ goog.require('ol.style.Symbolizer');
|
||||
*/
|
||||
ol.style.Rule = function(options) {
|
||||
|
||||
|
||||
var filter = null;
|
||||
if (goog.isDef(options.filter)) {
|
||||
if (goog.isString(options.filter)) {
|
||||
filter = ol.expr.parse(options.filter);
|
||||
} else {
|
||||
goog.asserts.assert(options.filter instanceof ol.expr.Expression);
|
||||
filter = options.filter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {ol.filter.Filter}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.filter_ = goog.isDef(options.filter) ? options.filter : null;
|
||||
this.filter_ = filter;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.style.Symbolizer>}
|
||||
@@ -33,7 +47,8 @@ ol.style.Rule = function(options) {
|
||||
* @return {boolean} Does the rule apply to the feature?
|
||||
*/
|
||||
ol.style.Rule.prototype.applies = function(feature) {
|
||||
return goog.isNull(this.filter_) ? true : this.filter_.applies(feature);
|
||||
return goog.isNull(this.filter_) ?
|
||||
true : !!ol.expr.evaluateFeature(this.filter_, feature);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@ goog.provide('ol.style.ShapeLiteral');
|
||||
goog.provide('ol.style.ShapeType');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Expression');
|
||||
goog.require('ol.ExpressionLiteral');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.style.Point');
|
||||
goog.require('ol.style.PointLiteral');
|
||||
|
||||
@@ -106,22 +107,22 @@ ol.style.Shape = function(options) {
|
||||
options.type : ol.style.ShapeDefaults.type);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.size_ = !goog.isDef(options.size) ?
|
||||
new ol.ExpressionLiteral(ol.style.ShapeDefaults.size) :
|
||||
(options.size instanceof ol.Expression) ?
|
||||
options.size : new ol.ExpressionLiteral(options.size);
|
||||
new ol.expr.Literal(ol.style.ShapeDefaults.size) :
|
||||
(options.size instanceof ol.expr.Expression) ?
|
||||
options.size : new ol.expr.Literal(options.size);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.fillColor_ = !goog.isDefAndNotNull(options.fillColor) ?
|
||||
null :
|
||||
(options.fillColor instanceof ol.Expression) ?
|
||||
options.fillColor : new ol.ExpressionLiteral(options.fillColor);
|
||||
(options.fillColor instanceof ol.expr.Expression) ?
|
||||
options.fillColor : new ol.expr.Literal(options.fillColor);
|
||||
|
||||
// stroke handling - if any stroke property is supplied, use defaults
|
||||
var strokeColor = null,
|
||||
@@ -130,25 +131,34 @@ ol.style.Shape = function(options) {
|
||||
if (goog.isDefAndNotNull(options.strokeColor) ||
|
||||
goog.isDefAndNotNull(options.strokeWidth)) {
|
||||
|
||||
strokeColor = !goog.isDefAndNotNull(options.strokeColor) ?
|
||||
new ol.ExpressionLiteral(ol.style.ShapeDefaults.strokeColor) :
|
||||
(options.strokeColor instanceof ol.Expression) ?
|
||||
options.strokeColor : new ol.ExpressionLiteral(options.strokeColor);
|
||||
if (goog.isDefAndNotNull(options.strokeColor)) {
|
||||
strokeColor = (options.strokeColor instanceof ol.expr.Expression) ?
|
||||
options.strokeColor :
|
||||
new ol.expr.Literal(options.strokeColor);
|
||||
} else {
|
||||
strokeColor = new ol.expr.Literal(
|
||||
/** @type {string} */ (ol.style.ShapeDefaults.strokeColor));
|
||||
}
|
||||
|
||||
if (goog.isDefAndNotNull(options.strokeWidth)) {
|
||||
strokeWidth = (options.strokeWidth instanceof ol.expr.Expression) ?
|
||||
options.strokeWidth :
|
||||
new ol.expr.Literal(options.strokeWidth);
|
||||
} else {
|
||||
strokeWidth = new ol.expr.Literal(
|
||||
/** @type {number} */ (ol.style.ShapeDefaults.strokeWidth));
|
||||
}
|
||||
|
||||
strokeWidth = !goog.isDef(options.strokeWidth) ?
|
||||
new ol.ExpressionLiteral(ol.style.ShapeDefaults.strokeWidth) :
|
||||
(options.strokeWidth instanceof ol.Expression) ?
|
||||
options.strokeWidth : new ol.ExpressionLiteral(options.strokeWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.strokeColor_ = strokeColor;
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.strokeWidth_ = strokeWidth;
|
||||
@@ -159,13 +169,13 @@ ol.style.Shape = function(options) {
|
||||
'Stroke or fill properties must be provided');
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.opacity_ = !goog.isDef(options.opacity) ?
|
||||
new ol.ExpressionLiteral(ol.style.ShapeDefaults.opacity) :
|
||||
(options.opacity instanceof ol.Expression) ?
|
||||
options.opacity : new ol.ExpressionLiteral(options.opacity);
|
||||
new ol.expr.Literal(ol.style.ShapeDefaults.opacity) :
|
||||
(options.opacity instanceof ol.expr.Expression) ?
|
||||
options.opacity : new ol.expr.Literal(options.opacity);
|
||||
|
||||
};
|
||||
|
||||
@@ -175,36 +185,34 @@ ol.style.Shape = function(options) {
|
||||
* @return {ol.style.ShapeLiteral} Literal shape symbolizer.
|
||||
*/
|
||||
ol.style.Shape.prototype.createLiteral = function(opt_feature) {
|
||||
var attrs,
|
||||
feature = opt_feature;
|
||||
if (goog.isDef(feature)) {
|
||||
attrs = feature.getAttributes();
|
||||
}
|
||||
|
||||
var size = this.size_.evaluate(feature, attrs);
|
||||
var size = ol.expr.evaluateFeature(this.size_, opt_feature);
|
||||
goog.asserts.assertNumber(size, 'size must be a number');
|
||||
|
||||
var fillColor = goog.isNull(this.fillColor_) ?
|
||||
undefined :
|
||||
/** @type {string} */ (this.fillColor_.evaluate(feature, attrs));
|
||||
goog.asserts.assert(!goog.isDef(fillColor) || goog.isString(fillColor));
|
||||
var fillColor;
|
||||
if (!goog.isNull(this.fillColor_)) {
|
||||
fillColor = ol.expr.evaluateFeature(this.fillColor_, opt_feature);
|
||||
goog.asserts.assertString(fillColor, 'fillColor must be a string');
|
||||
}
|
||||
|
||||
var strokeColor = goog.isNull(this.strokeColor_) ?
|
||||
undefined :
|
||||
/** @type {string} */ (this.strokeColor_.evaluate(feature, attrs));
|
||||
goog.asserts.assert(!goog.isDef(strokeColor) || goog.isString(strokeColor));
|
||||
var strokeColor;
|
||||
if (!goog.isNull(this.strokeColor_)) {
|
||||
strokeColor = ol.expr.evaluateFeature(this.strokeColor_, opt_feature);
|
||||
goog.asserts.assertString(strokeColor, 'strokeColor must be a string');
|
||||
}
|
||||
|
||||
var strokeWidth = goog.isNull(this.strokeWidth_) ?
|
||||
undefined :
|
||||
/** @type {number} */ (this.strokeWidth_.evaluate(feature, attrs));
|
||||
goog.asserts.assert(!goog.isDef(strokeWidth) || goog.isNumber(strokeWidth));
|
||||
var strokeWidth;
|
||||
if (!goog.isNull(this.strokeWidth_)) {
|
||||
strokeWidth = ol.expr.evaluateFeature(this.strokeWidth_, opt_feature);
|
||||
goog.asserts.assertNumber(strokeWidth, 'strokeWidth must be a number');
|
||||
}
|
||||
|
||||
goog.asserts.assert(
|
||||
goog.isDef(fillColor) ||
|
||||
(goog.isDef(strokeColor) && goog.isDef(strokeWidth)),
|
||||
'either fill style or strokeColor and strokeWidth must be defined');
|
||||
'either fillColor or strokeColor and strokeWidth must be defined');
|
||||
|
||||
var opacity = this.opacity_.evaluate(feature, attrs);
|
||||
var opacity = ol.expr.evaluateFeature(this.opacity_, opt_feature);
|
||||
goog.asserts.assertNumber(opacity, 'opacity must be a number');
|
||||
|
||||
return new ol.style.ShapeLiteral({
|
||||
|
||||
@@ -2,8 +2,9 @@ goog.provide('ol.style.Text');
|
||||
goog.provide('ol.style.TextLiteral');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Expression');
|
||||
goog.require('ol.ExpressionLiteral');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.style.Symbolizer');
|
||||
goog.require('ol.style.SymbolizerLiteral');
|
||||
|
||||
@@ -26,18 +27,13 @@ ol.style.TextLiteralOptions;
|
||||
*/
|
||||
ol.style.TextLiteral = function(options) {
|
||||
|
||||
goog.asserts.assertString(options.color, 'color must be a string');
|
||||
/** @type {string} */
|
||||
this.color = options.color;
|
||||
if (goog.isDef(options.color)) {
|
||||
goog.asserts.assertString(options.color, 'color must be a string');
|
||||
}
|
||||
|
||||
goog.asserts.assertString(options.fontFamily, 'fontFamily must be a string');
|
||||
/** @type {string} */
|
||||
this.fontFamily = options.fontFamily;
|
||||
if (goog.isDef(options.fontFamily)) {
|
||||
goog.asserts.assertString(options.fontFamily,
|
||||
'fontFamily must be a string');
|
||||
}
|
||||
|
||||
goog.asserts.assertNumber(options.fontSize, 'fontSize must be a number');
|
||||
/** @type {number} */
|
||||
@@ -75,47 +71,47 @@ ol.style.TextLiteral.prototype.equals = function(textLiteral) {
|
||||
ol.style.Text = function(options) {
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.color_ = !goog.isDef(options.color) ?
|
||||
new ol.ExpressionLiteral(ol.style.TextDefaults.color) :
|
||||
(options.color instanceof ol.Expression) ?
|
||||
options.color : new ol.ExpressionLiteral(options.color);
|
||||
new ol.expr.Literal(ol.style.TextDefaults.color) :
|
||||
(options.color instanceof ol.expr.Expression) ?
|
||||
options.color : new ol.expr.Literal(options.color);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.fontFamily_ = !goog.isDef(options.fontFamily) ?
|
||||
new ol.ExpressionLiteral(ol.style.TextDefaults.fontFamily) :
|
||||
(options.fontFamily instanceof ol.Expression) ?
|
||||
options.fontFamily : new ol.ExpressionLiteral(options.fontFamily);
|
||||
new ol.expr.Literal(ol.style.TextDefaults.fontFamily) :
|
||||
(options.fontFamily instanceof ol.expr.Expression) ?
|
||||
options.fontFamily : new ol.expr.Literal(options.fontFamily);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.fontSize_ = !goog.isDef(options.fontSize) ?
|
||||
new ol.ExpressionLiteral(ol.style.TextDefaults.fontSize) :
|
||||
(options.fontSize instanceof ol.Expression) ?
|
||||
options.fontSize : new ol.ExpressionLiteral(options.fontSize);
|
||||
new ol.expr.Literal(ol.style.TextDefaults.fontSize) :
|
||||
(options.fontSize instanceof ol.expr.Expression) ?
|
||||
options.fontSize : new ol.expr.Literal(options.fontSize);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.text_ = (options.text instanceof ol.Expression) ?
|
||||
options.text : new ol.ExpressionLiteral(options.text);
|
||||
this.text_ = (options.text instanceof ol.expr.Expression) ?
|
||||
options.text : new ol.expr.Literal(options.text);
|
||||
|
||||
/**
|
||||
* @type {ol.Expression}
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.opacity_ = !goog.isDef(options.opacity) ?
|
||||
new ol.ExpressionLiteral(ol.style.TextDefaults.opacity) :
|
||||
(options.opacity instanceof ol.Expression) ?
|
||||
options.opacity : new ol.ExpressionLiteral(options.opacity);
|
||||
new ol.expr.Literal(ol.style.TextDefaults.opacity) :
|
||||
(options.opacity instanceof ol.expr.Expression) ?
|
||||
options.opacity : new ol.expr.Literal(options.opacity);
|
||||
|
||||
};
|
||||
goog.inherits(ol.style.Text, ol.style.Symbolizer);
|
||||
@@ -126,25 +122,20 @@ goog.inherits(ol.style.Text, ol.style.Symbolizer);
|
||||
* @return {ol.style.TextLiteral} Literal text symbolizer.
|
||||
*/
|
||||
ol.style.Text.prototype.createLiteral = function(opt_feature) {
|
||||
var attrs,
|
||||
feature = opt_feature;
|
||||
if (goog.isDef(feature)) {
|
||||
attrs = feature.getAttributes();
|
||||
}
|
||||
|
||||
var color = this.color_.evaluate(feature, attrs);
|
||||
var color = ol.expr.evaluateFeature(this.color_, opt_feature);
|
||||
goog.asserts.assertString(color, 'color must be a string');
|
||||
|
||||
var fontFamily = this.fontFamily_.evaluate(feature, attrs);
|
||||
var fontFamily = ol.expr.evaluateFeature(this.fontFamily_, opt_feature);
|
||||
goog.asserts.assertString(fontFamily, 'fontFamily must be a string');
|
||||
|
||||
var fontSize = this.fontSize_.evaluate(feature, attrs);
|
||||
var fontSize = ol.expr.evaluateFeature(this.fontSize_, opt_feature);
|
||||
goog.asserts.assertNumber(fontSize, 'fontSize must be a number');
|
||||
|
||||
var text = this.text_.evaluate(feature, attrs);
|
||||
var text = ol.expr.evaluateFeature(this.text_, opt_feature);
|
||||
goog.asserts.assertString(text, 'text must be a string');
|
||||
|
||||
var opacity = this.opacity_.evaluate(feature, attrs);
|
||||
var opacity = ol.expr.evaluateFeature(this.opacity_, opt_feature);
|
||||
goog.asserts.assertNumber(opacity, 'opacity must be a number');
|
||||
|
||||
return new ol.style.TextLiteral({
|
||||
|
||||
828
test/spec/ol/expr/expression.test.js
Normal file
828
test/spec/ol/expr/expression.test.js
Normal file
@@ -0,0 +1,828 @@
|
||||
goog.provide('ol.test.expression');
|
||||
|
||||
|
||||
describe('ol.expr.parse()', function() {
|
||||
|
||||
it('parses a subset of ECMAScript 5.1 expressions', function() {
|
||||
var expr = ol.expr.parse('foo');
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
});
|
||||
|
||||
describe('11.1 - primary expressions', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.1
|
||||
|
||||
it('parses identifier expressions', function() {
|
||||
var expr = ol.expr.parse('foo');
|
||||
expect(expr).to.be.a(ol.expr.Identifier);
|
||||
expect(expr.evaluate({foo: 'bar'})).to.be('bar');
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected', function() {
|
||||
var expr = ol.expr.parse(' foo ');
|
||||
expect(expr).to.be.a(ol.expr.Identifier);
|
||||
expect(expr.evaluate({foo: 'bar'})).to.be('bar');
|
||||
});
|
||||
|
||||
it('throws on invalid identifier expressions', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('3foo');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('f');
|
||||
expect(token.index).to.be(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses string literal expressions', function() {
|
||||
var expr = ol.expr.parse('"foo"');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be('foo');
|
||||
});
|
||||
|
||||
it('throws on unterminated string', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('"foo');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.type).to.be(ol.expr.TokenType.EOF);
|
||||
expect(token.index).to.be(4);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses numeric literal expressions', function() {
|
||||
var expr = ol.expr.parse('.42e+2');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be(42);
|
||||
});
|
||||
|
||||
it('throws on invalid number', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('.42eX');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('X');
|
||||
expect(token.index).to.be(4);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses boolean literal expressions', function() {
|
||||
var expr = ol.expr.parse('false');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
});
|
||||
|
||||
it('parses null literal expressions', function() {
|
||||
var expr = ol.expr.parse('null');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be(null);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.2 - left-hand-side expressions', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.2
|
||||
|
||||
it('parses member expressions with dot notation', function() {
|
||||
var expr = ol.expr.parse('foo.bar.baz');
|
||||
expect(expr).to.be.a(ol.expr.Member);
|
||||
var scope = {foo: {bar: {baz: 42}}};
|
||||
expect(expr.evaluate(scope)).to.be(42);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected', function() {
|
||||
var expr = ol.expr.parse(' foo . bar . baz ');
|
||||
expect(expr).to.be.a(ol.expr.Member);
|
||||
var scope = {foo: {bar: {baz: 42}}};
|
||||
expect(expr.evaluate(scope)).to.be(42);
|
||||
});
|
||||
|
||||
it('throws on invalid member expression', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('foo.4bar');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('b');
|
||||
expect(token.index).to.be(5);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses call expressions with literal arguments', function() {
|
||||
var expr = ol.expr.parse('foo(42, "bar")');
|
||||
expect(expr).to.be.a(ol.expr.Call);
|
||||
var scope = {
|
||||
foo: function(num, str) {
|
||||
expect(num).to.be(42);
|
||||
expect(str).to.be('bar');
|
||||
return str + num;
|
||||
}
|
||||
};
|
||||
expect(expr.evaluate(scope)).to.be('bar42');
|
||||
});
|
||||
|
||||
it('throws on calls with unterminated arguments', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('foo(42,)');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be(')');
|
||||
expect(token.index).to.be(7);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.3 - postfix expressions', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.3
|
||||
it('not supported');
|
||||
});
|
||||
|
||||
|
||||
describe('11.4 - unary operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.4
|
||||
|
||||
it('parses logical not operator', function() {
|
||||
var expr = ol.expr.parse('!foo');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate({foo: true})).to.be(false);
|
||||
expect(expr.evaluate({foo: false})).to.be(true);
|
||||
expect(expr.evaluate({foo: ''})).to.be(true);
|
||||
expect(expr.evaluate({foo: 'foo'})).to.be(false);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected', function() {
|
||||
var expr = ol.expr.parse(' ! foo');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate({foo: true})).to.be(false);
|
||||
expect(expr.evaluate({foo: false})).to.be(true);
|
||||
});
|
||||
|
||||
it('parses not preceeding call expression', function() {
|
||||
var lib = {
|
||||
foo: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
var expr = ol.expr.parse('!foo()');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate(null, lib)).to.be(false);
|
||||
});
|
||||
|
||||
it('parses not in call argument', function() {
|
||||
var lib = {
|
||||
foo: function(arg) {
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
var expr = ol.expr.parse('foo(!bar)');
|
||||
expect(expr).to.be.a(ol.expr.Call);
|
||||
expect(expr.evaluate({bar: true}, lib)).to.be(false);
|
||||
expect(expr.evaluate({bar: false}, lib)).to.be(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.5 - multiplicitave operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.5
|
||||
|
||||
it('parses * operator', function() {
|
||||
var expr = ol.expr.parse('foo*bar');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(200);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with *', function() {
|
||||
var expr = ol.expr.parse(' foo * bar ');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 15, bar: 2})).to.be(30);
|
||||
});
|
||||
|
||||
it('parses / operator', function() {
|
||||
var expr = ol.expr.parse('foo/12');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 10})).to.be(10 / 12);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with /', function() {
|
||||
var expr = ol.expr.parse(' 4 / bar ');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({bar: 3})).to.be(4 / 3);
|
||||
});
|
||||
|
||||
it('parses % operator', function() {
|
||||
var expr = ol.expr.parse('12%foo');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 10})).to.be(2);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with %', function() {
|
||||
var expr = ol.expr.parse(' 4 %bar ');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({bar: 3})).to.be(1);
|
||||
});
|
||||
|
||||
it('parses * in call argument', function() {
|
||||
var lib = {
|
||||
foo: function(arg) {
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
var expr = ol.expr.parse('foo(2 * bar)');
|
||||
expect(expr).to.be.a(ol.expr.Call);
|
||||
expect(expr.evaluate({bar: 3}, lib)).to.be(6);
|
||||
expect(expr.evaluate({bar: 4}, lib)).to.be(8);
|
||||
});
|
||||
|
||||
it('evaluates left to right for equal precedence', function() {
|
||||
var expr = ol.expr.parse('2 / 4 * 20 % 15');
|
||||
expect(expr.evaluate()).to.be(10);
|
||||
});
|
||||
|
||||
it('respects group precedence', function() {
|
||||
expect(ol.expr.parse('2 / 4 * (20 % 15)').evaluate()).to.be(2.5);
|
||||
expect(ol.expr.parse('2 / (4 * (20 % 15))').evaluate()).to.be(0.1);
|
||||
expect(ol.expr.parse('2 / ((4 * 20) % 15)').evaluate()).to.be(0.4);
|
||||
expect(ol.expr.parse('2 / (4 * 20) % 15').evaluate()).to.be(0.025);
|
||||
expect(ol.expr.parse('(2 / (4 * 20)) % 15').evaluate()).to.be(0.025);
|
||||
expect(ol.expr.parse('(2 / 4) * 20 % 15').evaluate()).to.be(10);
|
||||
expect(ol.expr.parse('((2 / 4) * 20) % 15').evaluate()).to.be(10);
|
||||
});
|
||||
|
||||
it('parses * in left side of comparison expression', function() {
|
||||
var expr = ol.expr.parse('foo * 2 >bar');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 4, bar: 7})).to.be(true);
|
||||
expect(expr.evaluate({foo: 4, bar: 8})).to.be(false);
|
||||
});
|
||||
|
||||
it('parses * in right side of comparison expression', function() {
|
||||
var expr = ol.expr.parse('foo > 2 * bar');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 4, bar: 1})).to.be(true);
|
||||
expect(expr.evaluate({foo: 4, bar: 2})).to.be(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.6 - additive operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.6
|
||||
|
||||
it('parses + operator', function() {
|
||||
var expr = ol.expr.parse('foo+bar');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(30);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with +', function() {
|
||||
var expr = ol.expr.parse(' foo +10 ');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 15})).to.be(25);
|
||||
});
|
||||
|
||||
it('parses - operator', function() {
|
||||
var expr = ol.expr.parse('foo-bar');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(-10);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with -', function() {
|
||||
var expr = ol.expr.parse(' foo- 10 ');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 15})).to.be(5);
|
||||
});
|
||||
|
||||
it('respects precedence', function() {
|
||||
expect(ol.expr.parse('2 + 4 * 20 - 15').evaluate()).to.be(67);
|
||||
expect(ol.expr.parse('(2 + 4) * 20 - 15').evaluate()).to.be(105);
|
||||
expect(ol.expr.parse('((2 + 4) * 20) - 15').evaluate()).to.be(105);
|
||||
expect(ol.expr.parse('(2 + (4 * 20)) - 15').evaluate()).to.be(67);
|
||||
expect(ol.expr.parse('2 + (4 * 20) - 15').evaluate()).to.be(67);
|
||||
expect(ol.expr.parse('2 + ((4 * 20) - 15)').evaluate()).to.be(67);
|
||||
expect(ol.expr.parse('2 + (4 * (20 - 15))').evaluate()).to.be(22);
|
||||
expect(ol.expr.parse('2 + 4 * (20 - 15)').evaluate()).to.be(22);
|
||||
});
|
||||
|
||||
it('parses + in call argument', function() {
|
||||
var lib = {
|
||||
foo: function(arg) {
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
var expr = ol.expr.parse('foo(2 + bar)');
|
||||
expect(expr).to.be.a(ol.expr.Call);
|
||||
expect(expr.evaluate({bar: 3}, lib)).to.be(5);
|
||||
expect(expr.evaluate({bar: 4}, lib)).to.be(6);
|
||||
});
|
||||
|
||||
it('parses + in left side of comparison expression', function() {
|
||||
var expr = ol.expr.parse('foo+2>bar');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 4, bar: 5})).to.be(true);
|
||||
expect(expr.evaluate({foo: 4, bar: 6})).to.be(false);
|
||||
});
|
||||
|
||||
it('parses + in right side of comparison expression', function() {
|
||||
var expr = ol.expr.parse('foo >2 +bar');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 4, bar: 1})).to.be(true);
|
||||
expect(expr.evaluate({foo: 4, bar: 2})).to.be(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.7 - bitwise shift operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.7
|
||||
it('not supported');
|
||||
});
|
||||
|
||||
describe('11.8 - relational operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.8
|
||||
|
||||
it('parses < operator', function() {
|
||||
var expr = ol.expr.parse('foo<bar');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(true);
|
||||
expect(expr.evaluate({foo: 100, bar: 20})).to.be(false);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with <', function() {
|
||||
var expr = ol.expr.parse(' foo <10 ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 15})).to.be(false);
|
||||
expect(expr.evaluate({foo: 5})).to.be(true);
|
||||
});
|
||||
|
||||
it('parses > operator', function() {
|
||||
var expr = ol.expr.parse('foo>bar');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(false);
|
||||
expect(expr.evaluate({foo: 100, bar: 20})).to.be(true);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with >', function() {
|
||||
var expr = ol.expr.parse(' foo> 10 ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 15})).to.be(true);
|
||||
expect(expr.evaluate({foo: 5})).to.be(false);
|
||||
});
|
||||
|
||||
it('parses <= operator', function() {
|
||||
var expr = ol.expr.parse('foo<=bar');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(true);
|
||||
expect(expr.evaluate({foo: 100, bar: 20})).to.be(false);
|
||||
expect(expr.evaluate({foo: 20, bar: 20})).to.be(true);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with <=', function() {
|
||||
var expr = ol.expr.parse(' foo<= 10 ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 15})).to.be(false);
|
||||
expect(expr.evaluate({foo: 5})).to.be(true);
|
||||
expect(expr.evaluate({foo: 10})).to.be(true);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with <=', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse(' foo< = 10 ');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('=');
|
||||
expect(token.index).to.be(6);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses >= operator', function() {
|
||||
var expr = ol.expr.parse('foo>=bar');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(false);
|
||||
expect(expr.evaluate({foo: 100, bar: 20})).to.be(true);
|
||||
expect(expr.evaluate({foo: 20, bar: 20})).to.be(true);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with >=', function() {
|
||||
var expr = ol.expr.parse(' foo >=10 ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 15})).to.be(true);
|
||||
expect(expr.evaluate({foo: 5})).to.be(false);
|
||||
expect(expr.evaluate({foo: 10})).to.be(true);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with >=', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse(' 10 > =foo ');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('=');
|
||||
expect(token.index).to.be(6);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.9 - equality operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.9
|
||||
|
||||
it('parses == operator', function() {
|
||||
var expr = ol.expr.parse('foo==42');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: 41})).to.be(false);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(true);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with ==', function() {
|
||||
var expr = ol.expr.parse(' 42 ==foo ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: 41})).to.be(false);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(true);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with ==', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse(' 10 = =foo ');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('=');
|
||||
expect(token.index).to.be(4);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses != operator', function() {
|
||||
var expr = ol.expr.parse('foo!=42');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: 41})).to.be(true);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(false);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with !=', function() {
|
||||
var expr = ol.expr.parse(' 42 !=foo ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: 41})).to.be(true);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(false);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with !=', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse(' 10! =foo ');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('!');
|
||||
expect(token.index).to.be(3);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses === operator', function() {
|
||||
var expr = ol.expr.parse('42===foo');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: 41})).to.be(false);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(false);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with ===', function() {
|
||||
var expr = ol.expr.parse(' foo ===42 ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: 41})).to.be(false);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(false);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with ===', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse(' 10 = == foo ');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('=');
|
||||
expect(token.index).to.be(4);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses !== operator', function() {
|
||||
var expr = ol.expr.parse('foo!==42');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: 41})).to.be(true);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(true);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with !==', function() {
|
||||
var expr = ol.expr.parse(' 42 !== foo ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: 41})).to.be(true);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(true);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with !==', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse(' 10 != = foo ');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('=');
|
||||
expect(token.index).to.be(7);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('11.10 - binary bitwise operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.10
|
||||
it('not supported');
|
||||
});
|
||||
|
||||
describe('11.11 - binary logical operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.11
|
||||
|
||||
it('parses && operator', function() {
|
||||
var expr = ol.expr.parse('foo&&bar');
|
||||
expect(expr).to.be.a(ol.expr.Logical);
|
||||
expect(expr.evaluate({foo: true, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: true, bar: false})).to.be(false);
|
||||
expect(expr.evaluate({foo: false, bar: true})).to.be(false);
|
||||
expect(expr.evaluate({foo: false, bar: false})).to.be(false);
|
||||
});
|
||||
|
||||
it('consumes space as expected with &&', function() {
|
||||
var expr = ol.expr.parse(' foo && bar ');
|
||||
expect(expr).to.be.a(ol.expr.Logical);
|
||||
expect(expr.evaluate({foo: true, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: true, bar: false})).to.be(false);
|
||||
expect(expr.evaluate({foo: false, bar: true})).to.be(false);
|
||||
expect(expr.evaluate({foo: false, bar: false})).to.be(false);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with &&', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('true & & false');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('&');
|
||||
expect(token.index).to.be(5);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses || operator', function() {
|
||||
var expr = ol.expr.parse('foo||bar');
|
||||
expect(expr).to.be.a(ol.expr.Logical);
|
||||
expect(expr.evaluate({foo: true, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: true, bar: false})).to.be(true);
|
||||
expect(expr.evaluate({foo: false, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: false, bar: false})).to.be(false);
|
||||
});
|
||||
|
||||
it('consumes space as expected with ||', function() {
|
||||
var expr = ol.expr.parse(' foo || bar ');
|
||||
expect(expr).to.be.a(ol.expr.Logical);
|
||||
expect(expr.evaluate({foo: true, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: true, bar: false})).to.be(true);
|
||||
expect(expr.evaluate({foo: false, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: false, bar: false})).to.be(false);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with ||', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('true | | false');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('|');
|
||||
expect(token.index).to.be(5);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.12 - conditional operator', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.12
|
||||
it('not supported');
|
||||
});
|
||||
|
||||
describe('11.13 - assignment operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.13
|
||||
it('not supported');
|
||||
});
|
||||
|
||||
describe('11.14 - comma operator', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.14
|
||||
it('not supported');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.expr.lib', function() {
|
||||
|
||||
var parse = ol.expr.parse;
|
||||
var evaluate = ol.expr.evaluateFeature;
|
||||
|
||||
describe('extent()', function() {
|
||||
|
||||
var nw = new ol.Feature({
|
||||
geom: new ol.geom.Polygon([[
|
||||
[-180, 90], [0, 90], [0, 0], [-180, 0], [-180, 90]
|
||||
]])
|
||||
});
|
||||
|
||||
var se = new ol.Feature({
|
||||
geom: new ol.geom.Polygon([[
|
||||
[180, -90], [0, -90], [0, 0], [180, 0], [180, -90]
|
||||
]])
|
||||
});
|
||||
|
||||
var north = parse('extent(-100, 100, 40, 60)');
|
||||
var south = parse('extent(-100, 100, -60, -40)');
|
||||
var east = parse('extent(80, 100, -50, 50)');
|
||||
var west = parse('extent(-100, -80, -50, 50)');
|
||||
|
||||
it('evaluates to true for features within given extent', function() {
|
||||
|
||||
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('fid()', function() {
|
||||
|
||||
var one = new ol.Feature();
|
||||
one.setFeatureId('one');
|
||||
|
||||
var two = new ol.Feature();
|
||||
two.setFeatureId('two');
|
||||
|
||||
var three = new ol.Feature();
|
||||
three.setFeatureId('three');
|
||||
|
||||
var four = new ol.Feature();
|
||||
four.setFeatureId('four');
|
||||
|
||||
var odd = parse('fid("one", "three")');
|
||||
var even = parse('fid("two", "four")');
|
||||
var first = parse('fid("one")');
|
||||
var last = parse('fid("four")');
|
||||
var none = parse('fid("foo")');
|
||||
|
||||
it('evaluates to true if feature id matches', function() {
|
||||
expect(evaluate(odd, one), true);
|
||||
expect(evaluate(odd, three), true);
|
||||
expect(evaluate(even, two), true);
|
||||
expect(evaluate(even, four), true);
|
||||
expect(evaluate(first, one), true);
|
||||
expect(evaluate(last, four), true);
|
||||
});
|
||||
|
||||
it('evaluates to false if feature id doesn\'t match', function() {
|
||||
expect(evaluate(odd, two), false);
|
||||
expect(evaluate(odd, four), false);
|
||||
expect(evaluate(even, one), false);
|
||||
expect(evaluate(even, three), false);
|
||||
expect(evaluate(first, two), false);
|
||||
expect(evaluate(first, three), false);
|
||||
expect(evaluate(first, four), false);
|
||||
expect(evaluate(last, one), false);
|
||||
expect(evaluate(last, two), false);
|
||||
expect(evaluate(last, three), false);
|
||||
expect(evaluate(none, one), false);
|
||||
expect(evaluate(none, two), false);
|
||||
expect(evaluate(none, three), false);
|
||||
expect(evaluate(none, four), 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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.expr.register()', function() {
|
||||
|
||||
var spy;
|
||||
beforeEach(function() {
|
||||
spy = sinon.spy();
|
||||
});
|
||||
|
||||
it('registers custom functions in ol.expr.lib', function() {
|
||||
ol.expr.register('someFunc', spy);
|
||||
expect(ol.expr.lib.someFunc).to.be(spy);
|
||||
});
|
||||
|
||||
it('allows custom functions to be called', function() {
|
||||
ol.expr.register('myFunc', spy);
|
||||
var expr = ol.expr.parse('myFunc(42)');
|
||||
expr.evaluate(null, ol.expr.lib);
|
||||
expect(spy.calledOnce);
|
||||
expect(spy.calledWithExactly(42));
|
||||
});
|
||||
|
||||
it('allows custom functions to be called with identifiers', function() {
|
||||
ol.expr.register('myFunc', spy);
|
||||
var expr = ol.expr.parse('myFunc(foo, 42)');
|
||||
expr.evaluate({foo: 'bar'}, ol.expr.lib);
|
||||
expect(spy.calledOnce);
|
||||
expect(spy.calledWithExactly('bar', 42));
|
||||
});
|
||||
|
||||
it('allows custom functions to be called with custom this obj', function() {
|
||||
ol.expr.register('myFunc', spy);
|
||||
var expr = ol.expr.parse('myFunc(foo, 42)');
|
||||
var that = {};
|
||||
expr.evaluate({foo: 'bar'}, ol.expr.lib, that);
|
||||
expect(spy.calledOnce);
|
||||
expect(spy.calledWithExactly('bar', 42));
|
||||
expect(spy.calledOn(that));
|
||||
});
|
||||
|
||||
it('allows overriding existing ol.expr.lib functions', function() {
|
||||
var orig = ol.expr.lib.extent;
|
||||
expect(orig).not.to.be(spy);
|
||||
ol.expr.register('extent', spy);
|
||||
expect(ol.expr.lib.extent).to.be(spy);
|
||||
ol.expr.lib.extent = orig;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.expr.Call');
|
||||
goog.require('ol.expr.Comparison');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Identifier');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.expr.Logical');
|
||||
goog.require('ol.expr.Math');
|
||||
goog.require('ol.expr.Member');
|
||||
goog.require('ol.expr.Not');
|
||||
goog.require('ol.expr.TokenType');
|
||||
goog.require('ol.expr.UnexpectedToken');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.Polygon');
|
||||
638
test/spec/ol/expr/expressions.test.js
Normal file
638
test/spec/ol/expr/expressions.test.js
Normal file
@@ -0,0 +1,638 @@
|
||||
goog.provide('ol.test.expression.Expression');
|
||||
|
||||
|
||||
describe('ol.expr.Call', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Call(
|
||||
new ol.expr.Identifier('sqrt'),
|
||||
[new ol.expr.Literal(42)]);
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Call);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
var fns = {
|
||||
sqrt: function(value) {
|
||||
return Math.sqrt(value);
|
||||
},
|
||||
strConcat: function() {
|
||||
return Array.prototype.join.call(arguments, '');
|
||||
},
|
||||
discouraged: function() {
|
||||
return this.message;
|
||||
}
|
||||
};
|
||||
|
||||
it('calls method on scope with literal args', function() {
|
||||
var expr = new ol.expr.Call(
|
||||
new ol.expr.Identifier('sqrt'),
|
||||
[new ol.expr.Literal(42)]);
|
||||
expect(expr.evaluate(fns)).to.be(Math.sqrt(42));
|
||||
});
|
||||
|
||||
it('accepts a separate scope for functions', function() {
|
||||
var expr = new ol.expr.Call(
|
||||
new ol.expr.Identifier('sqrt'),
|
||||
[new ol.expr.Identifier('foo')]);
|
||||
expect(expr.evaluate({foo: 42}, fns)).to.be(Math.sqrt(42));
|
||||
});
|
||||
|
||||
it('accepts multiple expression arguments', function() {
|
||||
var expr = new ol.expr.Call(
|
||||
new ol.expr.Identifier('strConcat'),
|
||||
[
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(' comes after '),
|
||||
new ol.expr.Math(
|
||||
ol.expr.MathOp.SUBTRACT,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(1))
|
||||
]);
|
||||
expect(expr.evaluate({foo: 42}, fns)).to.be('42 comes after 41');
|
||||
});
|
||||
|
||||
it('accepts optional this arg', function() {
|
||||
var expr = new ol.expr.Call(
|
||||
new ol.expr.Identifier('discouraged'), []);
|
||||
|
||||
var thisArg = {
|
||||
message: 'avoid this'
|
||||
};
|
||||
|
||||
expect(expr.evaluate(fns, null, thisArg)).to.be('avoid this');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
var callee = new ol.expr.Identifier('sqrt');
|
||||
var args = [new ol.expr.Literal(42)];
|
||||
var expr = new ol.expr.Call(callee, args);
|
||||
|
||||
describe('#getArgs()', function() {
|
||||
it('gets the callee expression', function() {
|
||||
expect(expr.getArgs()).to.be(args);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getCallee()', function() {
|
||||
it('gets the callee expression', function() {
|
||||
expect(expr.getCallee()).to.be(callee);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('ol.expr.Comparison', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.EQ,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('compares with ==', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.EQ,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(true);
|
||||
expect(expr.evaluate({foo: true})).to.be(false);
|
||||
expect(expr.evaluate({bar: true})).to.be(false);
|
||||
});
|
||||
|
||||
it('compares with !=', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.NEQ,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(false);
|
||||
expect(expr.evaluate({foo: true})).to.be(true);
|
||||
expect(expr.evaluate({bar: true})).to.be(true);
|
||||
});
|
||||
|
||||
it('compares with ===', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.STRICT_EQ,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(false);
|
||||
expect(expr.evaluate({foo: true})).to.be(false);
|
||||
expect(expr.evaluate({bar: true})).to.be(false);
|
||||
});
|
||||
|
||||
it('compares with !==', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.STRICT_NEQ,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(true);
|
||||
expect(expr.evaluate({foo: true})).to.be(true);
|
||||
expect(expr.evaluate({bar: true})).to.be(true);
|
||||
});
|
||||
|
||||
it('compares with >', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.GT,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: 41})).to.be(false);
|
||||
expect(expr.evaluate({foo: 43})).to.be(true);
|
||||
});
|
||||
|
||||
it('compares with <', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.LT,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: 41})).to.be(true);
|
||||
expect(expr.evaluate({foo: 43})).to.be(false);
|
||||
});
|
||||
|
||||
it('compares with >=', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.GTE,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: 41})).to.be(false);
|
||||
expect(expr.evaluate({foo: 43})).to.be(true);
|
||||
});
|
||||
|
||||
it('compares with <=', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.LTE,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: 41})).to.be(true);
|
||||
expect(expr.evaluate({foo: 43})).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isValidOp()', function() {
|
||||
it('determines if a string is a valid operator', function() {
|
||||
expect(ol.expr.Comparison.isValidOp('<')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('<')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('<=')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('<=')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('==')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('!=')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('===')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('!==')).to.be(true);
|
||||
|
||||
expect(ol.expr.Comparison.isValidOp('')).to.be(false);
|
||||
expect(ol.expr.Comparison.isValidOp('+')).to.be(false);
|
||||
expect(ol.expr.Comparison.isValidOp('-')).to.be(false);
|
||||
expect(ol.expr.Comparison.isValidOp('&&')).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
var op = ol.expr.ComparisonOp.LTE;
|
||||
var left = new ol.expr.Identifier('foo');
|
||||
var right = new ol.expr.Literal(42);
|
||||
var expr = new ol.expr.Comparison(op, left, right);
|
||||
|
||||
describe('#getOperator()', function() {
|
||||
it('gets the operator', function() {
|
||||
expect(expr.getOperator()).to.be(op);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getLeft()', function() {
|
||||
it('gets the left expression', function() {
|
||||
expect(expr.getLeft()).to.be(left);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getRight()', function() {
|
||||
it('gets the right expression', function() {
|
||||
expect(expr.getRight()).to.be(right);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.expr.Identifier', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Identifier('foo');
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Identifier);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('returns a number from the scope', function() {
|
||||
var expr = new ol.expr.Identifier('foo');
|
||||
expect(expr.evaluate({foo: 42})).to.be(42);
|
||||
});
|
||||
|
||||
it('returns a string from the scope', function() {
|
||||
var expr = new ol.expr.Identifier('foo');
|
||||
expect(expr.evaluate({foo: 'chicken'})).to.be('chicken');
|
||||
});
|
||||
|
||||
it('returns a boolean from the scope', function() {
|
||||
var expr = new ol.expr.Identifier('bar');
|
||||
expect(expr.evaluate({bar: false})).to.be(false);
|
||||
expect(expr.evaluate({bar: true})).to.be(true);
|
||||
});
|
||||
|
||||
it('returns a null from the scope', function() {
|
||||
var expr = new ol.expr.Identifier('nada');
|
||||
expect(expr.evaluate({nada: null})).to.be(null);
|
||||
});
|
||||
|
||||
it('works for unicode identifiers', function() {
|
||||
var expr = new ol.expr.Identifier('\u03c0');
|
||||
expect(expr.evaluate({'\u03c0': Math.PI})).to.be(Math.PI);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getName()', function() {
|
||||
var expr = new ol.expr.Identifier('asdf');
|
||||
expect(expr.getName()).to.be('asdf');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.expr.Literal', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Literal(true);
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('works for numeric literal', function() {
|
||||
var expr = new ol.expr.Literal(42e-11);
|
||||
expect(expr.evaluate()).to.be(4.2e-10);
|
||||
});
|
||||
|
||||
it('works for string literal', function() {
|
||||
var expr = new ol.expr.Literal('asdf');
|
||||
expect(expr.evaluate()).to.be('asdf');
|
||||
});
|
||||
|
||||
it('works for boolean literal', function() {
|
||||
var expr = new ol.expr.Literal(true);
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('works for null literal', function() {
|
||||
var expr = new ol.expr.Literal(null);
|
||||
expect(expr.evaluate()).to.be(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getValue()', function() {
|
||||
var expr = new ol.expr.Literal('asdf');
|
||||
expect(expr.getValue()).to.be('asdf');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('ol.expr.Logical', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Logical(
|
||||
ol.expr.LogicalOp.OR,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Identifier('bar'));
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Logical);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('applies || to resolved identifiers', function() {
|
||||
var expr = new ol.expr.Logical(
|
||||
ol.expr.LogicalOp.OR,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Identifier('bar'));
|
||||
|
||||
expect(expr.evaluate({foo: true, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: true, bar: false})).to.be(true);
|
||||
expect(expr.evaluate({foo: false, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: false, bar: false})).to.be(false);
|
||||
});
|
||||
|
||||
it('applies && to resolved identifiers', function() {
|
||||
var expr = new ol.expr.Logical(
|
||||
ol.expr.LogicalOp.AND,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Identifier('bar'));
|
||||
|
||||
expect(expr.evaluate({foo: true, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: true, bar: false})).to.be(false);
|
||||
expect(expr.evaluate({foo: false, bar: true})).to.be(false);
|
||||
expect(expr.evaluate({foo: false, bar: false})).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isValidOp()', function() {
|
||||
it('determines if a string is a valid operator', function() {
|
||||
expect(ol.expr.Logical.isValidOp('||')).to.be(true);
|
||||
expect(ol.expr.Logical.isValidOp('&&')).to.be(true);
|
||||
|
||||
expect(ol.expr.Logical.isValidOp('')).to.be(false);
|
||||
expect(ol.expr.Logical.isValidOp('+')).to.be(false);
|
||||
expect(ol.expr.Logical.isValidOp('<')).to.be(false);
|
||||
expect(ol.expr.Logical.isValidOp('|')).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
var op = ol.expr.LogicalOp.AND;
|
||||
var left = new ol.expr.Identifier('foo');
|
||||
var right = new ol.expr.Literal(false);
|
||||
var expr = new ol.expr.Logical(op, left, right);
|
||||
|
||||
describe('#getOperator()', function() {
|
||||
it('gets the operator', function() {
|
||||
expect(expr.getOperator()).to.be(op);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getLeft()', function() {
|
||||
it('gets the left expression', function() {
|
||||
expect(expr.getLeft()).to.be(left);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getRight()', function() {
|
||||
it('gets the right expression', function() {
|
||||
expect(expr.getRight()).to.be(right);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.expr.Math', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.ADD,
|
||||
new ol.expr.Literal(40),
|
||||
new ol.expr.Literal(2));
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('does + with numeric literal', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.ADD,
|
||||
new ol.expr.Literal(40),
|
||||
new ol.expr.Literal(2));
|
||||
|
||||
expect(expr.evaluate()).to.be(42);
|
||||
});
|
||||
|
||||
it('does + with string literal (note: subject to change)', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.ADD,
|
||||
new ol.expr.Literal('foo'),
|
||||
new ol.expr.Literal('bar'));
|
||||
|
||||
expect(expr.evaluate()).to.be('foobar');
|
||||
});
|
||||
|
||||
it('does + with identifiers', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.ADD,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Identifier('bar'));
|
||||
|
||||
expect(expr.evaluate({foo: 40, bar: 2})).to.be(42);
|
||||
});
|
||||
|
||||
it('does - with identifiers', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.SUBTRACT,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(2));
|
||||
|
||||
expect(expr.evaluate({foo: 40})).to.be(38);
|
||||
});
|
||||
|
||||
it('casts to number with - (note: this may throw later)', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.SUBTRACT,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(2));
|
||||
|
||||
expect(expr.evaluate({foo: '40'})).to.be(38);
|
||||
});
|
||||
|
||||
it('does * with identifiers', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.MULTIPLY,
|
||||
new ol.expr.Literal(2),
|
||||
new ol.expr.Identifier('foo'));
|
||||
|
||||
expect(expr.evaluate({foo: 21})).to.be(42);
|
||||
});
|
||||
|
||||
it('casts to number with * (note: this may throw later)', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.MULTIPLY,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(2));
|
||||
|
||||
expect(expr.evaluate({foo: '21'})).to.be(42);
|
||||
});
|
||||
|
||||
it('does % with identifiers', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.MOD,
|
||||
new ol.expr.Literal(97),
|
||||
new ol.expr.Identifier('foo'));
|
||||
|
||||
expect(expr.evaluate({foo: 55})).to.be(42);
|
||||
});
|
||||
|
||||
it('casts to number with % (note: this may throw later)', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.MOD,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(100));
|
||||
|
||||
expect(expr.evaluate({foo: '150'})).to.be(50);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isValidOp()', function() {
|
||||
it('determines if a string is a valid operator', function() {
|
||||
expect(ol.expr.Math.isValidOp('+')).to.be(true);
|
||||
expect(ol.expr.Math.isValidOp('-')).to.be(true);
|
||||
expect(ol.expr.Math.isValidOp('*')).to.be(true);
|
||||
expect(ol.expr.Math.isValidOp('/')).to.be(true);
|
||||
expect(ol.expr.Math.isValidOp('%')).to.be(true);
|
||||
|
||||
expect(ol.expr.Math.isValidOp('')).to.be(false);
|
||||
expect(ol.expr.Math.isValidOp('|')).to.be(false);
|
||||
expect(ol.expr.Math.isValidOp('&')).to.be(false);
|
||||
expect(ol.expr.Math.isValidOp('<')).to.be(false);
|
||||
expect(ol.expr.Math.isValidOp('||')).to.be(false);
|
||||
expect(ol.expr.Math.isValidOp('.')).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
var op = ol.expr.MathOp.MOD;
|
||||
var left = new ol.expr.Identifier('foo');
|
||||
var right = new ol.expr.Literal(20);
|
||||
var expr = new ol.expr.Math(op, left, right);
|
||||
|
||||
describe('#getOperator()', function() {
|
||||
it('gets the operator', function() {
|
||||
expect(expr.getOperator()).to.be(op);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getLeft()', function() {
|
||||
it('gets the left expression', function() {
|
||||
expect(expr.getLeft()).to.be(left);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getRight()', function() {
|
||||
it('gets the right expression', function() {
|
||||
expect(expr.getRight()).to.be(right);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.expr.Member', function() {
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Member(
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Identifier('bar'));
|
||||
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Member);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('accesses an object property', function() {
|
||||
|
||||
var expr = new ol.expr.Member(
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Identifier('bar'));
|
||||
|
||||
var scope = {foo: {bar: 42}};
|
||||
expect(expr.evaluate(scope)).to.be(42);
|
||||
});
|
||||
});
|
||||
|
||||
var object = new ol.expr.Identifier('foo');
|
||||
var property = new ol.expr.Identifier('bar');
|
||||
var expr = new ol.expr.Member(object, property);
|
||||
|
||||
describe('#getObject()', function() {
|
||||
expect(expr.getObject()).to.be(object);
|
||||
});
|
||||
|
||||
describe('#getProperty()', function() {
|
||||
expect(expr.getProperty()).to.be(property);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('ol.expr.Not', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Not(
|
||||
new ol.expr.Literal(true));
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('returns the logical complement', function() {
|
||||
var expr = new ol.expr.Not(new ol.expr.Literal(true));
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
|
||||
expr = new ol.expr.Not(new ol.expr.Literal(false));
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('negates a truthy string', function() {
|
||||
var expr = new ol.expr.Not(new ol.expr.Literal('asdf'));
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
});
|
||||
|
||||
it('negates a falsy string', function() {
|
||||
var expr = new ol.expr.Not(new ol.expr.Literal(''));
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('negates a truthy number', function() {
|
||||
var expr = new ol.expr.Not(new ol.expr.Literal(42));
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
});
|
||||
|
||||
it('negates a falsy number', function() {
|
||||
var expr = new ol.expr.Not(new ol.expr.Literal(NaN));
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getArgument()', function() {
|
||||
var argument = new ol.expr.Literal(true);
|
||||
var expr = new ol.expr.Not(argument);
|
||||
expect(expr.getArgument()).to.be(argument);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
goog.require('ol.expr.Call');
|
||||
goog.require('ol.expr.Comparison');
|
||||
goog.require('ol.expr.ComparisonOp');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Identifier');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.expr.Logical');
|
||||
goog.require('ol.expr.LogicalOp');
|
||||
goog.require('ol.expr.Math');
|
||||
goog.require('ol.expr.MathOp');
|
||||
goog.require('ol.expr.Member');
|
||||
goog.require('ol.expr.Not');
|
||||
509
test/spec/ol/expr/lexer.test.js
Normal file
509
test/spec/ol/expr/lexer.test.js
Normal file
@@ -0,0 +1,509 @@
|
||||
goog.provide('ol.test.expression.Lexer');
|
||||
|
||||
describe('ol.expr.Lexer', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new lexer', function() {
|
||||
var lexer = new ol.expr.Lexer('foo');
|
||||
expect(lexer).to.be.a(ol.expr.Lexer);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#next()', function() {
|
||||
|
||||
it('returns one token at a time', function() {
|
||||
var source = 'foo === "bar"';
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
|
||||
// scan first token
|
||||
var token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
expect(token.value).to.be('foo');
|
||||
|
||||
// scan second token
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
expect(token.value).to.be('===');
|
||||
|
||||
// scan third token
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
expect(token.value).to.be('bar');
|
||||
|
||||
// scan again
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.EOF);
|
||||
|
||||
// and again
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.EOF);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#peek()', function() {
|
||||
|
||||
var lexer;
|
||||
beforeEach(function() {
|
||||
lexer = new ol.expr.Lexer('foo > 42 && bar == "chicken"');
|
||||
});
|
||||
|
||||
it('looks ahead without consuming token', function() {
|
||||
var token = lexer.peek();
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
expect(token.value).to.be('foo');
|
||||
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
expect(token.value).to.be('foo');
|
||||
});
|
||||
|
||||
it('works after a couple scans', function() {
|
||||
var token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
expect(token.value).to.be('foo');
|
||||
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
expect(token.value).to.be('>');
|
||||
|
||||
token = lexer.peek();
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
expect(token.value).to.be(42);
|
||||
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
expect(token.value).to.be(42);
|
||||
});
|
||||
|
||||
it('returns the same thing when called multiple times', function() {
|
||||
var token = lexer.peek();
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
expect(token.value).to.be('foo');
|
||||
|
||||
for (var i = 0; i < 10; ++i) {
|
||||
token = lexer.peek();
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
expect(token.value).to.be('foo');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('#scanIdentifier_()', function() {
|
||||
|
||||
function scan(source, part) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var token = lexer.scanIdentifier_(lexer.getCurrentCharCode_());
|
||||
if (!part) {
|
||||
expect(token.index).to.be(0);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
it('works for short identifiers', function() {
|
||||
var token = scan('a');
|
||||
expect(token.value).to.be('a');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
it('works for longer identifiers', function() {
|
||||
var token = scan('foo');
|
||||
expect(token.value).to.be('foo');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
it('works for $ anywhere', function() {
|
||||
var token = scan('$foo$bar$');
|
||||
expect(token.value).to.be('$foo$bar$');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
it('works for _ anywhere', function() {
|
||||
var token = scan('_foo_bar_');
|
||||
expect(token.value).to.be('_foo_bar_');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
it('works for keywords', function() {
|
||||
var token = scan('delete');
|
||||
expect(token.value).to.be('delete');
|
||||
expect(token.type).to.be(ol.expr.TokenType.KEYWORD);
|
||||
});
|
||||
|
||||
it('works for null', function() {
|
||||
var token = scan('null');
|
||||
expect(token.value).to.be('null');
|
||||
expect(token.type).to.be(ol.expr.TokenType.NULL_LITERAL);
|
||||
});
|
||||
|
||||
it('works for boolean true', function() {
|
||||
var token = scan('true');
|
||||
expect(token.value).to.be('true');
|
||||
expect(token.type).to.be(ol.expr.TokenType.BOOLEAN_LITERAL);
|
||||
});
|
||||
|
||||
it('works for boolean false', function() {
|
||||
var token = scan('false');
|
||||
expect(token.value).to.be('false');
|
||||
expect(token.type).to.be(ol.expr.TokenType.BOOLEAN_LITERAL);
|
||||
});
|
||||
|
||||
it('works with unicode escape sequences', function() {
|
||||
var token = scan('\u006f\u006c\u0033');
|
||||
expect(token.value).to.be('ol3');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
it('works with hex escape sequences', function() {
|
||||
var token = scan('\x6f\x6c\x33');
|
||||
expect(token.value).to.be('ol3');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
it('throws for identifiers starting with a number', function() {
|
||||
expect(function() {
|
||||
scan('4foo');
|
||||
}).throwException();
|
||||
});
|
||||
|
||||
it('throws for identifiers starting with a punctuation char', function() {
|
||||
expect(function() {
|
||||
scan('!foo');
|
||||
}).throwException();
|
||||
});
|
||||
|
||||
it('only scans valid identifier part', function() {
|
||||
var token = scan('foo>bar', true);
|
||||
expect(token.value).to.be('foo');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#scanNumericLiteral_()', function() {
|
||||
|
||||
function scan(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var token = lexer.scanNumericLiteral_(lexer.getCurrentCharCode_());
|
||||
expect(token.index).to.be(0);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return token;
|
||||
}
|
||||
|
||||
it('works for integers', function() {
|
||||
var token = scan('123');
|
||||
expect(token.value).to.be(123);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('throws for bogus integer', function() {
|
||||
expect(function() {
|
||||
scan('123z');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('z');
|
||||
expect(token.index).to.be(3);
|
||||
});
|
||||
});
|
||||
|
||||
it('works for float', function() {
|
||||
var token = scan('123.456');
|
||||
expect(token.value).to.be(123.456);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('throws for bogus float', function() {
|
||||
expect(function() {
|
||||
scan('123.4x4');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('x');
|
||||
expect(token.index).to.be(5);
|
||||
});
|
||||
});
|
||||
|
||||
it('works with exponent', function() {
|
||||
var token = scan('1.234e5');
|
||||
expect(token.value).to.be(1.234e5);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('works with explicit positive exponent', function() {
|
||||
var token = scan('1.234e+5');
|
||||
expect(token.value).to.be(1.234e5);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('works with negative exponent', function() {
|
||||
var token = scan('1.234e-5');
|
||||
expect(token.value).to.be(1.234e-5);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('throws for bogus float', function() {
|
||||
expect(function() {
|
||||
scan('1.234eo4');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('o');
|
||||
expect(token.index).to.be(6);
|
||||
});
|
||||
});
|
||||
|
||||
it('works with octals', function() {
|
||||
var token = scan('02322');
|
||||
expect(token.value).to.be(1234);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('throws for bogus octal', function() {
|
||||
// note that this is more strict than most es5 engines
|
||||
expect(function() {
|
||||
scan('02392');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('9');
|
||||
expect(token.index).to.be(3);
|
||||
});
|
||||
});
|
||||
|
||||
it('works with hex', function() {
|
||||
var token = scan('0x4d2');
|
||||
expect(token.value).to.be(1234);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('throws for bogus hex', function() {
|
||||
// note that this is more strict than most es5 engines
|
||||
expect(function() {
|
||||
scan('0x4G');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('G');
|
||||
expect(token.index).to.be(3);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#scanPunctuator_()', function() {
|
||||
|
||||
function scan(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var token = lexer.scanPunctuator_(lexer.getCurrentCharCode_());
|
||||
expect(token.index).to.be(0);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return token;
|
||||
}
|
||||
|
||||
it('works for dot', function() {
|
||||
var token = scan('.');
|
||||
expect(token.value).to.be('.');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for bang', function() {
|
||||
var token = scan('!');
|
||||
expect(token.value).to.be('!');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for double equal', function() {
|
||||
var token = scan('==');
|
||||
expect(token.value).to.be('==');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for triple equal', function() {
|
||||
var token = scan('===');
|
||||
expect(token.value).to.be('===');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for not double equal', function() {
|
||||
var token = scan('!=');
|
||||
expect(token.value).to.be('!=');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for not triple equal', function() {
|
||||
var token = scan('!==');
|
||||
expect(token.value).to.be('!==');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for logical or', function() {
|
||||
var token = scan('||');
|
||||
expect(token.value).to.be('||');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for logical and', function() {
|
||||
var token = scan('&&');
|
||||
expect(token.value).to.be('&&');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for plus', function() {
|
||||
var token = scan('+');
|
||||
expect(token.value).to.be('+');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for minus', function() {
|
||||
var token = scan('-');
|
||||
expect(token.value).to.be('-');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for star', function() {
|
||||
var token = scan('*');
|
||||
expect(token.value).to.be('*');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for slash', function() {
|
||||
var token = scan('/');
|
||||
expect(token.value).to.be('/');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for percent', function() {
|
||||
var token = scan('%');
|
||||
expect(token.value).to.be('%');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#scanStringLiteral_()', function() {
|
||||
|
||||
function scan(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var token = lexer.scanStringLiteral_(lexer.getCurrentCharCode_());
|
||||
expect(token.index).to.be(0);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return token;
|
||||
}
|
||||
|
||||
it('parses double quoted string', function() {
|
||||
var token = scan('"my string"');
|
||||
expect(token.value).to.be('my string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses double quoted string with internal single quotes', function() {
|
||||
var token = scan('"my \'quoted\' string"');
|
||||
expect(token.value).to.be('my \'quoted\' string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses double quoted string with escaped double quotes', function() {
|
||||
var token = scan('"my \\"quoted\\" string"');
|
||||
expect(token.value).to.be('my "quoted" string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses double quoted string with escaped backslash', function() {
|
||||
var token = scan('"my \\\ string"');
|
||||
expect(token.value).to.be('my \ string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses double quoted string with unicode escape sequences', function() {
|
||||
var token = scan('"\u006f\u006c\u0033"');
|
||||
expect(token.value).to.be('ol3');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses double quoted string with hex escape sequences', function() {
|
||||
var token = scan('"\x6f\x6c\x33"');
|
||||
expect(token.value).to.be('ol3');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses double quoted string with tab', function() {
|
||||
var token = scan('"a\ttab"');
|
||||
expect(token.value).to.be('a\ttab');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('throws on unterminated double quote', function() {
|
||||
expect(function() {
|
||||
scan('"never \'ending\' string');
|
||||
}).to.throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.type).to.be(ol.expr.TokenType.EOF);
|
||||
expect(token.index).to.be(22);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses single quoted string', function() {
|
||||
var token = scan('\'my string\'');
|
||||
expect(token.value).to.be('my string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses single quoted string with internal double quotes', function() {
|
||||
var token = scan('\'my "quoted" string\'');
|
||||
expect(token.value).to.be('my "quoted" string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses single quoted string with escaped single quotes', function() {
|
||||
var token = scan('\'my \\\'quoted\\\' string\'');
|
||||
expect(token.value).to.be('my \'quoted\' string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses single quoted string with escaped backslash', function() {
|
||||
var token = scan('\'my \\\ string\'');
|
||||
expect(token.value).to.be('my \ string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses single quoted string with unicode escape sequences', function() {
|
||||
var token = scan('\'\u006f\u006c\u0033\'');
|
||||
expect(token.value).to.be('ol3');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses single quoted string with hex escape sequences', function() {
|
||||
var token = scan('\'\x6f\x6c\x33\'');
|
||||
expect(token.value).to.be('ol3');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses single quoted string with tab', function() {
|
||||
var token = scan('\'a\ttab\'');
|
||||
expect(token.value).to.be('a\ttab');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('throws on unterminated single quote', function() {
|
||||
expect(function() {
|
||||
scan('\'never "ending" string');
|
||||
}).to.throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.type).to.be(ol.expr.TokenType.EOF);
|
||||
expect(token.index).to.be(22);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
goog.require('ol.expr.Lexer');
|
||||
goog.require('ol.expr.TokenType');
|
||||
goog.require('ol.expr.UnexpectedToken');
|
||||
275
test/spec/ol/expr/parser.test.js
Normal file
275
test/spec/ol/expr/parser.test.js
Normal file
@@ -0,0 +1,275 @@
|
||||
goog.provide('ol.test.expression.Parser');
|
||||
|
||||
describe('ol.expr.Parser', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression parser', function() {
|
||||
var parser = new ol.expr.Parser();
|
||||
expect(parser).to.be.a(ol.expr.Parser);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#parseArguments_()', function() {
|
||||
|
||||
function parse(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var parser = new ol.expr.Parser();
|
||||
var expr = parser.parseArguments_(lexer);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return expr;
|
||||
}
|
||||
|
||||
it('parses comma separated expressions in parens', function() {
|
||||
var args = parse('(1/3, "foo", true)');
|
||||
expect(args).length(3);
|
||||
|
||||
expect(args[0]).to.be.a(ol.expr.Math);
|
||||
expect(args[0].evaluate()).to.be(1 / 3);
|
||||
|
||||
expect(args[1]).to.be.a(ol.expr.Literal);
|
||||
expect(args[1].evaluate()).to.be('foo');
|
||||
|
||||
expect(args[2]).to.be.a(ol.expr.Literal);
|
||||
expect(args[2].evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('throws on invalid arg expression', function() {
|
||||
expect(function() {
|
||||
parse('(6e)');
|
||||
}).throwException();
|
||||
});
|
||||
|
||||
it('throws on unterminated args', function() {
|
||||
expect(function() {
|
||||
parse('("foo", 42, )');
|
||||
}).throwException();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#parseBinaryExpression_()', function() {
|
||||
|
||||
function parse(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var parser = new ol.expr.Parser();
|
||||
var expr = parser.parseBinaryExpression_(lexer);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return expr;
|
||||
}
|
||||
|
||||
it('works with multiplicitave operators', function() {
|
||||
var expr = parse('4 * 1e4');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate()).to.be(40000);
|
||||
|
||||
expect(parse('10/3').evaluate()).to.be(10 / 3);
|
||||
});
|
||||
|
||||
it('works with additive operators', function() {
|
||||
var expr = parse('4 +1e4');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate()).to.be(10004);
|
||||
|
||||
expect(parse('10-3').evaluate()).to.be(7);
|
||||
});
|
||||
|
||||
it('works with relational operators', function() {
|
||||
var expr = parse('4 < 1e4');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
|
||||
expect(parse('10<3').evaluate()).to.be(false);
|
||||
expect(parse('10 <= "10"').evaluate()).to.be(true);
|
||||
expect(parse('10 > "10"').evaluate()).to.be(false);
|
||||
expect(parse('10 >= 9').evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('works with equality operators', function() {
|
||||
var expr = parse('4 == 1e4');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
|
||||
expect(parse('10!=3').evaluate()).to.be(true);
|
||||
expect(parse('10 == "10"').evaluate()).to.be(true);
|
||||
expect(parse('10 === "10"').evaluate()).to.be(false);
|
||||
expect(parse('10 !== "10"').evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('works with binary logical operators', function() {
|
||||
var expr = parse('true && false');
|
||||
expect(expr).to.be.a(ol.expr.Logical);
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
|
||||
expect(parse('false||true').evaluate()).to.be(true);
|
||||
expect(parse('false || false').evaluate()).to.be(false);
|
||||
expect(parse('true &&true').evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('throws for invalid binary expression', function() {
|
||||
expect(function() {
|
||||
parse('4 * / 2');
|
||||
}).throwException();
|
||||
|
||||
expect(function() {
|
||||
parse('4 < / 2');
|
||||
}).throwException();
|
||||
|
||||
expect(function() {
|
||||
parse('4 * && 2');
|
||||
}).throwException();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#parseGroupExpression_()', function() {
|
||||
|
||||
function parse(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var parser = new ol.expr.Parser();
|
||||
var expr = parser.parseGroupExpression_(lexer);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return expr;
|
||||
}
|
||||
|
||||
it('parses grouped expressions', function() {
|
||||
var expr = parse('(3 * (foo + 2))');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 3})).to.be(15);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#parseLeftHandSideExpression_()', function() {
|
||||
|
||||
function parse(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var parser = new ol.expr.Parser();
|
||||
var expr = parser.parseLeftHandSideExpression_(lexer);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return expr;
|
||||
}
|
||||
|
||||
it('parses member expressions', function() {
|
||||
var expr = parse('foo.bar.bam');
|
||||
expect(expr).to.be.a(ol.expr.Member);
|
||||
});
|
||||
|
||||
it('throws on invalid member expression', function() {
|
||||
expect(function() {
|
||||
parse('foo.4');
|
||||
}).throwException();
|
||||
});
|
||||
|
||||
it('parses call expressions', function() {
|
||||
var expr = parse('foo(bar)');
|
||||
expect(expr).to.be.a(ol.expr.Call);
|
||||
var fns = {
|
||||
foo: function(arg) {
|
||||
expect(arguments).length(1);
|
||||
expect(arg).to.be('chicken');
|
||||
return 'got ' + arg;
|
||||
}
|
||||
};
|
||||
var scope = {
|
||||
bar: 'chicken'
|
||||
};
|
||||
expect(expr.evaluate(scope, fns)).to.be('got chicken');
|
||||
});
|
||||
|
||||
it('throws on invalid call expression', function() {
|
||||
expect(function() {
|
||||
parse('foo(*)');
|
||||
}).throwException();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('#parsePrimaryExpression_()', function() {
|
||||
|
||||
function parse(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var parser = new ol.expr.Parser();
|
||||
var expr = parser.parsePrimaryExpression_(lexer);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return expr;
|
||||
}
|
||||
|
||||
it('parses string literal', function() {
|
||||
var expr = parse('"foo"');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be('foo');
|
||||
});
|
||||
|
||||
it('parses numeric literal', function() {
|
||||
var expr = parse('.42e2');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be(42);
|
||||
});
|
||||
|
||||
it('parses boolean literal', function() {
|
||||
var expr = parse('.42e2');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be(42);
|
||||
});
|
||||
|
||||
it('parses null literal', function() {
|
||||
var expr = parse('null');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be(null);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#parseUnaryExpression_()', function() {
|
||||
|
||||
function parse(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var parser = new ol.expr.Parser();
|
||||
var expr = parser.parseUnaryExpression_(lexer);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return expr;
|
||||
}
|
||||
|
||||
it('parses logical not', function() {
|
||||
var expr = parse('!foo');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate({foo: true})).to.be(false);
|
||||
});
|
||||
|
||||
it('works with string literal', function() {
|
||||
var expr = parse('!"foo"');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
});
|
||||
|
||||
it('works with empty string', function() {
|
||||
var expr = parse('!""');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('works with null', function() {
|
||||
var expr = parse('!null');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Call');
|
||||
goog.require('ol.expr.Comparison');
|
||||
goog.require('ol.expr.Lexer');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.expr.Logical');
|
||||
goog.require('ol.expr.Math');
|
||||
goog.require('ol.expr.Member');
|
||||
goog.require('ol.expr.Not');
|
||||
goog.require('ol.expr.Parser');
|
||||
goog.require('ol.expr.TokenType');
|
||||
@@ -1,78 +0,0 @@
|
||||
goog.provide('ol.test.Expression');
|
||||
|
||||
describe('ol.Expression', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates an expression', function() {
|
||||
var exp = new ol.Expression('foo');
|
||||
expect(exp).to.be.a(ol.Expression);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
|
||||
it('evaluates and returns the result', function() {
|
||||
// test cases here with unique values only (lack of messages in expect)
|
||||
var cases = [{
|
||||
source: '42', result: 42
|
||||
}, {
|
||||
source: '10 + 10', result: 20
|
||||
}, {
|
||||
source: '"a" + "b"', result: 'ab'
|
||||
}, {
|
||||
source: 'Math.floor(Math.PI)', result: 3
|
||||
}, {
|
||||
source: 'ol', result: ol
|
||||
}, {
|
||||
source: 'this', result: goog.global
|
||||
}];
|
||||
|
||||
var c, exp;
|
||||
for (var i = 0, ii = cases.length; i < ii; ++i) {
|
||||
c = cases[i];
|
||||
exp = new ol.Expression(c.source);
|
||||
expect(exp.evaluate()).to.be(c.result);
|
||||
}
|
||||
});
|
||||
|
||||
it('accepts an optional this argument', function() {
|
||||
function Thing() {
|
||||
this.works = true;
|
||||
};
|
||||
|
||||
var exp = new ol.Expression('this.works ? "yes" : "no"');
|
||||
expect(exp.evaluate(new Thing())).to.be('yes');
|
||||
expect(exp.evaluate({})).to.be('no');
|
||||
});
|
||||
|
||||
it('accepts an optional scope argument', function() {
|
||||
var exp;
|
||||
var scope = {
|
||||
greeting: 'hello world',
|
||||
punctuation: '!',
|
||||
pick: function(array, index) {
|
||||
return array[index];
|
||||
}
|
||||
};
|
||||
|
||||
// access two members in the scope
|
||||
exp = new ol.Expression('greeting + punctuation');
|
||||
expect(exp.evaluate({}, scope)).to.be('hello world!');
|
||||
|
||||
// call a function in the scope
|
||||
exp = new ol.Expression(
|
||||
'pick([10, 42, "chicken"], 2) + Math.floor(Math.PI)');
|
||||
expect(exp.evaluate({}, scope)).to.be('chicken3');
|
||||
|
||||
});
|
||||
|
||||
it('throws on error', function() {
|
||||
var exp = new ol.Expression('@*)$(&');
|
||||
expect(function() {exp.evaluate()}).to.throwException();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
goog.require('ol.Expression');
|
||||
@@ -1,36 +0,0 @@
|
||||
goog.provide('ol.test.filter.Extent');
|
||||
|
||||
|
||||
describe('ol.filter.Extent', function() {
|
||||
|
||||
var extent, filter;
|
||||
|
||||
beforeEach(function() {
|
||||
extent = [0, 45, 0, 90];
|
||||
filter = new ol.filter.Extent(extent);
|
||||
});
|
||||
|
||||
describe('#getExtent()', function() {
|
||||
|
||||
it('returns the configured extent', function() {
|
||||
expect(filter.getExtent()).to.be(extent);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
|
||||
it('returns true if a feature intersects, false if not', function() {
|
||||
expect(filter.applies(new ol.Feature({g: new ol.geom.Point([44, 89])})))
|
||||
.to.be(true);
|
||||
expect(filter.applies(new ol.Feature({g: new ol.geom.Point([46, 91])})))
|
||||
.to.be(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.filter.Extent');
|
||||
goog.require('ol.geom.Point');
|
||||
@@ -1,51 +0,0 @@
|
||||
goog.provide('ol.test.filter.Geometry');
|
||||
|
||||
|
||||
describe('ol.filter.Geometry', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new filter', function() {
|
||||
var filter = new ol.filter.Geometry(ol.filter.GeometryType.POINT);
|
||||
expect(filter).to.be.a(ol.filter.Geometry);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getType()', function() {
|
||||
|
||||
it('works for point', function() {
|
||||
var filter = new ol.filter.Geometry(ol.filter.GeometryType.POINT);
|
||||
expect(filter.getType()).to.be(ol.filter.GeometryType.POINT);
|
||||
});
|
||||
|
||||
it('works for linestring', function() {
|
||||
var filter = new ol.filter.Geometry(ol.filter.GeometryType.LINESTRING);
|
||||
expect(filter.getType()).to.be(ol.filter.GeometryType.LINESTRING);
|
||||
});
|
||||
|
||||
it('works for polygon', function() {
|
||||
var filter = new ol.filter.Geometry(ol.filter.GeometryType.POLYGON);
|
||||
expect(filter.getType()).to.be(ol.filter.GeometryType.POLYGON);
|
||||
});
|
||||
|
||||
it('works for multi-point', function() {
|
||||
var filter = new ol.filter.Geometry(ol.filter.GeometryType.MULTIPOINT);
|
||||
expect(filter.getType()).to.be(ol.filter.GeometryType.MULTIPOINT);
|
||||
});
|
||||
|
||||
it('works for multi-linestring', function() {
|
||||
var filter = new ol.filter.Geometry(
|
||||
ol.filter.GeometryType.MULTILINESTRING);
|
||||
expect(filter.getType()).to.be(ol.filter.GeometryType.MULTILINESTRING);
|
||||
});
|
||||
|
||||
it('works for multi-polygon', function() {
|
||||
var filter = new ol.filter.Geometry(ol.filter.GeometryType.MULTIPOLYGON);
|
||||
expect(filter.getType()).to.be(ol.filter.GeometryType.MULTIPOLYGON);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
goog.require('ol.filter.Geometry');
|
||||
goog.require('ol.filter.GeometryType');
|
||||
@@ -1,144 +0,0 @@
|
||||
goog.provide('ol.test.filter.Logical');
|
||||
|
||||
|
||||
describe('ol.filter.Logical', function() {
|
||||
|
||||
var OR = ol.filter.LogicalOperator.OR;
|
||||
var AND = ol.filter.LogicalOperator.AND;
|
||||
var NOT = ol.filter.LogicalOperator.NOT;
|
||||
var include = new ol.filter.Filter(function() {return true;});
|
||||
var exclude = new ol.filter.Filter(function() {return false;});
|
||||
|
||||
var apple = new ol.Feature({});
|
||||
var orange = new ol.Feature({});
|
||||
var duck = new ol.Feature({});
|
||||
|
||||
var isApple = new ol.filter.Filter(function(feature) {
|
||||
return feature === apple;
|
||||
});
|
||||
var isOrange = new ol.filter.Filter(function(feature) {
|
||||
return feature === orange;
|
||||
});
|
||||
var isDuck = new ol.filter.Filter(function(feature) {
|
||||
return feature === duck;
|
||||
});
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new filter', function() {
|
||||
var filter = new ol.filter.Logical([include, exclude], OR);
|
||||
expect(filter).to.be.a(ol.filter.Logical);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#operator', function() {
|
||||
it('can be OR', function() {
|
||||
var filter = new ol.filter.Logical([include, exclude], OR);
|
||||
expect(filter.operator).to.be(OR);
|
||||
});
|
||||
|
||||
it('can be AND', function() {
|
||||
var filter = new ol.filter.Logical([include, exclude], AND);
|
||||
expect(filter.operator).to.be(AND);
|
||||
});
|
||||
|
||||
it('can be NOT', function() {
|
||||
var filter = new ol.filter.Logical([include], NOT);
|
||||
expect(filter.operator).to.be(NOT);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#applies', function() {
|
||||
|
||||
it('works for OR', function() {
|
||||
var isFruit = new ol.filter.Logical([isApple, isOrange], OR);
|
||||
|
||||
expect(isApple.applies(apple)).to.be(true);
|
||||
expect(isOrange.applies(apple)).to.be(false);
|
||||
expect(isFruit.applies(apple)).to.be(true);
|
||||
|
||||
expect(isApple.applies(duck)).to.be(false);
|
||||
expect(isOrange.applies(duck)).to.be(false);
|
||||
expect(isFruit.applies(duck)).to.be(false);
|
||||
});
|
||||
|
||||
it('works for AND', function() {
|
||||
expect(include.applies(apple)).to.be(true);
|
||||
expect(isApple.applies(apple)).to.be(true);
|
||||
expect(isDuck.applies(apple)).to.be(false);
|
||||
|
||||
var pass = new ol.filter.Logical([include, isApple], AND);
|
||||
expect(pass.applies(apple)).to.be(true);
|
||||
|
||||
var fail = new ol.filter.Logical([isApple, isDuck], AND);
|
||||
expect(fail.applies(apple)).to.be(false);
|
||||
});
|
||||
|
||||
it('works for NOT', function() {
|
||||
expect(isApple.applies(apple)).to.be(true);
|
||||
expect(isDuck.applies(apple)).to.be(false);
|
||||
expect(isDuck.applies(duck)).to.be(true);
|
||||
expect(isDuck.applies(apple)).to.be(false);
|
||||
|
||||
var notApple = new ol.filter.Logical([isApple], NOT);
|
||||
expect(notApple.applies(apple)).to.be(false);
|
||||
expect(notApple.applies(duck)).to.be(true);
|
||||
|
||||
var notDuck = new ol.filter.Logical([isDuck], NOT);
|
||||
expect(notDuck.applies(apple)).to.be(true);
|
||||
expect(notDuck.applies(duck)).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.filter.and', function() {
|
||||
it('creates the a logical AND filter', function() {
|
||||
var a = new ol.filter.Filter();
|
||||
var b = new ol.filter.Filter();
|
||||
var c = new ol.filter.Filter();
|
||||
var and = ol.filter.and(a, b, c);
|
||||
expect(and).to.be.a(ol.filter.Logical);
|
||||
expect(and.operator).to.be(ol.filter.LogicalOperator.AND);
|
||||
var filters = and.getFilters();
|
||||
expect(filters[0]).to.be(a);
|
||||
expect(filters[1]).to.be(b);
|
||||
expect(filters[2]).to.be(c);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ol.filter.not', function() {
|
||||
it('creates the logical compliment of another filter', function() {
|
||||
var include = new ol.filter.Filter(function() {return true;});
|
||||
var notInclude = ol.filter.not(include);
|
||||
expect(notInclude).to.be.a(ol.filter.Logical);
|
||||
expect(notInclude.applies()).to.be(false);
|
||||
|
||||
var exclude = new ol.filter.Filter(function() {return false;});
|
||||
var notExclude = ol.filter.not(exclude);
|
||||
expect(notExclude).to.be.a(ol.filter.Logical);
|
||||
expect(notExclude.applies()).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ol.filter.or', function() {
|
||||
it('creates the a logical OR filter', function() {
|
||||
var a = new ol.filter.Filter();
|
||||
var b = new ol.filter.Filter();
|
||||
var c = new ol.filter.Filter();
|
||||
var and = ol.filter.or(a, b, c);
|
||||
expect(and).to.be.a(ol.filter.Logical);
|
||||
expect(and.operator).to.be(ol.filter.LogicalOperator.OR);
|
||||
var filters = and.getFilters();
|
||||
expect(filters[0]).to.be(a);
|
||||
expect(filters[1]).to.be(b);
|
||||
expect(filters[2]).to.be(c);
|
||||
});
|
||||
});
|
||||
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.filter.Filter');
|
||||
goog.require('ol.filter.Logical');
|
||||
goog.require('ol.filter.LogicalOperator');
|
||||
goog.require('ol.filter.and');
|
||||
goog.require('ol.filter.not');
|
||||
goog.require('ol.filter.or');
|
||||
@@ -50,46 +50,46 @@ describe('ol.layer.Vector', function() {
|
||||
layer.addFeatures(features);
|
||||
});
|
||||
|
||||
var geomFilter = new ol.filter.Geometry(ol.geom.GeometryType.LINESTRING);
|
||||
var extentFilter = new ol.filter.Extent([16, 16.3, 48, 48.3]);
|
||||
var geomFilter = ol.expr.parse('geometryType("linestring")');
|
||||
var extentFilter = ol.expr.parse('extent(16, 16.3, 48, 48.3)');
|
||||
|
||||
it('can filter by geometry type using its GeometryType index', function() {
|
||||
sinon.spy(geomFilter, 'applies');
|
||||
sinon.spy(geomFilter, 'evaluate');
|
||||
var lineStrings = layer.getFeatures(geomFilter);
|
||||
expect(geomFilter.applies).to.not.be.called();
|
||||
expect(geomFilter.evaluate).to.not.be.called();
|
||||
expect(lineStrings.length).to.eql(4);
|
||||
expect(lineStrings).to.contain(features[4]);
|
||||
});
|
||||
|
||||
it('can filter by extent using its RTree', function() {
|
||||
sinon.spy(extentFilter, 'applies');
|
||||
sinon.spy(extentFilter, 'evaluate');
|
||||
var subset = layer.getFeatures(extentFilter);
|
||||
expect(extentFilter.applies).to.not.be.called();
|
||||
expect(extentFilter.evaluate).to.not.be.called();
|
||||
expect(subset.length).to.eql(4);
|
||||
expect(subset).not.to.contain(features[7]);
|
||||
});
|
||||
|
||||
it('can filter by extent and geometry type using its index', function() {
|
||||
var filter1 = new ol.filter.Logical([geomFilter, extentFilter],
|
||||
ol.filter.LogicalOperator.AND);
|
||||
var filter2 = new ol.filter.Logical([extentFilter, geomFilter],
|
||||
ol.filter.LogicalOperator.AND);
|
||||
sinon.spy(filter1, 'applies');
|
||||
sinon.spy(filter2, 'applies');
|
||||
var filter1 = new ol.expr.Logical(
|
||||
ol.expr.LogicalOp.AND, geomFilter, extentFilter);
|
||||
var filter2 = new ol.expr.Logical(
|
||||
ol.expr.LogicalOp.AND, extentFilter, geomFilter);
|
||||
sinon.spy(filter1, 'evaluate');
|
||||
sinon.spy(filter2, 'evaluate');
|
||||
var subset1 = layer.getFeatures(filter1);
|
||||
var subset2 = layer.getFeatures(filter2);
|
||||
expect(filter1.applies).to.not.be.called();
|
||||
expect(filter2.applies).to.not.be.called();
|
||||
expect(filter1.evaluate).to.not.be.called();
|
||||
expect(filter2.evaluate).to.not.be.called();
|
||||
expect(subset1.length).to.eql(0);
|
||||
expect(subset2.length).to.eql(0);
|
||||
});
|
||||
|
||||
it('can handle query using the filter\'s applies function', function() {
|
||||
var filter = new ol.filter.Logical([geomFilter, extentFilter],
|
||||
ol.filter.LogicalOperator.OR);
|
||||
sinon.spy(filter, 'applies');
|
||||
it('can handle query using the filter\'s evaluate function', function() {
|
||||
var filter = new ol.expr.Logical(
|
||||
ol.expr.LogicalOp.OR, geomFilter, extentFilter);
|
||||
sinon.spy(filter, 'evaluate');
|
||||
var subset = layer.getFeatures(filter);
|
||||
expect(filter.applies).to.be.called();
|
||||
expect(filter.evaluate).to.be.called();
|
||||
expect(subset.length).to.eql(8);
|
||||
});
|
||||
|
||||
@@ -107,7 +107,7 @@ describe('ol.layer.Vector', function() {
|
||||
symbolizers: [
|
||||
new ol.style.Line({
|
||||
strokeWidth: 2,
|
||||
strokeColor: new ol.Expression('colorProperty'),
|
||||
strokeColor: ol.expr.parse('colorProperty'),
|
||||
opacity: 1
|
||||
})
|
||||
]
|
||||
@@ -144,7 +144,7 @@ describe('ol.layer.Vector', function() {
|
||||
it('groups equal symbolizers also when defined on features', function() {
|
||||
var symbolizer = new ol.style.Line({
|
||||
strokeWidth: 3,
|
||||
strokeColor: new ol.Expression('colorProperty'),
|
||||
strokeColor: ol.expr.parse('colorProperty'),
|
||||
opacity: 1
|
||||
});
|
||||
var anotherSymbolizer = new ol.style.Line({
|
||||
@@ -177,13 +177,10 @@ describe('ol.layer.Vector', function() {
|
||||
});
|
||||
|
||||
goog.require('goog.dispose');
|
||||
goog.require('ol.Expression');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.filter.Extent');
|
||||
goog.require('ol.filter.Geometry');
|
||||
goog.require('ol.filter.Logical');
|
||||
goog.require('ol.filter.LogicalOperator');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.expr.Logical');
|
||||
goog.require('ol.expr.LogicalOp');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.proj');
|
||||
|
||||
@@ -42,8 +42,8 @@ describe('ol.style.Line', function() {
|
||||
|
||||
it('accepts expressions', function() {
|
||||
var symbolizer = new ol.style.Line({
|
||||
opacity: new ol.Expression('value / 100'),
|
||||
strokeWidth: ol.Expression('widthAttr')
|
||||
opacity: ol.expr.parse('value / 100'),
|
||||
strokeWidth: ol.expr.parse('widthAttr')
|
||||
});
|
||||
expect(symbolizer).to.be.a(ol.style.Line);
|
||||
});
|
||||
@@ -54,8 +54,8 @@ describe('ol.style.Line', function() {
|
||||
|
||||
it('evaluates expressions with the given feature', function() {
|
||||
var symbolizer = new ol.style.Line({
|
||||
opacity: new ol.Expression('value / 100'),
|
||||
strokeWidth: ol.Expression('widthAttr')
|
||||
opacity: ol.expr.parse('value / 100'),
|
||||
strokeWidth: ol.expr.parse('widthAttr')
|
||||
});
|
||||
|
||||
var feature = new ol.Feature({
|
||||
@@ -73,7 +73,7 @@ describe('ol.style.Line', function() {
|
||||
|
||||
});
|
||||
|
||||
goog.require('ol.Expression');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.style.Line');
|
||||
goog.require('ol.style.LineLiteral');
|
||||
|
||||
@@ -45,8 +45,8 @@ describe('ol.style.Polygon', function() {
|
||||
|
||||
it('accepts expressions', function() {
|
||||
var symbolizer = new ol.style.Polygon({
|
||||
opacity: new ol.Expression('value / 100'),
|
||||
fillColor: new ol.Expression('fillAttr')
|
||||
opacity: ol.expr.parse('value / 100'),
|
||||
fillColor: ol.expr.parse('fillAttr')
|
||||
});
|
||||
expect(symbolizer).to.be.a(ol.style.Polygon);
|
||||
});
|
||||
@@ -57,8 +57,8 @@ describe('ol.style.Polygon', function() {
|
||||
|
||||
it('evaluates expressions with the given feature', function() {
|
||||
var symbolizer = new ol.style.Polygon({
|
||||
opacity: new ol.Expression('value / 100'),
|
||||
fillColor: new ol.Expression('fillAttr')
|
||||
opacity: ol.expr.parse('value / 100'),
|
||||
fillColor: ol.expr.parse('fillAttr')
|
||||
});
|
||||
|
||||
var feature = new ol.Feature({
|
||||
@@ -89,7 +89,7 @@ describe('ol.style.Polygon', function() {
|
||||
|
||||
});
|
||||
|
||||
goog.require('ol.Expression');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.style.Polygon');
|
||||
goog.require('ol.style.PolygonLiteral');
|
||||
|
||||
@@ -13,14 +13,14 @@ describe('ol.style.Rule', function() {
|
||||
|
||||
it('returns false when the rule does not apply', function() {
|
||||
rule = new ol.style.Rule({
|
||||
filter: new ol.filter.Filter(function() { return false; })
|
||||
filter: new ol.expr.Literal(false)
|
||||
});
|
||||
expect(rule.applies(feature)).to.be(false);
|
||||
});
|
||||
|
||||
it('returns true when the rule applies', function() {
|
||||
rule = new ol.style.Rule({
|
||||
filter: new ol.filter.Filter(function() { return true; })
|
||||
filter: new ol.expr.Literal(true)
|
||||
});
|
||||
expect(rule.applies(feature)).to.be(true);
|
||||
});
|
||||
@@ -29,5 +29,5 @@ describe('ol.style.Rule', function() {
|
||||
});
|
||||
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.filter.Filter');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.style.Rule');
|
||||
|
||||
@@ -51,8 +51,8 @@ describe('ol.style.Shape', function() {
|
||||
|
||||
it('accepts expressions', function() {
|
||||
var symbolizer = new ol.style.Shape({
|
||||
size: new ol.Expression('sizeAttr'),
|
||||
strokeColor: new ol.Expression('color')
|
||||
size: ol.expr.parse('sizeAttr'),
|
||||
strokeColor: ol.expr.parse('color')
|
||||
});
|
||||
expect(symbolizer).to.be.a(ol.style.Shape);
|
||||
});
|
||||
@@ -63,8 +63,8 @@ describe('ol.style.Shape', function() {
|
||||
|
||||
it('evaluates expressions with the given feature', function() {
|
||||
var symbolizer = new ol.style.Shape({
|
||||
size: new ol.Expression('sizeAttr'),
|
||||
opacity: new ol.Expression('opacityAttr'),
|
||||
size: ol.expr.parse('sizeAttr'),
|
||||
opacity: ol.expr.parse('opacityAttr'),
|
||||
fillColor: '#BADA55'
|
||||
});
|
||||
|
||||
@@ -99,8 +99,8 @@ describe('ol.style.Shape', function() {
|
||||
|
||||
it('applies default type if none provided', function() {
|
||||
var symbolizer = new ol.style.Shape({
|
||||
size: new ol.Expression('sizeAttr'),
|
||||
opacity: new ol.Expression('opacityAttr'),
|
||||
size: ol.expr.parse('sizeAttr'),
|
||||
opacity: ol.expr.parse('opacityAttr'),
|
||||
fillColor: '#BADA55'
|
||||
});
|
||||
|
||||
@@ -119,8 +119,8 @@ describe('ol.style.Shape', function() {
|
||||
|
||||
});
|
||||
|
||||
goog.require('ol.Expression');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.style.Shape');
|
||||
goog.require('ol.style.ShapeLiteral');
|
||||
goog.require('ol.style.ShapeType');
|
||||
|
||||
@@ -9,9 +9,7 @@ describe('ol.style.Style', function() {
|
||||
var style = new ol.style.Style({
|
||||
rules: [
|
||||
new ol.style.Rule({
|
||||
filter: new ol.filter.Filter(function(feature) {
|
||||
return feature.get('foo') == 'bar';
|
||||
}),
|
||||
filter: 'foo == "bar"',
|
||||
symbolizers: [
|
||||
new ol.style.Shape({
|
||||
size: 4,
|
||||
@@ -66,7 +64,6 @@ goog.require('ol.Feature');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.filter.Filter');
|
||||
goog.require('ol.style.Rule');
|
||||
goog.require('ol.style.Shape');
|
||||
goog.require('ol.style.ShapeLiteral');
|
||||
|
||||
Reference in New Issue
Block a user