changed out a stack based filter parser for a operator/operand k-ary tree based parser.

This commit is contained in:
Craig Baker 2012-01-19 15:18:20 -05:00 committed by Mark Cavage
parent 1690a3f3f1
commit d09a2ee711
1 changed files with 224 additions and 1 deletions

View File

@ -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) { function _parseString(str) {
assert.ok(str); assert.ok(str);
@ -207,7 +430,7 @@ function _parseString(str) {
return filters.pop(); return filters.pop();
} }
*/
/* /*
* A filter looks like this coming in: * A filter looks like this coming in: