///////////////////////////////////////////////////////////////////////////
//
// XBSDB - Cross-Browser JavaScript Database library
// Copyright (C) 2010 Alexey A.Znayev
//
// This file is part of XBSDB.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// Alexey A.Znayev, znaeff@mail.ru
//
///////////////////////////////////////////////////////////////////////////
// This flie contains private class(es) and/or method(s) and may be changed any time
function XBSEParser(){
this.sResultCode = 'OK';
this.oResult;
}
function XBSEParserResult(){
// types:
// arrays
//array_OR (OR array)
//array_AND (AND array)
// 'WHERE' parsing objects
//object_calc_scalar (scalar calculation object)
//object_calc_logical (logical calculation object) - not done yet
//object_calc_string (string calculation object) - not done yet
// 'KEY' parsing objects
//object_key_scalar (scalar key object)
//object_key_logical (logical key object) - not done yet
//object_key_string (string key object) - not done yet
this.sType; // element type
this.aOR; // if Type == 'array_OR' - array of something binded by OR
this.aAND; // if Type == 'array_AND' - array of something binded by AND
this.sExprFields; // if Type == 'object_calc_scalar','object_calc_logical','object_key_scalar' - string of expression with field names
this.sExprFieldsX; // if Type == 'object_calc_scalar','object_calc_logical','object_key_scalar' - string of expression with field names extended by strings before filed name and after one
this.sConstant; // if Type == 'object_calc_scalar' - string of constant
this.sOperation; // if Type == 'object_calc_scalar' - string of logical operation between sExprFields (left side) and sConstant (right side)
this.oFields = {}; // if Type == 'object_calc_scalar','object_calc_logical','object_key_scalar' - hash of used field names ('field' : true);
}
XBSEParser.prototype.Parse = function(sExpr,oOptions){
this.sResultCode = 'OK';
if(typeof sExpr == 'string' && sExpr != ''){
this.oResult = new XBSEParserResult();
this._aFieldNames = [];
this._sFieldBefore = '';
this._sFieldAfter = '';
this._sExprType = 'OR';
this._sExprSource = sExpr;
this._aPSyn = []; // syntax
this._oPSem = {}; // semantics
this._oPCon = {}; // context
if(oOptions && typeof oOptions == 'object'){
if(Object.prototype.toString.call(oOptions.aFieldNames) === '[object Array]'){
this._aFieldNames = oOptions.aFieldNames;
}
if(oOptions.sFieldBefore && typeof oOptions.sFieldBefore == 'string'){
this._sFieldBefore = oOptions.sFieldBefore;
}
if(oOptions.sFieldAfter && typeof oOptions.sFieldAfter == 'string'){
this._sFieldAfter = oOptions.sFieldAfter;
}
if(oOptions.sExprType && typeof oOptions.sExprType == 'string'){
switch(oOptions.sExprType.toUpperCase()){
case 'OR' :
case 'AND' :
case 'WHERE' :
this._sExprType = 'WHERE';
break;
case 'KEY':
this._sExprType = 'KEY';
break;
}
}
}
if(this._ParseSyn()){
if(this._ParseSem()){
if(this._ParseCon()){
this.oResult.sType = this._oPCon.sType;
this.oResult.aOR = this._oPCon.aOR;
this.oResult.aAND = this._oPCon.aAND;
this.oResult.sExprFields = this._oPCon.sExprFields;
this.oResult.sExprFieldsX = this._oPCon.sExprFieldsX;
this.oResult.sConstant = this._oPCon.sConstant;
this.oResult.sOperation = this._oPCon.sOperation;
}
}
}
delete this._aFieldNames;
delete this._sFieldBefore;
delete this._sFieldAfter;
delete this._sExprSource;
delete this._aPSyn;
delete this._oPSem;
delete this._oPCon;
}else{
this.sResultCode = 'PARSER_SYN_EXPR_BAD';
}
if(this.sResultCode == 'OK'){
return this.oResult;
}else{
return false;
}
}
//////////////////////////////////////////////////////////////////////////////////
// syntax
function XBSEPSynItem(Value,sType,nPos,nLevel){
// types:
//const_string (string constant)
//const_numeric (numeric constant)
//bracket_left (left bracket)
//bracket_right (right bracket)
//oper_comparsion (comparsion operation)
//oper_scalar (scalar operation)
//oper_bind_AND (bind operation AND)
//oper_bind_OR (bind operation OR)
//field (field)
this.Value = Value; // element value (strings in initial quotes!)
this.sType = sType; // element type
this.nPos = nPos; // element position
this.nLevel = nLevel; // element brackets level
}
XBSEParser.prototype._ParseSyn = function(){
var rSymbols = /./ig;
var rOpersComp = /[<>\=\!]/;
var rOpersScal = /[\+\-\*\/]/;
var sKav = ''; // current symbol of quote (and flag of string value) (',")
var nBrackets = 0; // number of open brackets
var sItemValue = '';
var sItemType = '';
var nItemPos = 0;
var aExpr = this._sExprSource.match(rSymbols), i;
try{
for(i = 0; i < aExpr.length; i++){ // solid
if(sItemType != 'const_string'){ // not string
if(aExpr[i] == "'" || aExpr[i] == '"'){
if(sItemValue != ''){
if(!this._AddPSynItem(sItemValue,sItemType,nItemPos)){
this.sResultCode = 'PARSER_SYN_ELEMENT_UN';
break;
}
}
sKav = aExpr[i];
sItemValue = aExpr[i];
sItemType = 'const_string';
nItemPos = i;
}else if(rOpersComp.test(aExpr[i])){
if(sItemType == 'oper_comparsion' && aExpr[i] == '=' && sItemValue.length == 1){
sItemValue += aExpr[i];
}else{
if(sItemValue != ''){
if(!this._AddPSynItem(sItemValue,sItemType,nItemPos)){
this.sResultCode = 'PARSER_SYN_ELEMENT_UN';
break;
}
}
sItemValue = aExpr[i];
sItemType = 'oper_comparsion';
nItemPos = i;
}
}else if(rOpersScal.test(aExpr[i])){
if(sItemValue != ''){
if(!this._AddPSynItem(sItemValue,sItemType,nItemPos)){
this.sResultCode = 'PARSER_SYN_ELEMENT_UN';
break;
}
}
sItemValue = aExpr[i];
sItemType = 'oper_scalar';
nItemPos = i;
}else if(aExpr[i] == '('){
if(sItemValue != ''){
if(!this._AddPSynItem(sItemValue,sItemType,nItemPos)){
this.sResultCode = 'PARSER_SYN_ELEMENT_UN';
break;
}
}
sItemValue = aExpr[i];
sItemType = 'bracket_left';
nItemPos = i;
nBrackets ++;
}else if(aExpr[i] == ')'){
if(sItemValue != ''){
if(!this._AddPSynItem(sItemValue,sItemType,nItemPos)){
this.sResultCode = 'PARSER_SYN_ELEMENT_UN';
break;
}
}
if(nBrackets > 0){
sItemValue = aExpr[i];
sItemType = 'bracket_right';
nItemPos = i;
nBrackets --;
}else{
this.sResultCode = 'PARSER_SYN_BRACKETS_R';
break;
}
}else if(aExpr[i] == ' '){
if(sItemValue != ''){
if(!this._AddPSynItem(sItemValue,sItemType,nItemPos)){
this.sResultCode = 'PARSER_SYN_ELEMENT_UN';
break;
}
}
sItemValue = '';
sItemType = '';
nItemPos = i;
}else{
if(sItemType != ''){
if(sItemValue != ''){
if(!this._AddPSynItem(sItemValue,sItemType,nItemPos)){
this.sResultCode = 'PARSER_SYN_ELEMENT_UN';
break;
}
}
sItemValue = aExpr[i];
sItemType = '';
nItemPos = i;
}else{
if(sItemValue != ''){
sItemValue += aExpr[i];
}else{
sItemValue = aExpr[i];
sItemType = '';
nItemPos = i;
}
}
}
}else{
if(aExpr[i] != sKav){
sItemValue += aExpr[i];
}else{
sItemValue += aExpr[i];
if(!this._AddPSynItem(sItemValue,sItemType,nItemPos)){
this.sResultCode = 'PARSER_SYN_ELEMENT_UN';
break;
}
sKav = '';
sItemValue = '';
sItemType = '';
nItemPos = i;
}
}
} //for
if(this.sResultCode == 'OK'){
if(sKav != ''){
this.sResultCode = 'PARSER_SYN_EOS_MISSING';
nItemPos = i;
}else if(nBrackets != 0){
this.sResultCode = 'PARSER_SYN_BRACKETS_L';
}else{
if(sItemValue != ''){
if(!this._AddPSynItem(sItemValue,sItemType,nItemPos)){
this.sResultCode = 'PARSER_SYN_ELEMENT_UN';
}
}
}
}
if(this.sResultCode == 'OK'){
var iPrev2 = -1, iPrev1 = -1;
for(i = 0; i < this._aPSyn.length; i++){ // negative numbers, solid
if(this._aPSyn[i]){
if(iPrev1 >= 0 && i > iPrev1 &&
this._aPSyn[i].sType == 'const_numeric' &&
this._aPSyn[iPrev1].sType == 'oper_scalar' &&
this._aPSyn[iPrev1].Value == '-' &&
this._aPSyn[i].nPos - this._aPSyn[iPrev1].nPos == 1 &&
(iPrev2 == -1 || iPrev2 >=0 && (this._aPSyn[iPrev2].sType == 'bracket_left' || this._aPSyn[iPrev2].sType == 'oper_comparsion' || this._aPSyn[iPrev1].nPos - this._aPSyn[iPrev2].nPos - this._aPSyn[iPrev2].Value.length == 1))
){
this._aPSyn[i].Value = '-' + this._aPSyn[i].Value;
delete this._aPSyn[iPrev1];
iPrev1 = -1;
}
iPrev2 = iPrev1;
iPrev1 = i;
}
} //for
var aBuff = []; // solidization after deleting of negative numbers minuses
for(i = 0; i < this._aPSyn.length; i++){ // not solid
if(this._aPSyn[i]){
aBuff.push(this._aPSyn[i]);
}
} //for
this._aPSyn = aBuff; // solid now
var nBN1, nBN2, nBQ=0, aBracketsOdd = [], j, k, l;
for(i = 0; i < this._aPSyn.length; i++){ // brackets levels parsing, solid
if(this._aPSyn[i]){
if(this._aPSyn[i].sType == 'bracket_left'){
nBN1 = i;
nBQ = 0;
for(j = i+1; j < this._aPSyn.length; j++){ // solid
if(this._aPSyn[j].sType == 'bracket_right'){
if(nBQ != 0){
nBQ--;
}else{
nBN2 = j;
break;
}
}
if(this._aPSyn[j].sType == 'bracket_left'){
nBQ++;
}
} //for j
var bIsLevelUp = false;
for(k = nBN1; k <= nBN2; k++){
if(this._aPSyn[k].sType == 'oper_bind_AND' || this._aPSyn[k].sType == 'oper_bind_OR'){ // increase level when AND or OR exists only
bIsLevelUp = true;
break;
}
} //for k
if(bIsLevelUp){
for(k = nBN1; k <= nBN2; k++){ // level increasing
this._aPSyn[k].nLevel++;
} //for k
}else{
aBracketsOdd.push(nBN1); // store redundant brackets
aBracketsOdd.push(nBN2);
}
}
} //if
if(aBracketsOdd.length > 0){ // process redundant brackets
this.sResultCode = 'PARSER_SYN_BRACKETS_ODD PARSER_AT_POS ';
for(l = 0; l < aBracketsOdd.length; l++){ // solid
this.sResultCode += this._aPSyn[aBracketsOdd[l]].nPos + ' ';
}
}
} //for i
} //if
}catch(e){
this.sResultCode = 'PARSER_SYN_ERROR_UN';
}
switch(this.sResultCode){
case 'PARSER_SYN_ELEMENT_UN' :
this.sResultCode += ' PARSER_AT_POS ' + nItemPos + ' (' + sItemValue + ')';
break;
case 'PARSER_SYN_EOS_MISSING' :
this.sResultCode += ' PARSER_AT_POS ' + nItemPos;
break;
case 'PARSER_SYN_BRACKETS_R' :
this.sResultCode += ' PARSER_AT_POS ' + nItemPos;
break;
case 'PARSER_SYN_BRACKETS_L' :
this.sResultCode += ' PARSER_AT_POS ' + nItemPos;
break;
}
if(this.sResultCode == 'OK'){
return true;
}else{
return false;
}
}
XBSEParser.prototype._AddPSynItem = function(sItemValue,sItemType,nItemPos){
if(sItemType == ''){
var sBuf = sItemValue.toLowerCase(), rNumber = /^\d+(\.\d*)?$/, i;
for(i = 0; i < this._aFieldNames.length; i++){ //solid
if(this._aFieldNames[i]){
if(sBuf == this._aFieldNames[i]){
sItemValue = sBuf;
sItemType = 'field';
this.oResult.oFields[sItemValue] = true;
break;
}
}
}//for
if(sItemType == ''){
if(sBuf == 'and'){
sItemValue = sBuf.toUpperCase();
sItemType = 'oper_bind_AND';
}else if(sBuf == 'or'){
sItemValue = sBuf.toUpperCase();
sItemType = 'oper_bind_OR';
}else if(rNumber.test(sBuf)){
sItemType = 'const_numeric';
}
}
}
if(sItemType == 'oper_comparsion' && sItemValue == '='){
sItemValue = '==';
}
if(sItemType != ''){
this._aPSyn.push(new XBSEPSynItem(sItemValue,sItemType,nItemPos,0));
return true;
}else{
return false;
}
}
//////////////////////////////////////////////////////////////////////////////////
// semantics
function XBSEPSemItem(Value,sType){
// types
//array_undef (array of something)
//array_OR (OR array)
//array_AND (AND array)
//array_calculation (comparsion array)
//array_expression (expression array)
//array_expression_fields (expression array with field names)
//array_expression_const (expression array with constants only)
//link2syn (link to syntax array element)
this.Value = Value; // element value (array or number)
if(sType != ''){
this.sType = sType; // element type
}else{
this.sType = '';
}
}
XBSEParser.prototype._ParseSem = function(){
this._oPSemBuf = new XBSEPSemItem([],'array_undef'); // root element XBSEPSemItem, type 'array_undef'
for(var i = 0; i < this._aPSyn.length; i++){ //solid
if(this._aPSyn[i]){
this._oPSemBuf.Value.push(new XBSEPSemItem(i,'link2syn'));
}
}
try{
switch(this._sExprType){
case 'WHERE' :
if(!this._ParseSemBR(this._oPSemBuf)){
return false;
}
this._ParseSemOR(this._oPSemBuf);
this._ParseSemAND(this._oPSemBuf);
this._ParseSemComparsion(this._oPSemBuf);
case 'KEY' :
this._ParseSemCalculation(this._oPSemBuf);
}
}catch(e){
this.sResultCode = 'PARSER_SEM_ERROR_UN';
}
if(this.sResultCode == 'OK'){
this._oPSem = this._oPSemBuf;
delete this._oPSemBuf;
return true;
}else{
delete this._oPSemBuf;
return false;
}
}
// parsing of arrays with 'array_undef' type to levels
// solid sequences of array with level upper than given move to nested arrays type 'array_undef'
XBSEParser.prototype._ParseSemBR = function(oPA){
if(oPA.sType == 'array_undef'){
var aArrayNested = [], aNewValue = [], nLowestLevel = 65535, i;
for(i = 0; i < oPA.Value.length; i++){ //lowest level definition, solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object' && oPA.Value[i].sType == 'link2syn' && nLowestLevel > this._aPSyn[oPA.Value[i].Value].nLevel){
nLowestLevel = this._aPSyn[oPA.Value[i].Value].nLevel;
}
}//for
for(i = 0; i < oPA.Value.length; i++){ //moving of upped levels elements to nested arrays except first and last (brackets), solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object'){
if(oPA.Value[i].sType == 'link2syn'){
if(this._aPSyn[oPA.Value[i].Value].nLevel == nLowestLevel){
if(aArrayNested.length >= 3){
aNewValue.push(new XBSEPSemItem(aArrayNested.slice(1,aArrayNested.length-1),'array_undef'));
aArrayNested = [];
}else if(aArrayNested.length > 0 && aArrayNested.length < 3){
this.sResultCode = 'PARSER_SEM_UPPER_ARRAY_MUST_3';
}
aNewValue.push(oPA.Value[i]);
}else{
aArrayNested.push(oPA.Value[i]);
}
}else{
aNewValue.push(oPA.Value[i]);
}//if
}//if
}//for
if(aArrayNested.length >= 3){
aNewValue.push(new XBSEPSemItem(aArrayNested.slice(1,aArrayNested.length-1),'array_undef'));
aArrayNested = [];
}else if(aArrayNested.length > 0 && aArrayNested.length < 3){
this.sResultCode = 'PARSER_SEM_UPPER_ARRAY_MUST_3';
}
oPA.Value = aNewValue;
for(i = 0; i < oPA.Value.length; i++){ //recursive call for nested arrays, solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object' && oPA.Value[i].sType == 'array_undef'){
this._ParseSemBR(oPA.Value[i]);
}
}//for
}//if
return true;
}
// parsing of arrays with 'array_undef' type to 'oper_bind_OR' (OR) elements
// if array contains 'oper_bind_OR'
// then its type becomes 'array_OR' and its elements move to nested arrays with 'array_undef' type
// else its type keeps 'array_undef', 'link2syn' elements keep
XBSEParser.prototype._ParseSemOR = function(oPA){
if(oPA.sType == 'array_undef'){
var aItemNested, aNewValue = [], i;
for(i = 0; i < oPA.Value.length; i++){ //type defenition, solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object' && oPA.Value[i].sType == 'link2syn' && this._aPSyn[oPA.Value[i].Value].sType == 'oper_bind_OR'){
oPA.sType = 'array_OR';
break;
}
}//for
if(oPA.sType == 'array_OR'){ //move elements between 'oper_bind_OR' to nested arrays
aItemNested = new XBSEPSemItem([],'array_undef');
for(i = 0; i < oPA.Value.length; i++){ // solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object'){
if(oPA.Value[i].sType == 'link2syn' && this._aPSyn[oPA.Value[i].Value].sType == 'oper_bind_OR'){
if(aItemNested.Value.length > 0){
if(aItemNested.Value.length == 1 && (aItemNested.Value[0].sType == 'array_undef' || aItemNested.Value[0].sType == 'array_OR')){
aNewValue.push(aItemNested.Value[0]);
}else{
aNewValue.push(aItemNested);
}
aItemNested = new XBSEPSemItem([],'array_undef');
}
}else{
aItemNested.Value.push(oPA.Value[i]);
}
}
}//for
if(aItemNested.Value.length > 0){
if(aItemNested.Value.length == 1 && (aItemNested.Value[0].sType == 'array_undef' || aItemNested.Value[0].sType == 'array_OR')){
aNewValue.push(aItemNested.Value[0]);
}else{
aNewValue.push(aItemNested);
}
}
oPA.Value = aNewValue;
}//if
}//if
if(oPA.sType == 'array_undef' || oPA.sType == 'array_OR'){
for(i = 0; i < oPA.Value.length; i++){ //recursive call for nested arrays, solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object' && oPA.Value[i].sType == 'array_undef'){
this._ParseSemOR(oPA.Value[i]);
}
}//for
}//if
}
// parsing of arrays with 'array_undef' type to 'oper_bind_AND' (AND) elements
// if array contains 'oper_bind_AND'
// then its type becomes 'array_AND' and its elements move to nested arrays with 'array_undef' type
// else its type keeps 'array_undef', 'link2syn' elements keep
XBSEParser.prototype._ParseSemAND = function(oPA){
if(oPA.sType == 'array_undef'){
var aItemNested, aNewValue = [], i;
for(i = 0; i < oPA.Value.length; i++){ //type defenition, solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object' && oPA.Value[i].sType == 'link2syn' && this._aPSyn[oPA.Value[i].Value].sType == 'oper_bind_AND'){
oPA.sType = 'array_AND';
break;
}
}//for
if(oPA.sType == 'array_AND'){ //move elements between 'oper_bind_AND' to nested arrays
aItemNested = new XBSEPSemItem([],'array_undef');
for(i = 0; i < oPA.Value.length; i++){ // solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object'){
if(oPA.Value[i].sType == 'link2syn' && this._aPSyn[oPA.Value[i].Value].sType == 'oper_bind_AND'){
if(aItemNested.Value.length > 0){
if(aItemNested.Value.length == 1 && (aItemNested.Value[0].sType == 'array_undef' || aItemNested.Value[0].sType == 'array_OR' || aItemNested.Value[0].sType == 'array_AND')){
aNewValue.push(aItemNested.Value[0]);
}else{
aNewValue.push(aItemNested);
}
aItemNested = new XBSEPSemItem([],'array_undef');
}
}else{
aItemNested.Value.push(oPA.Value[i]);
}
}
}//for
if(aItemNested.Value.length > 0){
if(aItemNested.Value.length == 1 && (aItemNested.Value[0].sType == 'array_undef' || aItemNested.Value[0].sType == 'array_OR' || aItemNested.Value[0].sType == 'array_AND')){
aNewValue.push(aItemNested.Value[0]);
}else{
aNewValue.push(aItemNested);
}
}
oPA.Value = aNewValue;
}//if
}//if
if(oPA.sType == 'array_undef' || oPA.sType == 'array_OR' || oPA.sType == 'array_AND'){
for(i = 0; i < oPA.Value.length; i++){ //recursive call for nested arrays, solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object' && (oPA.Value[i].sType == 'array_undef' || oPA.Value[i].sType == 'array_OR')){
this._ParseSemAND(oPA.Value[i]);
}
}//for
}//if
}
// parsing of arrays with 'array_undef' type to 'oper_comparsion'(><!=) elements
// if array contains 'oper_comparsion'
// then its type becomes 'array_calculation' and its elements between 'oper_comparsion' move to nested arrays with 'array_undef' type
// 'oper_comparsion' element keeps
// else its type keeps 'array_undef', 'link2syn' elements keep
XBSEParser.prototype._ParseSemComparsion = function(oPA){
if(oPA.sType == 'array_undef'){
var aItemNested, aNewValue = [], i;
for(i = 0; i < oPA.Value.length; i++){ //type defenition, solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object' && oPA.Value[i].sType == 'link2syn' && this._aPSyn[oPA.Value[i].Value].sType == 'oper_comparsion'){
oPA.sType = 'array_calculation';
break;
}
}//for
if(oPA.sType == 'array_calculation'){ //move elements between 'oper_comparsion' to nested 'array_undef' arrays
aItemNested = new XBSEPSemItem([],'array_undef');
for(i = 0; i < oPA.Value.length; i++){// solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object'){
if(oPA.Value[i].sType == 'link2syn' && this._aPSyn[oPA.Value[i].Value].sType == 'oper_comparsion'){
aNewValue.push(aItemNested);
aNewValue.push(oPA.Value[i]);
aItemNested = new XBSEPSemItem([],'array_undef');
}else{
aItemNested.Value.push(oPA.Value[i]);
}
}
}//for
if(aItemNested.Value.length > 0){
aNewValue.push(aItemNested);
}
oPA.Value = aNewValue;
}//if
}//if
if(oPA.sType == 'array_undef' || oPA.sType == 'array_OR' || oPA.sType == 'array_AND' || oPA.sType == 'array_calculation'){
for(i = 0; i < oPA.Value.length; i++){ //recursive call for nested arrays, solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object' && (oPA.Value[i].sType == 'array_undef' || oPA.Value[i].sType == 'array_OR' || oPA.Value[i].sType == 'array_AND')){
this._ParseSemComparsion(oPA.Value[i]);
}
}//for
}//if
}
// parsing of arrays with 'array_undef' type to 'field', 'const_numeric', 'const_string' elements
// if array contains one 'field'
// then its type becomes 'array_expression_fields'
// else its type becomes 'array_expression_const'
XBSEParser.prototype._ParseSemCalculation = function(oPA){
if(oPA.sType == 'array_undef'){ //type defenition
var oTypes = {}, i;
for(i = 0; i < oPA.Value.length; i++){ //store all presented types to hash, solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object'){
if(oPA.Value[i].sType == 'link2syn'){
oTypes[this._aPSyn[oPA.Value[i].Value].sType] = true;
}else{
oTypes[oPA.Value[i].sType] = true;
}
}
}//for
delete oTypes['bracket_left']; // check of types, allowed in key expression
delete oTypes['bracket_right'];
delete oTypes['oper_scalar'];
if(oTypes['const_string']){
oPA.sType = 'array_expression_const';
delete oTypes['const_string'];
}
if(oTypes['const_numeric']){
oPA.sType = 'array_expression_const';
delete oTypes['const_numeric'];
}
if(oTypes['field'] ){
oPA.sType = 'array_expression_fields';
delete oTypes['field'];
}
var bPACorrect = true; // is hash empty (more elegant solution?)
for(i in oTypes){
bPACorrect = false;
}
if(!bPACorrect){
this.sResultCode = 'PARSER_SEM_KEY_EXPR_ITEM_UN : ' + oTypes.toString();
}
}
if(oPA.sType == 'array_undef' || oPA.sType == 'array_OR' || oPA.sType == 'array_AND' || oPA.sType == 'array_calculation'){
for(i = 0; i < oPA.Value.length; i++){ //recursive call for nested arrays, solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object' && (oPA.Value[i].sType == 'array_undef' || oPA.Value[i].sType == 'array_OR' || oPA.Value[i].sType == 'array_AND' || oPA.Value[i].sType == 'array_calculation')){
this._ParseSemCalculation(oPA.Value[i]);
}
}//for
}//if
}
//////////////////////////////////////////////////////////////////////////////////
// context
function XBSEPConItem(sType){
// types:
// arrays
//array_OR (OR array)
//array_AND (AND array)
// WHERE parsing objects
//object_calc_scalar (scalar calculation object)
//object_calc_logical (logical calculation object) - not done yet
//object_calc_string (string calculation object) - not done yet
// KEY parsing objects
//object_key_scalar (scalar key object)
//object_key_logical (logical key object) - not done yet
//object_key_string (string key object) - not done yet
if(sType != ''){
this.sType = sType; // element type
}else{
this.sType = '';
}
this.aOR;
this.aAND;
this.sExprFields;
this.sExprFieldsX;
this.sConstant;
this.sOperation;
}
XBSEParser.prototype._ParseCon = function(){
this._oPConBuf = new XBSEPConItem(); // root XBSEPConItem element
try{
switch(this._sExprType){
case 'WHERE' :
this._ParseConAOAA(this._oPConBuf,this._oPSem);
break;
case 'KEY' :
this._oPConBuf.sType = 'object_key_scalar';
this._oPConBuf.sExprFields = '';
this._oPConBuf.sExprFieldsX = '';
this._ParseConAEF(this._oPConBuf,this._oPSem);
}
}catch(e){
this.sResultCode = 'PARSER_CON_ERROR_UN';
}
if(this.sResultCode == 'OK'){
this._oPCon = this._oPConBuf;
delete this._oPConBuf;
return true;
}else{
delete this._oPConBuf;
return false;
}
}
XBSEParser.prototype._ParseConAOAA = function(oRes,oPA){
// oRes has no type, determine here
// if array type is array_OR or array_AND
// then one cycle thru oPA.Value elements
// for array_AND and array_OR elements : create untyped aCon elements, then recursive call for them
// for array_calculation elements : create 'object_calc_scalar' aCon elements and fill them from
// array_expression_fields, array_expression_const and link2syn oPA-elements
if(oPA.sType == 'array_OR' || oPA.sType == 'array_AND'){
var aNewValue = [], oNewResItem, i;
oRes.sType = oPA.sType;
for(i = 0; i < oPA.Value.length; i++){// solid
if(oPA.Value[i] && typeof oPA.Value[i] == 'object'){
oNewResItem = new XBSEPConItem();
if(oPA.Value[i].sType == 'array_calculation'){
if(!this._ParseConAC(oNewResItem,oPA.Value[i])){
return false;
}
}else if(oPA.Value[i].sType == 'array_OR' || oPA.Value[i].sType == 'array_AND'){
if(!this._ParseConAOAA(oNewResItem,oPA.Value[i])){
return false;
}
}else if(oPA.Value[i].sType == 'array_undef'){
this.sResultCode = 'PARSER_CON_ARRAY_UN : ' + oPA.sType;
}else{
this.sResultCode = 'PARSER_CON_ELEMENT_UN : ' + oPA.sType;
}
aNewValue.push(oNewResItem);
}
}//for
if(oPA.sType == 'array_OR'){
oRes.aOR = aNewValue;
}else{
oRes.aAND = aNewValue;
}
}else if(oPA.sType == 'array_calculation'){
if(!this._ParseConAC(oRes,oPA)){
return false;
}
}else if(oPA.sType == 'array_undef'){
this.sResultCode = 'PARSER_CON_ARRAY_UN : ' + oPA.sType;
}else{
this.sResultCode = 'PARSER_CON_ELEMENT_UN : ' + oPA.sType;
}
if(this.sResultCode == 'OK'){
return true;
}else{
return false;
}
}
XBSEParser.prototype._ParseConAC = function(oRes,oPA){
// ac (calculation array) parsing: array consists of field(s) object and constant obect divided by operation
if(oPA.Value.length == 3){
if(oPA.Value[1].sType == 'link2syn' && this._aPSyn[oPA.Value[1].Value].sType == 'oper_comparsion'){
if(oPA.Value[0].sType == 'array_expression_fields' && oPA.Value[2].sType == 'array_expression_const' || oPA.Value[0].sType == 'array_expression_const' && oPA.Value[2].sType == 'array_expression_fields'){
oRes.sType = 'object_calc_scalar';
oRes.sExprFields = '';
oRes.sExprFieldsX = '';
oRes.sConstant = '';
oRes.sOperation = this._aPSyn[oPA.Value[1].Value].Value;
var aExprFields, aConstant;
if(oPA.Value[0].sType == 'array_expression_fields'){
aExprFields = oPA.Value[0];
aConstant = oPA.Value[2];
}else{
aConstant = oPA.Value[0];
aExprFields = oPA.Value[2];
var rLess = /</, rMore = />/;
if(rLess.test(oRes.sOperation)){
oRes.sOperation = oRes.sOperation.replace(rLess, '>');
}else if(rMore.test(oRes.sOperation)){
oRes.sOperation = oRes.sOperation.replace(rMore, '<');
}
}
if(!this._ParseConAEF(oRes,aExprFields)){
return false;
}
for(var j = 0; j < aConstant.Value.length; j++){ // solid
if(aConstant.Value[j] && typeof aConstant.Value[j] == 'object'){
if(oRes.sConstant != ''){
oRes.sConstant += ' ';
}
oRes.sConstant += this._aPSyn[aConstant.Value[j].Value].Value;
}
}//for
}else if(oPA.Value[0].sType == 'array_expression_fields' && oPA.Value[2].sType == 'array_expression_fields'){
oRes.sType = 'object_calc_logical';
oRes.sExprFields = '';
oRes.sExprFieldsX = '';
if(!this._ParseConAEF(oRes,oPA)){
return false;
}
}else{
this.sResultCode = 'PARSER_CON_ARRAY_AC_NO_FIELDS';
}
}else{
this.sResultCode = 'PARSER_CON_ARRAY_AC_2ND_NOT_LOGIC';
}
}else{
this.sResultCode = 'PARSER_CON_ARRAY_AC_MUST_HAVE_3_EL';
}
if(this.sResultCode == 'OK'){
return true;
}else{
return false;
}
}
XBSEParser.prototype._ParseConAEF = function(oRes,oPA){
var j;
switch(oPA.sType){
case 'array_expression_fields' :
//some checking needed mayby ?
for(j = 0; j < oPA.Value.length; j++){ // solid
if(oPA.Value[j] && typeof oPA.Value[j] == 'object'){
if(oRes.sExprFields != ''){
oRes.sExprFields += ' ';
}
oRes.sExprFields += this._aPSyn[oPA.Value[j].Value].Value;
if(oRes.sExprFieldsX != ''){
oRes.sExprFieldsX += ' ';
}
if(this._aPSyn[oPA.Value[j].Value].sType == 'field'){
oRes.sExprFieldsX += this._sFieldBefore;
}
oRes.sExprFieldsX += this._aPSyn[oPA.Value[j].Value].Value;
if(this._aPSyn[oPA.Value[j].Value].sType == 'field'){
oRes.sExprFieldsX += this._sFieldAfter;
}
}
} //for
break;
case 'array_calculation' :
for(j = 0; j < oPA.Value[0].Value.length; j++){ // solid
if(oPA.Value[0].Value[j] && typeof oPA.Value[0].Value[j] == 'object'){
if(oRes.sExprFields != ''){
oRes.sExprFields += ' ';
}
oRes.sExprFields += this._aPSyn[oPA.Value[0].Value[j].Value].Value;
if(oRes.sExprFieldsX != ''){
oRes.sExprFieldsX += ' ';
}
if(this._aPSyn[oPA.Value[0].Value[j].Value].sType == 'field'){
oRes.sExprFieldsX += this._sFieldBefore;
}
oRes.sExprFieldsX += this._aPSyn[oPA.Value[0].Value[j].Value].Value;
if(this._aPSyn[oPA.Value[0].Value[j].Value].sType == 'field'){
oRes.sExprFieldsX += this._sFieldAfter;
}
}
} //for
oRes.sExprFields += ' ' + this._aPSyn[oPA.Value[1].Value].Value;
oRes.sExprFieldsX += ' ' + this._aPSyn[oPA.Value[1].Value].Value;
for(j = 0; j < oPA.Value[2].Value.length; j++){ // solid
if(oPA.Value[2].Value[j] && typeof oPA.Value[2].Value[j] == 'object'){
if(oRes.sExprFields != ''){
oRes.sExprFields += ' ';
}
oRes.sExprFields += this._aPSyn[oPA.Value[2].Value[j].Value].Value;
if(oRes.sExprFieldsX != ''){
oRes.sExprFieldsX += ' ';
}
if(this._aPSyn[oPA.Value[2].Value[j].Value].sType == 'field'){
oRes.sExprFieldsX += this._sFieldBefore;
}
oRes.sExprFieldsX += this._aPSyn[oPA.Value[2].Value[j].Value].Value;
if(this._aPSyn[oPA.Value[2].Value[j].Value].sType == 'field'){
oRes.sExprFieldsX += this._sFieldAfter;
}
}
} //for
default :
this.sResultCode = 'PARSER_CON_ARRAY_UN : ' + oPA.sType;
}
if(this.sResultCode == 'OK'){
return true;
}else{
return false;
}
}
|