From dd8415cc058f943d17712a2a5230d78578cb8485 Mon Sep 17 00:00:00 2001
From: slomo <steve.harrison@gmx.net>
Date: Fri, 28 Jan 2011 22:10:43 +0100
Subject: fixed parsing

---
 src/nodejs/parse.js             | 159 +++++++++++++++++++++++++++++-----------
 src/nodejs/tests/pathparsing.js |   8 +-
 2 files changed, 119 insertions(+), 48 deletions(-)

(limited to 'src')

diff --git a/src/nodejs/parse.js b/src/nodejs/parse.js
index 932f91f..321823b 100644
--- a/src/nodejs/parse.js
+++ b/src/nodejs/parse.js
@@ -1,60 +1,131 @@
-exports.urlToXpathObj = function urlToXpathObj(url){
 
-    // FIXMEresult.shift(): more validaiton
-    // filter stars in keys
-    // filter no enough arguments
 
-    var parseKeyList = function(string){
-        
-        console.log("input f1: " + string);
-        result = /([^\|]*)/g.exec(string);
-        console.log(result);
-        result.shift();
-        return result;
-    }   
+var parser = function(){
 
-    var parseBboxList = function(string){
+    var offset =0;
+    var expr ="";
 
-        console.log("input: " + string);
-        result = /(.+),(.+),(.+),(.+)/.exec(string);
+    var keys = [];
+    var values = [];
+    var bbox= {};
+    var object = "";
 
-        console.log(result);
+    var check = function(char){
+        if (expr.charAt(offset) != char) {
+            throw "Unexpected char " + expr[offset] +  " at " + offset + " expected: " + char;
+        }
+        offset ++;
+    }
+    
+    var parsePredicate = function(){
+        check('[');
+        parseInnerPredicate();
+        check(']');
+    }
 
-        if(result.length != 4){ 
-            throw "error";
-        }   
+    var parseInnerPredicate = function(){
+        tmpKeys=[];
+        parseKeyValue(tmpKeys,'=');
+        check('=');
+        if(tmpKeys.length==1 && tmpKeys[0] == "bbox"){
+            parseBboxValues();
+        } else {
+            keys = tmpKeys;
+            parseKeyValue(values,']');
+        }
+    }
 
-        result.shift();
+    var parseBboxValues = function(){
+        bbox.left = parseBboxFloat();
+        check(',');
+        bbox.bottom = parseBboxFloat();
+        check(',');
+        bbox.right = parseBboxFloat();
+        check(',');
+        bbox.top = parseBboxFloat();
+    }
 
-        return {
-            'left' : result[0],
-            'bottom' : result[1],
-            'right' : result[2],
-            'top' : result[3]
-        }  
-    } 
-        
-    var xp = {}; 
+    var parseBboxFloat = function(){
+        var floatStr = "";
+        while(expr[offset]!=',' &&  expr[offset]!=']' && offset < expr.length){
+            floatStr += expr[offset];
+            offset ++;
+        }
+        return parseFloat(floatStr);
+    }
 
-    result = url.match(/\/(\*|node|way|relation)\[(.*)=(.*)\]*/);
-    console.log("OUTER: " + result);
+    var parseKeyValue = function(list,delim){
+        var word = "";
+        while(expr[offset]!=delim && offset < expr.length){
+            if(expr[offset]=='|'){
+                list.push(word);
+                word="";
+                offset ++;
+                continue;
+            }
+            // jump escaped chars
+            if(expr[offset]=='\\'){
+                word += expr[offset];
+                offset ++;
+            }
+            word += expr[offset];
+            offset ++;
+        }
+        list.push(word);
+
+    }
 
+    this.parse = function(exprLocal){
+        expr = exprLocal;
+        offset = 0;
+        object = "";
 
-    xp.object=result[1];
 
-    for(i=2;i<=result.length;i++){
-        if(result[i]==="bbox" && result[i]){
-            xp.bbox = parseBboxList(result[i+1]);
-        } else {
-            if(result[i]){
-                xp.tag ={};
-                xp.tag.keys = parseKeyList(result[i]);
-                xp.tag.values = parseKeyList(result[i+1]); 
+
+        check('/');
+
+        for(;expr[offset]!='[' && offset<expr.length;offset++){
+            if(expr[offset] == '/' && offset == expr.length-1){
+                offset ++;
+                break;
             }
-        }   
-        i++;
+            object += expr[offset];
+        }
+
+        if (object != "*" && object != "way" && object != "node" && object != "relation"){
+            throw "invalid identifier: "  + object;
+        }
+
+
+        for(var i=0; i<3 && offset < expr.length;i++) {
+            parsePredicate();
+        }
+        if (offset < expr.length){
+
+            throw "string longer than excepected";
+        }
+
+        var result = {
+            object : object
+        };
+
+        if(bbox.left != undefined){
+            result.bbox = bbox;
+        }
+
+        if(keys.length > 0){
+
+            result.tag = { 
+                key : keys,
+                value : values
+            }
+        }
+        return result; 
     }
-    console.log(xp);
-    return(xp);
 }
 
+
+exports.urlToXpathObj = function urlToXpathObj(url){
+    var parse = new parser();
+    return parse.parse(url);
+}
diff --git a/src/nodejs/tests/pathparsing.js b/src/nodejs/tests/pathparsing.js
index e1a20f5..ebd5baf 100644
--- a/src/nodejs/tests/pathparsing.js
+++ b/src/nodejs/tests/pathparsing.js
@@ -54,7 +54,7 @@ module.exports =
     test.ok(true);
     var simpleRelationStringTrail = "/relation/";
     var expected = { object: "relation" };
-    assert.deepEqual(toTest(simpleRelationStringTrail), expectedi);
+    assert.deepEqual(toTest(simpleRelationStringTrail), expected);
     test.finish();
   }
 
@@ -78,20 +78,20 @@ module.exports =
  , 'tag with two values': function(test) {
     test.ok(true);
     var nodeWithTwoValues = "/node[tag=foo|bar]";
-    var expected = { object: "node", tag: { key:["key"], value:["foo", "bar"]}};
+    var expected = { object: "node", tag: { key:["tag"], value:["foo", "bar"]}};
     assert.deepEqual(toTest(nodeWithTwoValues), expected);
     test.finish();
   }
    , 'tag with two keys': function(test) {
    test.ok(true);
-   var nodeWithTwoKeys = "/node[foo,bar=value]";
+   var nodeWithTwoKeys = "/node[foo|bar=value]";
    var expected = { object: "node", tag: { key:["foo", "bar"], value:["value"]}};
    assert.deepEqual(toTest(nodeWithTwoKeys), expected);
    test.finish();
   }
    , 'tags with cross product': function(test) {
     test.ok(true);
-    var tagCrossProduct = "/node[key1,key2=value1,value2]";
+    var tagCrossProduct = "/node[key1|key2=value1|value2]";
     var expected = { object: "node", tag: {key:["key1", "key2"], value:["value1", "value2"]}};
     assert.deepEqual(toTest(tagCrossProduct), expected);
     test.finish();
-- 
cgit v1.2.3