diff --git a/cql.js b/cql.js
index 37035d3..77e05bb 100644
--- a/cql.js
+++ b/cql.js
@@ -9,28 +9,51 @@ function indent(n, c) {
s = s + c;
return s;
}
+
+var CQLError = function (message, query, pos, look, val, lval) {
+ this.name = "CQLError";
+ this.message = message;
+ // raw query string
+ this.query = query;
+ // parser (error) position in raw query
+ this.pos = pos;
+ // state: s | q | | ()/ | <>= | "'
+ this.look = look;
+ // value of token (may be (quoted) content, "index"; field or term)
+ this.val = val;
+ // lowercased this.val
+ this.lval = lval;
+ this.stack = (new Error()).stack;
+}
+CQLError.prototype = Object.create(Error.prototype);
+
// CQLModifier
var CQLModifier = function () {
+ // name of (relation) modifier
this.name = null;
+ // relation of modifier value (e.g. equals, lower than, etc.)
this.relation = null;
+ // optional value of modifier ("true" if empty)
this.value = null;
+ this._pos = null;
+ this._range = null;
}
CQLModifier.prototype = {
toString: function () {
- return this.name + this.relation + this.value;
+ return this.name + this.relation + this.value;
},
toXCQL: function (n, c) {
- var s = indent(n+1, c) + "\n";
- s = s + indent(n+2, c) + "" + this.name + "\n";
+ var s = indent(n + 1, c) + "\n";
+ s = s + indent(n + 2, c) + "" + this.name + "\n";
if (this.relation != null)
- s = s + indent(n+2, c)
+ s = s + indent(n + 2, c)
+ "" + this.relation + "\n";
if (this.value != null)
- s = s + indent(n+2, c)
- + "" + this.value +"\n";
- s = s + indent(n+1, c) + "\n";
+ s = s + indent(n + 2, c)
+ + "" + this.value + "\n";
+ s = s + indent(n + 1, c) + "\n";
return s;
},
@@ -38,170 +61,208 @@ CQLModifier.prototype = {
//we ignore modifier relation symbol, for value-less modifiers
//we assume 'true'
var value = this.value.length > 0 ? this.value : "true";
- var s = '"'+this.name+'": "'+value+'"';
+ var s = '"' + this.name + '": "' + value + '"';
+ if (this._pos !== null) s += ', "' + this.name + '@pos": ' + this._pos;
+ if (this._range !== null) s += ', "' + this.name + '@range": ' + JSON.stringify(this._range);
return s;
}
}
// CQLSearchClause
-var CQLSearchClause = function (field, fielduri, relation, relationuri,
- modifiers, term, scf, scr) {
+var CQLSearchClause = function (field, fielduri, relation, relationuri,
+ modifiers, term, scf, scr) {
+ // index or name
this.field = field;
+ // not supported yet? (always empty string)
this.fielduri = fielduri;
+ // relation symbol or string
this.relation = relation;
+ // not supported yet? (always empty string)
this.relationuri = relationuri;
+ // list of modifiers
this.modifiers = modifiers;
+ // value
this.term = term;
this.scf = scf || DEFAULT_SERVER_CHOICE_FIELD;
this.scr = scr || DEFAULT_SERVER_CHOICE_RELATION;
+ // start position of search clause
+ this._pos = null;
+ // range (start + end position) of search clause (without surrounding braces or spaces)
+ this._range = null;
+ // start position of relation
+ this._relpos = null;
}
CQLSearchClause.prototype = {
toString: function () {
- var field = this.field;
- var relation = this.relation;
- if (field == this.scf && relation == this.scr) {
- //avoid redundant field/relation
- field = null;
- relation = null;
- }
- return (field ? field + ' ' : '') +
- (relation ? relation : '') +
- (this.modifiers.length > 0 ? '/' + this.modifiers.join('/') : '') +
- (relation || this.modifiers.length ? ' ' : '') +
- '"' + this.term + '"';
+ var field = this.field;
+ var relation = this.relation;
+ if (field == this.scf && relation == this.scr) {
+ //avoid redundant field/relation
+ field = null;
+ relation = null;
+ }
+ return (field ? field + ' ' : '') +
+ (relation ? relation : '') +
+ (this.modifiers.length > 0 ? '/' + this.modifiers.join('/') : '') +
+ (relation || this.modifiers.length ? ' ' : '') +
+ '"' + this.term + '"';
},
toXCQL: function (n, c) {
var s = indent(n, c) + "\n";
- if (this.fielduri.length > 0)
- {
- s = s + indent(n+1, c) + "\n" +
- indent(n+2, c) + "\n" +
- indent(n+3, c) + "" + this.fielduri +
+ if (this.fielduri.length > 0) {
+ s = s + indent(n + 1, c) + "\n" +
+ indent(n + 2, c) + "\n" +
+ indent(n + 3, c) + "" + this.fielduri +
"\n" +
- indent(n+2, c) + "\n" +
- indent(n+1, c) + "\n";
+ indent(n + 2, c) + "\n" +
+ indent(n + 1, c) + "\n";
}
- s = s + indent(n+1, c) + "" + this.field + "\n";
- s = s + indent(n+1, c) + "\n";
+ s = s + indent(n + 1, c) + "" + this.field + "\n";
+ s = s + indent(n + 1, c) + "\n";
if (this.relationuri.length > 0) {
- s = s + indent(n+2, c) +
+ s = s + indent(n + 2, c) +
"" + this.relationuri + "\n";
}
- s = s + indent(n+2, c) + "" + this.relation + "\n";
+ s = s + indent(n + 2, c) + "" + this.relation + "\n";
if (this.modifiers.length > 0) {
- s = s + indent(n+2, c) + "\n";
+ s = s + indent(n + 2, c) + "\n";
for (var i = 0; i < this.modifiers.length; i++)
- s = s + this.modifiers[i].toXCQL(n+2, c);
- s = s + indent(n+2, c) + "\n";
+ s = s + this.modifiers[i].toXCQL(n + 2, c);
+ s = s + indent(n + 2, c) + "\n";
}
- s = s + indent(n+1, c) + "\n";
- s = s + indent(n+1, c) + "" + this.term + "\n";
+ s = s + indent(n + 1, c) + "\n";
+ s = s + indent(n + 1, c) + "" + this.term + "\n";
s = s + indent(n, c) + "\n";
return s;
},
toFQ: function () {
- var s = '{"term": "'+this.term+'"';
+ var s = '{"term": "' + this.term + '"';
if (this.field.length > 0 && this.field != this.scf)
- s+= ', "field": "'+this.field+'"';
+ s += ', "field": "' + this.field + '"';
if (this.relation.length > 0 && this.relation != this.scr)
- s+= ', "relation": "'+this._mapRelation(this.relation)+'"';
+ s += ', "relation": "' + this._mapRelation(this.relation) + '"';
for (var i = 0; i < this.modifiers.length; i++) {
- //since modifiers are mapped to keys, ignore the reserved ones
- if (this.modifiers[i].name == "term"
- ||this.modifiers[i].name == "field"
- ||this.modifiers[i].name == "relation")
- continue;
- s += ', ' + this.modifiers[i].toFQ();
+ //since modifiers are mapped to keys, ignore the reserved ones
+ if (this.modifiers[i].name == "term"
+ || this.modifiers[i].name == "field"
+ || this.modifiers[i].name == "relation")
+ continue;
+ s += ', ' + this.modifiers[i].toFQ();
}
+ if (this._pos !== null) s += ', "@pos": ' + this._pos;
+ if (this._range !== null) s += ', "@range": ' + JSON.stringify(this._range);
+ if (this._relpos !== null) s += ', "relation@pos": ' + this._relpos;
s += '}';
return s;
},
_mapRelation: function (rel) {
- switch(rel) {
- case "<" : return "lt";
- case ">" : return "gt";
- case "=" : return "eq";
- case "<>" : return "ne";
- case ">=" : return "ge";
- case "<=" : return "le";
- default: return rel;
- }
+ switch (rel) {
+ case "<": return "lt";
+ case ">": return "gt";
+ case "=": return "eq";
+ case "<>": return "ne";
+ case ">=": return "ge";
+ case "<=": return "le";
+ default: return rel;
+ }
},
_remapRelation: function (rel) {
- switch(rel) {
- case "lt" : return "<";
- case "gt" : return ">";
- case "eq" : return "=";
- case "ne" : return "<>";
- case "ge" : return ">=";
- case "le" : return "<=";
- default: return rel;
- }
+ switch (rel) {
+ case "lt": return "<";
+ case "gt": return ">";
+ case "eq": return "=";
+ case "ne": return "<>";
+ case "ge": return ">=";
+ case "le": return "<=";
+ default: return rel;
+ }
}
-
}
+
// CQLBoolean
-var CQLBoolean = function() {
+var CQLBoolean = function () {
+ // operator: and | or | not | prox
this.op = null;
+ // list of modifiers
this.modifiers = null;
+ // left search clause
this.left = null;
+ // right search clause
this.right = null;
+ this._pos = null;
+ this._range = null;
}
CQLBoolean.prototype = {
toString: function () {
- return (this.left.op ? '(' + this.left + ')' : this.left) + ' ' +
- this.op.toUpperCase() +
- (this.modifiers.length > 0 ? '/' + this.modifiers.join('/') : '') +
- ' ' + (this.right.op ? '(' + this.right + ')' : this.right);;
+ return (this.left.op ? '(' + this.left + ')' : this.left) + ' ' +
+ this.op.toUpperCase() +
+ (this.modifiers.length > 0 ? '/' + this.modifiers.join('/') : '') +
+ ' ' + (this.right.op ? '(' + this.right + ')' : this.right);;
},
+
toXCQL: function (n, c) {
var s = indent(n, c) + "\n";
- s = s + indent(n+1, c) + "\n" +
- indent(n+2, c) + "" + this.op + "\n";
+ s = s + indent(n + 1, c) + "\n" +
+ indent(n + 2, c) + "" + this.op + "\n";
if (this.modifiers.length > 0) {
- s = s + indent(n+2, c) + "\n";
+ s = s + indent(n + 2, c) + "\n";
for (var i = 0; i < this.modifiers.length; i++)
- s = s + this.modifiers[i].toXCQL(n+2, c);
- s = s + indent(n+2, c) + "\n";
+ s = s + this.modifiers[i].toXCQL(n + 2, c);
+ s = s + indent(n + 2, c) + "\n";
}
- s = s + indent(n+1, c) + "\n";
- s = s + indent(n+1, c) + "\n" +
- this.left.toXCQL(n+2, c) + indent(n+1, c) + "\n";
+ s = s + indent(n + 1, c) + "\n";
+ s = s + indent(n + 1, c) + "\n" +
+ this.left.toXCQL(n + 2, c) + indent(n + 1, c) + "\n";
- s = s + indent(n+1, c) + "\n" +
- this.right.toXCQL(n+2, c) + indent(n+1, c) + "\n";
+ s = s + indent(n + 1, c) + "\n" +
+ this.right.toXCQL(n + 2, c) + indent(n + 1, c) + "\n";
s = s + indent(n, c) + "\n";
return s;
},
toFQ: function (n, c, nl) {
- var s = '{"op": "'+this.op+'"';
- //proximity modifiers
- for (var i = 0; i < this.modifiers.length; i++)
- s += ', ' + this.modifiers[i].toFQ();
- s += ','+nl+indent(n, c)+' "s1": '+this.left.toFQ(n+1, c, nl);
- s += ','+nl+indent(n, c)+' "s2": '+this.right.toFQ(n+1, c, nl);
- var fill = n && c ? ' ' : '';
- s += nl+indent(n-1, c)+fill+'}';
- return s;
+ var s = '{"op": "' + this.op + '"';
+ //proximity modifiers
+ for (var i = 0; i < this.modifiers.length; i++)
+ s += ', ' + this.modifiers[i].toFQ();
+ s += ',' + nl + indent(n, c) + ' "s1": ' + this.left.toFQ(n + 1, c, nl);
+ s += ',' + nl + indent(n, c) + ' "s2": ' + this.right.toFQ(n + 1, c, nl);
+ if (this._pos !== null) s += ',' + nl + indent(n, c) + ' "@pos": ' + this._pos;
+ if (this._range !== null) s += ',' + nl + indent(n, c) + ' "@range": ' + JSON.stringify(this._range);
+ var fill = n && c ? ' ' : '';
+ s += nl + indent(n - 1, c) + fill + '}';
+ return s;
}
}
+
// CQLParser
var CQLParser = function () {
+ // index/position in raw query
this.qi = null;
+ // raw query string length (char count)
this.ql = null;
+ // raw query string
this.qs = null;
+ // parser state: s | q | ()/ | <>= | "'
+ // if empty string then error
this.look = null;
+ // lowercased this.val
this.lval = null;
+ // value of token (may be (quoted) content, "index"; field or term)
this.val = null;
+ // (internal) start position of expression
+ this._exprStart = null;
+ // (internal) start position of relation (in expression)
+ this._exprRelStart = null;
this.prefixes = new Object();
+ // parsed query
this.tree = null;
this.scf = null;
this.scr = null;
@@ -210,78 +271,83 @@ var CQLParser = function () {
CQLParser.prototype = {
parse: function (query, scf, scr) {
if (!query)
- throw new Error("The query to be parsed cannot be empty");
- this.scf = typeof scf != 'string'
- ? DEFAULT_SERVER_CHOICE_FIELD : scf;
- this.scr = typeof scr != 'string'
- ? DEFAULT_SERVER_CHOICE_RELATION : scr;
+ throw new CQLError("The query to be parsed cannot be empty", this.qs);
+ this.scf = typeof scf != 'string'
+ ? DEFAULT_SERVER_CHOICE_FIELD : scf;
+ this.scr = typeof scr != 'string'
+ ? DEFAULT_SERVER_CHOICE_RELATION : scr;
this.qs = query;
this.ql = this.qs.length;
this.qi = 0;
- this._move();
+ this.lval = this.val = this._exprStart = null;
+ this._move();
this.tree = this._parseQuery(this.scf, this.scr, new Array());
if (this.look != "")
- throw new Error("EOF expected");
+ throw new CQLError("EOF expected", this.qs, this.qi, this.look, this.val, this.lval);
},
parseFromFQ: function (query, scf, scr) {
- if (!query)
- throw new Error("The query to be parsed cannot be empty");
- if (typeof query == 'string')
- query = JSON.parse(query);
- this.scf = typeof scf != 'string'
- ? DEFAULT_SERVER_CHOICE_FIELD : scf;
- this.scr = typeof scr != 'string'
- ? DEFAULT_SERVER_CHOICE_RELATION : scr;
- this.tree = this._parseFromFQ(query);
+ if (!query)
+ throw new CQLError("The query to be parsed cannot be empty", this.qs);
+ if (typeof query == 'string')
+ query = JSON.parse(query);
+ this.scf = typeof scf != 'string'
+ ? DEFAULT_SERVER_CHOICE_FIELD : scf;
+ this.scr = typeof scr != 'string'
+ ? DEFAULT_SERVER_CHOICE_RELATION : scr;
+ this.tree = this._parseFromFQ(query);
},
_parseFromFQ: function (fq) {
//op-node
- if (fq.hasOwnProperty('op')
+ if (fq.hasOwnProperty('op')
&& fq.hasOwnProperty('s1')
&& fq.hasOwnProperty('s2')) {
- var node = new CQLBoolean();
- node.op = fq.op;
- node.left = this._parseFromFQ(fq.s1);
- node.right = this._parseFromFQ(fq.s2);
- //include all other members as modifiers
- node.modifiers = [];
- for (var key in fq) {
- if (key == 'op' || key == 's1' || key == 's2')
- continue;
- var mod = new CQLModifier();
- mod.name = key;
- mod.relation = '=';
- mod.value = fq[key];
- node.modifiers.push(mod);
- }
- return node;
+ var node = new CQLBoolean();
+ node.op = fq.op;
+ node.left = this._parseFromFQ(fq.s1);
+ node.right = this._parseFromFQ(fq.s2);
+ //include all other members as modifiers
+ node.modifiers = [];
+ for (var key in fq) {
+ if (key == 'op' || key == 's1' || key == 's2')
+ continue;
+ if (key.endsWith("@pos") || key.endsWith("@range"))
+ continue;
+ var mod = new CQLModifier();
+ mod.name = key;
+ mod.relation = '=';
+ mod.value = fq[key];
+ node.modifiers.push(mod);
+ }
+ return node;
}
//search-clause node
if (fq.hasOwnProperty('term')) {
- var node = new CQLSearchClause();
- node.term = fq.term;
- node.scf = this.scf;
- node.scr = this.scr;
- node.field = fq.hasOwnProperty('field')
- ? fq.field : this.scf;
- node.relation = fq.hasOwnProperty('relation')
- ? node._remapRelation(fq.relation) : this.scr;
- //include all other members as modifiers
- node.relationuri = '';
- node.fielduri = '';
- node.modifiers = [];
- for (var key in fq) {
- if (key == 'term' || key == 'field' || key == 'relation')
- continue;
- var mod = new CQLModifier();
- mod.name = key;
- mod.relation = '=';
- mod.value = fq[key];
- node.modifiers.push(mod);
- }
- return node;
+ var node = new CQLSearchClause();
+ node.term = fq.term;
+ node.scf = this.scf;
+ node.scr = this.scr;
+ node.field = fq.hasOwnProperty('field')
+ ? fq.field : this.scf;
+ node.relation = fq.hasOwnProperty('relation')
+ ? node._remapRelation(fq.relation) : this.scr;
+ //include all other members as modifiers
+ node.relationuri = '';
+ node.fielduri = '';
+ node.modifiers = [];
+ for (var key in fq) {
+ if (key == 'term' || key == 'field' || key == 'relation')
+ continue;
+ if (key.endsWith("@pos") || key.endsWith("@range"))
+ continue;
+ var mod = new CQLModifier();
+ mod.name = key;
+ mod.relation = '=';
+ mod.value = fq[key];
+ node.modifiers.push(mod);
+ }
+ return node;
}
- throw new Error('Unknow node type; '+JSON.stringify(fq));
+ throw new CQLError('Unknow node type; ' + JSON.stringify(fq), this.qs, this.qi, this.look, this.val, this.lval);
},
toXCQL: function (c) {
c = typeof c == "undefined" ? ' ' : c;
@@ -295,40 +361,51 @@ CQLParser.prototype = {
toString: function () {
return this.tree.toString();
},
- _parseQuery: function(field, relation, modifiers) {
+ _parseQuery: function (field, relation, modifiers) {
var left = this._parseSearchClause(field, relation, modifiers);
while (this.look == "s" && (
- this.lval == "and" ||
- this.lval == "or" ||
- this.lval == "not" ||
- this.lval == "prox")) {
+ this.lval == "and" ||
+ this.lval == "or" ||
+ this.lval == "not" ||
+ this.lval == "prox")) {
var b = new CQLBoolean();
+ b._pos = this.qi - this.lval.length + 1;
b.op = this.lval;
this._move();
b.modifiers = this._parseModifiers();
+ b._range = [b._pos, Math.max(b._pos + b.op.length - 1, Math.max.apply(null, b.modifiers.map(x => ("_range" in x) ? x._range[1]: 0)))];
b.left = left;
b.right = this._parseSearchClause(field, relation, modifiers);
left = b;
}
return left;
},
- _parseModifiers: function() {
+ _parseModifiers: function () {
var ar = new Array();
+ let _safeExprStart = this._exprStart;
+ let _safeExprRelStart = this._exprRelStart;
while (this.look == "/") {
+ let _mstart = this.qi;
this._move();
if (this.look != "s" && this.look != "q")
- throw new Error("Invalid modifier.")
-
+ throw new CQLError("Invalid modifier.", this.qs, this.qi, this.look, this.val, this.lval)
+
var name = this.lval;
+ let _mpos = this.qi - this.lval.length + 1;
+ let _mend = this.qi;
this._move();
- if (this.look.length > 0
+ if (this.look.length > 0
&& this._strchr("<>=", this.look.charAt(0))) {
var rel = this.look;
this._move();
+ _mend = this.qi;
if (this.look != "s" && this.look != "q")
- throw new Error("Invalid relation within the modifier.");
-
+ throw new CQLError("Invalid relation within the modifier.", this.qs, this.qi, this.look, this.val, this.lval);
+
var m = new CQLModifier();
+ m._pos = _mpos;
+ m._range = [_mstart, _mend];
+ this._exprStart = null;
m.name = name;
m.relation = rel;
m.value = this.val;
@@ -336,54 +413,64 @@ CQLParser.prototype = {
this._move();
} else {
var m = new CQLModifier();
+ m._pos = _mpos;
+ m._range = [_mstart, _mend];
+ this._exprStart = null;
m.name = name;
m.relation = "";
m.value = "";
ar.push(m);
}
}
+ this._exprStart = _safeExprStart;
+ this._exprRelStart = _safeExprRelStart;
return ar;
},
- _parseSearchClause: function(field, relation, modifiers) {
+ _parseSearchClause: function (field, relation, modifiers) {
if (this.look == "(") {
+ let _qi = this.qi;
this._move();
var b = this._parseQuery(field, relation, modifiers);
if (this.look == ")")
this._move();
else
- throw new Error("Missing closing parenthesis.");
+ throw new CQLError("Missing closing parenthesis.", this.qs, _qi, this.look, this.val, this.lval);
return b;
} else if (this.look == "s" || this.look == "q") {
var first = this.val; // dont know if field or term yet
+ if (this._exprStart === null)
+ this._exprStart = this.qi - this.val.length + 1;
+ let _tend = this.qi;
this._move();
if (this.look == "q" ||
- (this.look == "s" &&
- this.lval != "and" &&
- this.lval != "or" &&
- this.lval != "not" &&
- this.lval != "prox")) {
+ (this.look == "s" &&
+ this.lval != "and" &&
+ this.lval != "or" &&
+ this.lval != "not" &&
+ this.lval != "prox")) {
var rel = this.val; // string relation
+ this._exprRelStart = this.qi - this.val.length + 1;
this._move();
return this._parseSearchClause(first, rel,
- this._parseModifiers());
- } else if (this.look.length > 0
- && this._strchr("<>=", this.look.charAt(0))) {
+ this._parseModifiers());
+ } else if (this.look.length > 0
+ && this._strchr("<>=", this.look.charAt(0))) {
var rel = this.look; // other relation <, = ,etc
this._move();
- return this._parseSearchClause(first, rel,
- this._parseModifiers());
+ return this._parseSearchClause(first, rel,
+ this._parseModifiers());
} else {
// it's a search term
var pos = field.indexOf('.');
var pre = "";
if (pos != -1)
pre = field.substring(0, pos);
-
+
var uri = this._lookupPrefix(pre);
if (uri.length > 0)
- field = field.substring(pos+1);
-
+ field = field.substring(pos + 1);
+
pos = relation.indexOf('.');
if (pos == -1)
pre = "cql";
@@ -392,32 +479,34 @@ CQLParser.prototype = {
var reluri = this._lookupPrefix(pre);
if (reluri.Length > 0)
- relation = relation.Substring(pos+1);
+ relation = relation.Substring(pos + 1);
var sc = new CQLSearchClause(field,
- uri,
- relation,
- reluri,
- modifiers,
- first,
- this.scf,
- this.scr);
+ uri,
+ relation,
+ reluri,
+ modifiers,
+ first,
+ this.scf,
+ this.scr);
+ sc._range = [this._exprStart, _tend];
+ sc._relpos = this._exprRelStart;
+ this._exprStart = this._exprRelStart = null;
return sc;
}
- // prefixes
+ // prefixes
} else if (this.look == ">") {
this._move();
if (this.look != "s" && this.look != "q")
- throw new Error("Expecting string or a quoted expression.");
-
+ throw new CQLError("Expecting string or a quoted expression.", this.qs, this.qi, this.look, this.val, this.lval);
+
var first = this.lval;
this._move();
- if (this.look == "=")
- {
+ if (this.look == "=") {
this._move();
if (this.look != "s" && this.look != "q")
- throw new Error("Expecting string or a quoted expression.");
-
+ throw new CQLError("Expecting string or a quoted expression.", this.qs, this.qi, this.look, this.val, this.lval);
+
this._addPrefix(first, this.lval);
this._move();
return this._parseQuery(field, relation, modifiers);
@@ -426,14 +515,14 @@ CQLParser.prototype = {
return this._parseQuery(field, relation, modifiers);
}
} else {
- throw new Error("Invalid search clause.");
+ throw new CQLError("Invalid search clause.", this.qs, this.qi, this.look, this.val, this.lval);
}
},
_move: function () {
//eat whitespace
- while (this.qi < this.ql
- && this._strchr(" \t\r\n", this.qs.charAt(this.qi)))
+ while (this.qi < this.ql
+ && this._strchr(" \t\r\n", this.qs.charAt(this.qi)))
this.qi++;
//eof
if (this.qi == this.ql) {
@@ -446,18 +535,21 @@ CQLParser.prototype = {
if (this._strchr("()/", c)) {
this.look = c;
this.qi++;
- //comparitor
+ //comparitor
} else if (this._strchr("<>=", c)) {
this.look = c;
this.qi++;
+ this._exprRelStart = this.qi;
//comparitors can repeat, could be if
- while (this.qi < this.ql
- && this._strchr("<>=", this.qs.charAt(this.qi))) {
+ while (this.qi < this.ql
+ && this._strchr("<>=", this.qs.charAt(this.qi))) {
this.look = this.look + this.qs.charAt(this.qi);
this.qi++;
}
- //quoted string
+ //quoted string
} else if (this._strchr("\"'", c)) {
+ if (this._exprStart === null)
+ this._exprStart = this.qi + 1;
this.look = "q";
//remember quote char
var mark = c;
@@ -465,26 +557,26 @@ CQLParser.prototype = {
this.val = "";
var escaped = false;
while (this.qi < this.ql) {
- if (!escaped && this.qs.charAt(this.qi) == mark)
- break;
- if (!escaped && this.qs.charAt(this.qi) == '\\')
- escaped = true;
- else
- escaped = false;
- this.val += this.qs.charAt(this.qi);
- this.qi++;
+ if (!escaped && this.qs.charAt(this.qi) == mark)
+ break;
+ if (!escaped && this.qs.charAt(this.qi) == '\\')
+ escaped = true;
+ else
+ escaped = false;
+ this.val += this.qs.charAt(this.qi);
+ this.qi++;
}
this.lval = this.val.toLowerCase();
if (this.qi < this.ql)
this.qi++;
else //unterminated
- this.look = ""; //notify error
- //unquoted string
+ this.look = ""; //notify error
+ //unquoted string
} else {
this.look = "s";
this.val = "";
- while (this.qi < this.ql
- && !this._strchr("()/<>= \t\r\n", this.qs.charAt(this.qi))) {
+ while (this.qi < this.ql
+ && !this._strchr("()/<>= \t\r\n", this.qs.charAt(this.qi))) {
this.val = this.val + this.qs.charAt(this.qi);
this.qi++;
}
@@ -494,11 +586,14 @@ CQLParser.prototype = {
_strchr: function (s, ch) {
return s.indexOf(ch) >= 0
},
- _lookupPrefix: function(name) {
+ _lookupPrefix: function (name) {
return this.prefixes[name] ? this.prefixes[name] : "";
},
- _addPrefix: function(name, value) {
+ _addPrefix: function (name, value) {
//overwrite existing items
this.prefixes[name] = value;
}
}
+
+// for module import systems uncomment the following line
+// module.exports = CQLParser;
diff --git a/index.html b/index.html
index 50aaef1..34eec2d 100644
--- a/index.html
+++ b/index.html
@@ -4,6 +4,48 @@
+
CQL parser
@@ -28,15 +100,27 @@
-
-
-
-
+
+
+
+
+
+
Annotated
(original input)
+
+