fix #54: simplify filters for contradicting rules and ignore unsound rules alltogether
This commit is contained in:
parent
bbcca46f6f
commit
7e33846de5
@ -305,8 +305,13 @@ mess.Renderer = function Renderer(env) {
|
||||
// TODO: run uniq on this.
|
||||
filters.push.apply(filters, negatedFilters);
|
||||
|
||||
// add this definition's filter's negations to the list
|
||||
negatedFilters.push.apply(negatedFilters, negation);
|
||||
// Throw out contradicting rules.
|
||||
if (!tree.Filter.sound(filters)) {
|
||||
continue;
|
||||
} else {
|
||||
// add this definition's filter's negations to the list
|
||||
negatedFilters.push.apply(negatedFilters, negation);
|
||||
}
|
||||
|
||||
definition.selector.filters = filters;
|
||||
definition.selector.zoom = zoom;
|
||||
|
@ -68,6 +68,7 @@ tree.Definition.prototype.unique_rules = function() {
|
||||
|
||||
tree.Definition.prototype.toXML = function(env) {
|
||||
if (this._xml) return this._xml;
|
||||
|
||||
var sym = this.symbolizers();
|
||||
if (!env.returnErrors && sym.length !== 1) {
|
||||
throw {
|
||||
|
@ -9,22 +9,63 @@ tree.Filter = function Filter(key, op, val, index) {
|
||||
|
||||
tree.Filter.prototype.toXML = function(env) {
|
||||
if (this.val.is) {
|
||||
this.val = this.val.toString((this.val.is == 'string'));
|
||||
var value = this.val.toString((this.val.is == 'string'));
|
||||
} else {
|
||||
var value = this.val;
|
||||
}
|
||||
|
||||
return '[' + this.key + '] ' +
|
||||
this.op.toString() +
|
||||
' ' +
|
||||
this.val;
|
||||
value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Negate this filter: warning - this changes
|
||||
* the filter itself.
|
||||
*
|
||||
* TODO: should this have an index?
|
||||
*/
|
||||
tree.Filter.prototype.negate = function() {
|
||||
return new tree.Filter(this.key, this.op.negate(), this.val);
|
||||
return new tree.Filter(this.key, this.op.negate(), this.val, this.index);
|
||||
};
|
||||
|
||||
tree.Filter.prototype.conflictsWith = function(filter) {
|
||||
if (this.key !== filter.key) return;
|
||||
|
||||
if (this.val.toString() !== filter.val.toString() &&
|
||||
this.op.value === '=' &&
|
||||
filter.op.value === '=') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.val.toString() === filter.val.toString() &&
|
||||
((this.op.value === '!=' && filter.op.value === '=') ||
|
||||
(this.op.value === '=' && filter.op.value === '!='))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Doesn't yet check for > and <.
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes all filters from the list that are overridden by this one.
|
||||
* In case another filter is present that overrides this one, the filter won't
|
||||
* be added to the list of filters.
|
||||
*/
|
||||
tree.Filter.prototype.overrides = function(filter) {
|
||||
if (this.key !== filter.key) return;
|
||||
if (this.op.value === '=') return true;
|
||||
};
|
||||
|
||||
|
||||
tree.Filter.sound = function(filters) {
|
||||
for (var i = 0; i < filters.length; i++) {
|
||||
for (var j = i + 1; j < filters.length; j++) {
|
||||
if (filters[i].conflictsWith(filters[j])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
})(require('mess/tree'));
|
||||
|
@ -25,7 +25,7 @@ tree.Operation.prototype.eval = function(env) {
|
||||
return a.operate(this.op, b);
|
||||
};
|
||||
|
||||
tree.operate = function(op, a, b) {
|
||||
tree.operate = function operate(op, a, b) {
|
||||
switch (op) {
|
||||
case '+': return a + b;
|
||||
case '-': return a - b;
|
||||
|
@ -55,11 +55,29 @@ tree.Selector.prototype.layers = function(env) {
|
||||
}).join(' ');
|
||||
};
|
||||
|
||||
tree.Selector.prototype.simplifiedFilters = function() {
|
||||
var simplified = [];
|
||||
filters: for (var i = 0; i < this.filters.length; i++) {
|
||||
// Operate from the back so that we don't run into renumbering problems
|
||||
// when deleting items from the array.
|
||||
for (var j = simplified.length - 1; j >= 0; j--) {
|
||||
if (simplified[j].overrides(this.filters[i])) {
|
||||
continue filters;
|
||||
}
|
||||
else if (this.filters[i].overrides(simplified[j])) {
|
||||
simplified.splice(j, 1);
|
||||
}
|
||||
}
|
||||
simplified.push(this.filters[i]);
|
||||
}
|
||||
return simplified;
|
||||
};
|
||||
|
||||
tree.Selector.prototype.combinedFilter = function(env) {
|
||||
var filters = this.zoom ? this.zoom.toXML() : [];
|
||||
|
||||
if (this.filters.length) {
|
||||
filters.push('<Filter>' + this.filters.map(function(f) {
|
||||
filters.push('<Filter>' + this.simplifiedFilters().map(function(f) {
|
||||
// TODO: this is required to support selectors
|
||||
// that haven't been processed in the render() function.
|
||||
if (f instanceof tree.Filter) {
|
||||
|
Loading…
Reference in New Issue
Block a user