File: lib-js/xbseparser.js

Recommend this page to a friend!
  Classes of Alexey Znaev   XBSDB   lib-js/xbseparser.js   Download  
File: lib-js/xbseparser.js
Role: Class source
Content type: text/plain
Description: Expression parser
Class: XBSDB
Manipulate arrays with an SQL-like language
Author: By
Last change: changed Listing priority
Date: 13 years ago
Size: 32,581 bytes
 

Contents

Class file image Download
/////////////////////////////////////////////////////////////////////////// // // 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; } }