changed out a stack based filter parser for a operator/operand k-ary tree based parser.
This commit is contained in:
parent
1690a3f3f1
commit
d09a2ee711
|
@ -96,6 +96,229 @@ function _filterStringToStack(str) {
|
|||
}
|
||||
|
||||
|
||||
//expression parsing
|
||||
//returns the index of the closing parenthesis matching the open paren specified by openParenIndex
|
||||
function matchParens(str, openParenIndex){
|
||||
var stack = [];
|
||||
|
||||
for(var i=openParenIndex || 0;i<str.length;i++){
|
||||
if(str.charAt(i)=='('){
|
||||
stack.push(1);
|
||||
}else if(str.charAt(i) == ')'){
|
||||
stack.pop();
|
||||
if(stack.length === 0){
|
||||
//console.log('[_findMatchingParenthesis]: returning ', i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log('[_findMatchingParenthesis]: returning ', str.length-1);
|
||||
return str.length-1;
|
||||
};
|
||||
//recursive function that builds a filter tree from a string expression
|
||||
//the filter tree is an intermediary step between the incoming expression and the outgoing Dsml.
|
||||
//see the comments of store.fetch concerning the filter argument for more info
|
||||
function _buildFilterTree(expr){
|
||||
console.log('[buildFilterTree]: expression: ',expr);
|
||||
var tree = {};
|
||||
if(expr.length === 0){
|
||||
return tree;
|
||||
}
|
||||
console.log(expr);
|
||||
|
||||
//remove leading and trailing parenthesis if they are there
|
||||
if (expr.charAt(0) == '('){
|
||||
expr = expr.substring(1,expr.length-1);
|
||||
console.log('substring: '+expr);
|
||||
}
|
||||
|
||||
//store prefix op
|
||||
if(expr.charAt(0) == '&'){
|
||||
tree.op = 'and';
|
||||
expr = expr.substring(1);
|
||||
}else if (expr.charAt(0) == '|'){
|
||||
tree.op = 'or';
|
||||
expr = expr.substring(1);
|
||||
}else if(expr.charAt(0) == '!'){
|
||||
tree.op = 'not';
|
||||
expr = expr.substring(1);
|
||||
}else{
|
||||
tree.op = 'expr';
|
||||
}
|
||||
//if its a logical operator
|
||||
if(tree.op != 'expr'){
|
||||
var child,i=0;
|
||||
tree.children = [];
|
||||
|
||||
//logical operators are k-ary, so we go until our expression string runs out
|
||||
//(at least for this recursion level)
|
||||
var endParen;
|
||||
while (expr.length !== 0){
|
||||
endParen = matchParens(expr);
|
||||
if (endParen == expr.length-1){
|
||||
tree.children[i] = _buildFilterTree(expr);
|
||||
expr = "";
|
||||
}else{
|
||||
child = expr.slice(0,endParen+1);
|
||||
expr = expr.substring(endParen+1);
|
||||
tree.children[i] = _buildFilterTree(child);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}else{
|
||||
//else its equality expression, parse and return as such
|
||||
var operatorStr = "";
|
||||
var valueOffset=0;
|
||||
tree.name = "";
|
||||
tree.value = '';
|
||||
if(expr.indexOf('~=') !=-1 ){
|
||||
operatorStr = '~=';
|
||||
tree.tag = 'approxMatch';
|
||||
valueOffset = 2;
|
||||
}else if(expr.indexOf('>=') != -1){
|
||||
operatorStr = '>=';
|
||||
tree.tag = 'greaterOrEqual';
|
||||
valueOffset = 2;
|
||||
}else if(expr.indexOf('<=') != -1){
|
||||
operatorStr = '<=';
|
||||
tree.tag = 'lessOrEqual';
|
||||
valueOffset = 2;
|
||||
}else if(expr.indexOf("=") != -1){
|
||||
operatorStr = '=';
|
||||
tree.tag = 'equalityMatch';
|
||||
valueOffset = 1;
|
||||
}else {
|
||||
tree.tag = 'present';
|
||||
}
|
||||
console.log('operatorStr: ' + operatorStr + '; valueOffset: ' + valueOffset);
|
||||
if (operatorStr == ""){
|
||||
tree.name = expr;
|
||||
}else{
|
||||
//pull out lhs and rhs of equality operator
|
||||
//var index = expr.indexOf('=');
|
||||
|
||||
var splitAry = expr.split(operatorStr,2);
|
||||
tree.name =splitAry[0];
|
||||
tree.value = splitAry[1];
|
||||
|
||||
if (tree.value.indexOf('*') != -1 && tree.tag == 'equalityMatch'){
|
||||
tree.tag = 'substrings';
|
||||
var split = tree.value.split("*");
|
||||
if(tree.value.indexOf("*") != 0){
|
||||
tree.initial = split.shift();
|
||||
}else{
|
||||
split.shift();
|
||||
}
|
||||
if(tree.value.lastIndexOf("*") != tree.value.length-1){
|
||||
tree['final'] = split.pop();
|
||||
}else{
|
||||
split.pop();
|
||||
}
|
||||
tree.any = split;
|
||||
}
|
||||
if(tree.value.length == 0){
|
||||
tree.tag = 'present';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tree;
|
||||
};
|
||||
|
||||
var treeToObjs = function(tree,filterObj){
|
||||
console.log("in treeToObjs");
|
||||
if(tree === undefined){
|
||||
return filterObj;
|
||||
}
|
||||
|
||||
if(tree.length === 0){
|
||||
return filterObj;
|
||||
}
|
||||
|
||||
var currentFilter = filterObj;
|
||||
if(tree.op != "expr"){
|
||||
console.log("adding "+tree.op+" to filters");
|
||||
switch (tree.op){
|
||||
case "and":
|
||||
filterObj.addFilter(currentFilter = new AndFilter({filters:[]}));
|
||||
break;
|
||||
case "or":
|
||||
filterObj.addFilter(currentFilter = new OrFilter({filters:[]}));
|
||||
break;
|
||||
case "not":
|
||||
filterObj.addFilter(currentFilter = new NotFilter({filters:[]}));
|
||||
break;
|
||||
}
|
||||
for(var i = 0,tempFilter,child;i<tree.children.length;i++){
|
||||
child = tree.children[i];
|
||||
treeToObjs(child,currentFilter);
|
||||
}
|
||||
}else{
|
||||
var tempFilter;
|
||||
//console.log("adding "+tree.tag+" to filters");
|
||||
switch(tree.tag){
|
||||
case "approxMatch":
|
||||
tempFilter = new ApproximateFilter({
|
||||
attribute: tree.name,
|
||||
value: tree.value
|
||||
});
|
||||
console.log("adding "+tree.tag+"; attr: "+tree.name+"; value: "+tree.value);
|
||||
break;
|
||||
case "greaterOrEqual":
|
||||
tempFilter = new GreaterThanEqualsFilter({
|
||||
attribute: tree.name,
|
||||
value: tree.value
|
||||
});
|
||||
console.log("adding "+tree.tag+"; attr: "+tree.name+"; value: "+tree.value);
|
||||
break;
|
||||
case "lessOrEqual":
|
||||
tempFilter = new LessThanEqualsFilter({
|
||||
attribute: tree.name,
|
||||
value: tree.value
|
||||
});
|
||||
console.log("adding "+tree.tag+"; attr: "+tree.name+"; value: "+tree.value);
|
||||
break;
|
||||
case "equalityMatch":
|
||||
tempFilter = new EqualityFilter({
|
||||
attribute: tree.name,
|
||||
value: tree.value
|
||||
});
|
||||
console.log("adding "+tree.tag+"; attr: "+tree.name+"; value: "+tree.value);
|
||||
break;
|
||||
case "substrings":
|
||||
tempFilter = new SubstringFilter({
|
||||
attribute: tree.name,
|
||||
initial: tree.initial,
|
||||
any: tree.any,
|
||||
"final": tree["final"]
|
||||
});
|
||||
console.log("adding "+tree.tag+"; attr: "+tree.name+"; initial: "+tree.initial+"; any: "+JSON.stringify(tree.any) + "; final: "+tree['final']);
|
||||
break;
|
||||
case "present":
|
||||
tempFilter = new PresenceFilter({
|
||||
attribute: tree.name
|
||||
});
|
||||
console.log("adding "+tree.tag+"; attr: "+tree.name);
|
||||
break;
|
||||
}
|
||||
filterObj.addFilter(tempFilter);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function _parseString(str){
|
||||
assert.ok(str);
|
||||
var filterObj = new AndFilter({
|
||||
filters:[]
|
||||
});
|
||||
|
||||
var tree = _buildFilterTree(str);
|
||||
console.log("tree built: ",JSON.stringify(tree));
|
||||
treeToObjs(tree,filterObj);
|
||||
return filterObj.filters[0];
|
||||
};
|
||||
|
||||
/*
|
||||
function _parseString(str) {
|
||||
assert.ok(str);
|
||||
|
||||
|
@ -207,7 +430,7 @@ function _parseString(str) {
|
|||
|
||||
return filters.pop();
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* A filter looks like this coming in:
|
||||
|
|
Loading…
Reference in New Issue