123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050 |
- /*------------------------------------------------------------------------------
- * NAME : Evaluator.js
- * PURPOSE : Expression Evaluator
- * AUTHOR : Prasad P. Khandekar
- * CREATED : August 21, 2005 Unary Minus = 0xAD
- *------------------------------------------------------------------------------
- * Copyright (c) 2005. Khan Information Systems. All Rights Reserved
- * The contents of this file are subject to the KIS Public License 1.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You should have received a copy of the KIS Public License along with
- * this library; if not, please ask your software vendor to provide one.
- *
- * YOU AGREE THAT THE PROGRAM IS PROVIDED AS-IS, WITHOUT WARRANTY OF ANY KIND
- * (EITHER EXPRESS OR IMPLIED) INCLUDING, WITHOUT LIMITATION, ANY IMPLIED
- * WARRANTY OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND ANY
- * WARRANTY OF NON INFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
- * PROGRAM, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * See the License for the specific language governing rights and limitations
- * under the License.
- *-----------------------------------------------------------------------------*/
- var UNARY_NEG = "";
- var ARG_TERMINAL = "Ø";
- var LESS_THAN = "«";
- var GREATER_THAN = "»";
- var NOT_EQUAL = "×";
- var DEBUG_ON = false;
- var NUMARIC_OP = "*,/,%,^";
- function Expression(pstrExp)
- {
- var strInFix = null;
- var arrVars = null;
- var arrTokens = null;
- var arrPostFix = null;
- var dtFormat = "dd/MM/yyyy";
- this.DateFormat = SetDateFormat;
- this.Expression = SetExpression;
- this.Parse = ParseExpression;
- this.Evaluate = EvaluateExpression;
- this.AddVariable = AddNewVariable;
- this.Reset = ClearAll;
- function SetDateFormat(pstrFmt)
- {
- dtFormat = pstrFmt;
- }
- function SetExpression(pstrExp)
- {
- strInFix = pstrExp;
- }
- function AddNewVariable(varName, varValue)
- {
- if (arrVars == null || arrVars == undefined)
- arrVars = new Array();
- arrVars[varName] = varValue;
- }
- function ClearAll()
- {
- arrVars = null;
- strInFix = null;
- arrTokens = null;
- arrPostFix = null;
- }
- function ParseExpression()
- {
- arrTokens = Tokanize(strInFix);
- if (arrTokens == null || arrTokens == undefined)
- throw "Unable to tokanize the expression!";
- if (arrTokens.length <= 0)
- throw "Unable to tokanize the expression!";
- arrPostFix = InFixToPostFix(arrTokens);
- if (arrPostFix == null || arrPostFix == undefined)
- throw "Unable to convert the expression to postfix form!";
- if (arrPostFix.length <= 0)
- throw "Unable to convert the expression to postfix form!";
- return arrPostFix.toString();
- }
- function getVariable(strVarName)
- {
- var retVal;
- debugAssert(strVarName);
- if (arrVars == null || arrVars == undefined)
- throw "Variable values are not supplied!";
- retVal = arrVars[strVarName];
- if (retVal == undefined || retVal == null)
- throw "Variable [" + strVarName + "] not defined";
- debugAssert(strVarName + " - " + retVal);
- return retVal;
- }
- // postfix function evaluator
- function EvaluateExpression()
- {
- var intIndex;
- var myStack;
- var strTok, strOp;
- var objOp1, objOp2, objTmp1, objTmp2;
- var dblNo, dblVal1, dblVal2;
- var parrExp;
- if (arrPostFix == null || arrPostFix == undefined)
- ParseExpression();
- if (arrPostFix.length == 0)
- throw "Unable to parse the expression!";
- parrExp = arrPostFix;
- if (parrExp == null || parrExp == undefined)
- {
- throw "Invalid postfix expression!";
- return;
- }
- if (parrExp.length == 0)
- {
- throw "Invalid postfix expression!";
- return;
- }
- intIndex = 0;
- myStack = new Stack();
- while (intIndex < parrExp.length)
- {
- strTok = parrExp[intIndex];
- switch (strTok)
- {
- case ARG_TERMINAL :
- myStack.Push(strTok);
- break;
- case UNARY_NEG :
- if (myStack.IsEmpty())
- throw "No operand to negate!";
- objOp1 = null;
- objOp2 = null;
- objOp1 = myStack.Pop();
- if (IsVariable(objOp1))
- objOp1 = getVariable(objOp1);
- dblNo = ToNumber(objOp1);
- if (isNaN(dblNo))
- throw "Not a numaric value!";
- else
- {
- dblNo = (0 - dblNo);
- myStack.Push(dblNo);
- }
- break;
- case "!" :
- if (myStack.IsEmpty())
- throw "No operand on stack!";
- objOp1 = null;
- objOp2 = null;
- objOp1 = myStack.Pop();
- if (IsVariable(objOp1))
- objOp1 = getVariable(objOp1);
- objOp1 = ToBoolean(objOp1);
- if (objOp1 == null)
- throw "Not a boolean value!";
- else
- myStack.Push(!objOp1);
- break;
- case "*" :
- case "/" :
- case "%" :
- case "^" :
- if (myStack.IsEmpty() || myStack.Size() < 2)
- throw "Stack is empty, can not perform [" + strTok + "]";
- objOp1 = null;
- objOp2 = null;
- objTmp = null;
- objOp2 = myStack.Pop();
- objOp1 = myStack.Pop();
- if (IsVariable(objOp1))
- objOp1 = getVariable(objOp1);
- if (IsVariable(objOp2))
- objOp2 = getVariable(objOp2);
- dblVal1 = ToNumber(objOp1);
- dblVal2 = ToNumber(objOp2);
- if (isNaN(dblVal1) || isNaN(dblVal2))
- throw "Either one of the operand is not a number can not perform [" +
- strTok + "]";
- if (strTok == "^")
- myStack.Push(Math.pow(dblVal1, dblVal2));
- else if (strTok == "*")
- myStack.Push((dblVal1 * dblVal2));
- else if (strTok == "/")
- myStack.Push((dblVal1 / dblVal2));
- else
- {
- debugAssert (dblVal1 + " - " + dblVal2);
- myStack.Push((dblVal1 % dblVal2));
- }
- break;
- case "+" :
- case "-" :
- if (myStack.IsEmpty() || myStack.Size() < 2)
- throw "Stack is empty, can not perform [" + strTok + "]";
- objOp1 = null;
- objOp2 = null;
- objTmp1 = null;
- objTmp2 = null;
- strOp = ((strTok == "+") ? "Addition" : "Substraction");
- objOp2 = myStack.Pop();
- objOp1 = myStack.Pop();
- if (IsVariable(objOp1))
- objOp1 = getVariable(objOp1);
- if (IsVariable(objOp2))
- objOp2 = getVariable(objOp2);
- if (IsBoolean(objOp1) || IsBoolean(objOp2))
- throw "Can not perform " + strOp + " with boolean values!";
- else if (isDate(objOp1, dtFormat) && isDate(objOp1, dtFormat))
- throw strOp + " of two dates not supported!";
- else if (typeof(objOp1) == "object" || typeof(objOp1) == "object")
- throw strOp + " of two objects not supported!";
- else if (typeof(objOp1) == "undefined" || typeof(objOp1) == "undefined")
- throw strOp + " of two undefined not supported!";
- else if (IsNumber(objOp1) && IsNumber(objOp2))
- {
- // Number addition
- dblVal1 = ToNumber(objOp1);
- dblVal2 = ToNumber(objOp2);
- if (strTok == "+")
- myStack.Push((dblVal1 + dblVal2));
- else
- myStack.Push((dblVal1 - dblVal2));
- }
- else
- {
- if (strTok == "+")
- myStack.Push((objOp1 + objOp2));
- else
- throw strOP + " not supported for strings!"
- }
- break;
- case "=" :
- case "<" :
- case ">" :
- case "<>" :
- case "<=" :
- case ">=" :
- if (myStack.IsEmpty() || myStack.Size() < 2)
- throw "Stack is empty, can not perform [" + strTok + "]";
- objOp1 = null;
- objOp2 = null;
- objTmp1 = null;
- objTmp2 = null;
- objOp2 = myStack.Pop();
- objOp1 = myStack.Pop();
- if (IsVariable(objOp1))
- objOp1 = getVariable(objOp1);
- if (IsVariable(objOp2))
- objOp2 = getVariable(objOp2);
- if (IsNumber(objOp1) && IsNumber(objOp2))
- {
- dblVal1 = ToNumber(objOp1);
- dblVal2 = ToNumber(objOp2);
- if (strTok == "=")
- myStack.Push((dblVal1 == dblVal2));
- else if (strTok == "<>")
- myStack.Push((dblVal1 != dblVal2));
- else if (strTok == ">")
- myStack.Push((dblVal1 > dblVal2));
- else if (strTok == "<")
- myStack.Push((dblVal1 < dblVal2));
- else if (strTok == "<=")
- myStack.Push((dblVal1 <= dblVal2));
- else if (strTok == ">=")
- myStack.Push((dblVal1 >= dblVal2));
- }
- else if (IsBoolean(objOp1) && IsBoolean(objOp2) &&
- (strTok == "=" || strTok == "<>"))
- {
- objTmp1 = ToBoolean(objOp1);
- objTmp2 = ToBoolean(objOp2);
- if (strTok == "=")
- myStack.Push((objTmp1 == objTmp2));
- else if (strTok == "<>")
- myStack.Push((objTmp1 != objTmp2));
- }
- else if (isDate(objOp1, dtFormat) &&
- isDate(objOp2, dtFormat))
- {
- if (typeof(objOp1) == "string")
- objTmp1 = getDateFromFormat(objOp1, dtFormat);
- else
- objTmp1 = objOp1;
- if (typeof(objOp1) == "string")
- objTmp2 = getDateFromFormat(objOp2, dtFormat);
- else
- objTmp2 = objOp2;
- if (strTok == "=")
- myStack.Push((objTmp1 == objTmp2));
- else if (strTok == "<>")
- myStack.Push((objTmp1 != objTmp2));
- else if (strTok == ">")
- myStack.Push((objTmp1 > objTmp2));
- else if (strTok == "<")
- myStack.Push((objTmp1 < objTmp2));
- else if (strTok == "<=")
- myStack.Push((objTmp1 <= objTmp2));
- else if (strTok == ">=")
- myStack.Push((objTmp1 >= objTmp2));
- }
- else if ((typeof(objOp1) == "string" &&
- typeof(objOp2) == "string") &&
- (strTok == "=" || strTok == "<>"))
- {
- if (strTok == "=")
- myStack.Push((objOp1 == objOp2));
- else if (strTok == "<>")
- myStack.Push((objOp1 != objOp2));
- }
- else
- throw "For " + strTok +
- " operator LHS & RHS should be of same data type!";
- break;
- case "&" :
- case "|" :
- if (myStack.IsEmpty() || myStack.Size() < 2)
- throw "Stack is empty, can not perform [" + strTok + "]";
- objOp1 = null;
- objOp2 = null;
- objTmp1 = null;
- objTmp2 = null;
- objOp2 = myStack.Pop();
- objOp1 = myStack.Pop();
- if (IsVariable(objOp1))
- objOp1 = getVariable(objOp1);
- if (IsVariable(objOp2))
- objOp2 = getVariable(objOp2);
- if (IsBoolean(objOp1) && IsBoolean(objOp2))
- {
- objTmp1 = ToBoolean(objOp1);
- objTmp2 = ToBoolean(objOp2);
- if (strTok == "&")
- myStack.Push((objTmp1 && objTmp2));
- else if (strTok == "|")
- myStack.Push((objTmp1 || objTmp2));
- }
- else
- throw "Logical operator requires LHS & RHS of boolean type!";
- break;
- default :
- // Handle functions and operands
- if (IsNumber(strTok) || IsBoolean(strTok) ||
- isDate(strTok, dtFormat) || typeof(strTok) == "number"
- || typeof(strTok) == "boolean" || typeof(strTok) == "object"
- || IsVariable(strTok))
- {
- myStack.Push(strTok);
- break;
- }
- else
- HandleFunctions(strTok, myStack, dtFormat, arrVars);
- }
- intIndex++;
- }
- if (myStack.IsEmpty() || myStack.Size() > 1)
- throw "Unable to evaluate expression!";
- else
- return myStack.Pop();
- }
- /*------------------------------------------------------------------------------
- * NAME : InFixToPostFix
- * PURPOSE : Convert an Infix expression into a postfix (RPN) equivalent
- * PARAMETERS : Infix expression element array
- * RETURNS : array containing postfix expression element tokens
- *----------------------------------------------------------------------------*/
- function InFixToPostFix(arrToks)
- {
- var myStack;
- var intCntr, intIndex;
- var strTok, strTop, strNext, strPrev;
- var blnStart;
- blnStart = false;
- intIndex = 0;
- arrPFix = new Array();
- myStack = new Stack();
- // Infix to postfix converter
- for (intCntr = 0; intCntr < arrToks.length; intCntr++)
- {
- strTok = arrToks[intCntr];
- debugAssert ("Processing token [" + strTok + "]");
- switch (strTok)
- {
- case "(" :
- if (myStack.Size() > 0 && IsFunction(myStack.Get(0)))
- {
- arrPFix[intIndex] = ARG_TERMINAL;
- intIndex++;
- }
- myStack.Push(strTok);
- break;
- case ")" :
- blnStart = true;
- debugAssert("Stack.Pop [" + myStack.toString());
- while (!myStack.IsEmpty())
- {
- strTok = myStack.Pop();
- if (strTok != "(")
- {
- arrPFix[intIndex] = strTok;
- intIndex++;
- }
- else
- {
- blnStart = false;
- break;
- }
- }
- if (myStack.IsEmpty() && blnStart)
- throw "Unbalanced parenthesis!";
- break;
- case "," :
- if (myStack.IsEmpty()) break;
- debugAssert("Pop stack till opening bracket found!")
- while (!myStack.IsEmpty())
- {
- strTok = myStack.Get(0);
- if (strTok == "(") break;
- arrPFix[intIndex] = myStack.Pop();
- intIndex++;
- }
- break;
- case "!" :
- case "-" :
- // check for unary negative operator.
- if (strTok == "-")
- {
- strPrev = null;
- if (intCntr > 0)
- strPrev = arrToks[intCntr - 1];
- strNext = arrToks[intCntr + 1];
- if (strPrev == null || IsOperator(strPrev) || strPrev == "(")
- {
- debugAssert("Unary negation!")
- strTok = UNARY_NEG;
- }
- }
- case "^" :
- case "*" :
- case "/" :
- case "%" :
- case "+" :
- // check for unary + addition operator, we need to ignore this.
- if (strTok == "+")
- {
- strPrev = null;
- if (intCntr > 0)
- strPrev = arrToks[intCntr - 1];
- strNext = arrToks[intCntr + 1];
- if (strPrev == null || IsOperator(strPrev) || strPrev == "(")
- {
- debugAssert("Unary add, Skipping");
- break;
- }
- }
- case "&" :
- case "|" :
- case ">" :
- case "<" :
- case "=" :
- case ">=" :
- case "<=" :
- case "<>" :
- strTop = "";
- if (!myStack.IsEmpty()) strTop = myStack.Get(0);
- if (myStack.IsEmpty() || (!myStack.IsEmpty() && strTop == "("))
- {
- debugAssert("Empty stack pushing operator [" + strTok + "]");
- myStack.Push(strTok);
- }
- else if (Precedence(strTok) > Precedence(strTop))
- {
- debugAssert("[" + strTok +
- "] has higher precedence over [" +
- strTop + "]");
- myStack.Push(strTok);
- }
- else
- {
- // Pop operators with precedence >= operator strTok
- while (!myStack.IsEmpty())
- {
- strTop = myStack.Get(0);
- if (strTop == "(" || Precedence(strTop) < Precedence(strTok))
- {
- debugAssert ("[" + strTop +
- "] has lesser precedence over [" +
- strTok + "]")
- break;
- }
- else
- {
- arrPFix[intIndex] = myStack.Pop();
- intIndex++;
- }
- }
- myStack.Push(strTok);
- }
- break;
- default :
- if (!IsFunction(strTok))
- {
- debugAssert("Token [" + strTok + "] is a variable/number!");
- // Token is an operand
- if (IsNumber(strTok))
- strTok = ToNumber(strTok);
- else if (IsBoolean(strTok))
- strTok = ToBoolean(strTok);
- else if (isDate(strTok, dtFormat))
- strTok = getDateFromFormat(strTok, dtFormat);
- arrPFix[intIndex] = strTok;
- intIndex++;
- break;
- }
- else
- {
- strTop = "";
- if (!myStack.IsEmpty()) strTop = myStack.Get(0);
- if (myStack.IsEmpty() || (!myStack.IsEmpty() && strTop == "("))
- {
- debugAssert("Empty stack pushing operator [" + strTok + "]");
- myStack.Push(strTok);
- }
- else if (Precedence(strTok) > Precedence(strTop))
- {
- debugAssert("[" + strTok +
- "] has higher precedence over [" +
- strTop + "]");
- myStack.Push(strTok);
- }
- else
- {
- // Pop operators with precedence >= operator in strTok
- while (!myStack.IsEmpty())
- {
- strTop = myStack.Get(0);
- if (strTop == "(" || Precedence(strTop) < Precedence(strTok))
- {
- debugAssert ("[" + strTop +
- "] has lesser precedence over [" +
- strTok + "]")
- break;
- }
- else
- {
- arrPFix[intIndex] = myStack.Pop();
- intIndex++;
- }
- }
- myStack.Push(strTok);
- }
- }
- break;
- }
- debugAssert("Stack : " + myStack.toString() + "\n" +
- "RPN Exp : " + arrPFix.toString());
- }
- // Pop remaining operators from stack.
- while (!myStack.IsEmpty())
- {
- arrPFix[intIndex] = myStack.Pop();
- intIndex++;
- }
- return arrPFix;
- }
- }
- /*------------------------------------------------------------------------------
- * NAME : HandleFunctions
- * PURPOSE : Execute built-in functions
- * PARAMETERS : pstrTok - The current function name
- * pStack - Operand stack
- * RETURNS : Nothing, the result is pushed back onto the stack.
- *----------------------------------------------------------------------------*/
- function HandleFunctions(pstrTok, pStack, pdtFormat, parrVars)
- {
- var varTmp, varTerm, objTmp;
- var objOp1, objOp2;
- var arrArgs;
- var intCntr;
- if (!IsFunction(pstrTok))
- throw "Unsupported function token [" + pstrTok + "]";
- varTmp = pstrTok.toUpperCase();
- arrArgs = new Array();
- while (!pStack.IsEmpty())
- {
- varTerm = ARG_TERMINAL;
- varTerm = pStack.Pop();
- if (varTerm != ARG_TERMINAL)
- arrArgs[arrArgs.length] = varTerm;
- else
- break;
- }
- switch (varTmp)
- {
- case "DATE" :
- varTerm = new Date();
- pStack.Push(formatDate(varTerm, pdtFormat));
- break;
- case "ACOS" :
- case "ASIN" :
- case "ATAN" :
- throw "Function [" + varTmp + "] is not implemented!";
- break;
- case "ABS" :
- case "CHR" :
- case "COS" :
- case "FIX" :
- case "HEX" :
- case "LOG" :
- case "ROUND" :
- case "SIN" :
- case "SQRT" :
- case "TAN" :
- if (arrArgs.length < 1)
- throw varTmp + " requires atleast one argument!";
- else if (arrArgs.length > 1)
- throw varTmp + " requires only one argument!";
- varTerm = arrArgs[0];
- if (IsVariable(varTerm))
- {
- objTmp = parrVars[varTerm];
- if (objTmp == undefined || objTmp == null)
- throw "Variable [" + varTerm + "] not defined";
- else
- varTerm = objTmp;
- }
- if (!IsNumber(varTerm))
- throw varTmp + " operates on numeric operands only!";
- else
- {
- objTmp = ToNumber(varTerm);
- if (varTmp == "ABS")
- pStack.Push(Math.abs(objTmp));
- else if (varTmp == "CHR")
- pStack.Push(String.fromCharCode(objTmp));
- else if (varTmp == "COS")
- pStack.Push(Math.cos(objTmp));
- else if (varTmp == "FIX")
- pStack.Push(Math.floor(objTmp));
- else if (varTmp == "HEX")
- pStack.Push(objTmp.toString(16));
- else if (varTmp == "LOG")
- pStack.Push(Math.log(objTmp));
- else if (varTmp == "ROUND")
- pStack.Push(Math.round(objTmp));
- else if (varTmp == "SIN")
- pStack.Push(Math.sin(objTmp));
- else if (varTmp == "SQRT")
- pStack.Push(Math.sqrt(objTmp));
- else if (varTmp == "TAN")
- pStack.Push(Math.tan(objTmp));
- }
- break;
- case "ASC" :
- if (arrArgs.length > 1)
- throw varTmp + " requires only one argument!";
- else if (arrArgs.length < 1)
- throw varTmp + " requires atleast one argument!";
- varTerm = arrArgs[0];
- if (IsVariable(varTerm))
- {
- objTmp = parrVars[varTerm];
- if (objTmp == undefined || objTmp == null)
- throw "Variable [" + varTerm + "] not defined";
- else
- varTerm = objTmp;
- }
- if (IsNumber(varTerm) || IsBoolean(varTerm) ||
- isDate(varTerm, pdtFormat) || typeof(varTerm) != "string")
- throw varTmp + " requires a string type operand!";
- else
- pStack.Push(varTerm.charCodeAt(0));
- break;
- case "LCASE" :
- case "UCASE" :
- case "CDATE" :
- if (arrArgs.length < 1)
- throw varTmp + " requires atleast one argument!";
- else if (arrArgs.length > 1)
- throw varTmp + " requires only one argument!";
- varTerm = arrArgs[0];
- if (IsVariable(varTerm))
- {
- objTmp = parrVars[varTerm];
- if (objTmp == undefined || objTmp == null)
- throw "Variable [" + varTerm + "] not defined";
- else
- varTerm = objTmp;
- }
- if (varTmp == "CDATE" && !isDate(varTerm, pdtFormat))
- throw "CDate can not convert [" + varTerm + "] to a valid date!";
- else if (typeof(varTerm) == "number" || typeof(varTerm) != "string")
- throw varTmp + " requires a string type operand!";
- else
- {
- if (varTmp == "LCASE")
- pStack.Push(varTerm.toLowerCase());
- else if (varTmp == "UCASE")
- pStack.Push(varTerm.toUpperCase());
- else if (varTmp == "CDATE")
- {
- objTmp = getDateFromFormat(varTerm, pdtFormat);
- pStack.Push(new Date(objTmp));
- }
- }
- break;
- case "LEFT" :
- case "RIGHT" :
- if (arrArgs.length < 2)
- throw varTmp + " requires atleast two arguments!";
- else if (arrArgs.length > 2)
- throw varTmp + " requires only two arguments!";
- for (intCntr = 0; intCntr < arrArgs.length; intCntr++)
- {
- varTerm = arrArgs[intCntr];
- if (IsVariable(varTerm))
- {
- objTmp = parrVars[varTerm];
- if (objTmp == undefined || objTmp == null)
- throw "Variable [" + varTerm + "] not defined";
- else
- varTerm = objTmp;
- }
- if (intCntr == 0 && !IsNumber(varTerm))
- throw varTmp + " oprator requires numaric length!";
- arrArgs[intCntr] = varTerm;
- }
- varTerm = new String(arrArgs[1]);
- objTmp = ToNumber(arrArgs[0]);
- if (varTmp == "LEFT")
- pStack.Push(varTmp.substring(0, objTmp));
- else
- pStack.Push(varTmp.substr((varTerm.length - objTmp), objTmp));
- break;
- case "MID" :
- case "IIF" :
- if (arrArgs.length < 3)
- throw varTmp + " requires atleast three arguments!";
- else if (arrArgs.length > 3)
- throw varTmp + " requires only three arguments!";
- for (intCntr = 0; intCntr < arrArgs.length; intCntr++)
- {
- varTerm = arrArgs[intCntr];
- if (IsVariable(varTerm))
- {
- objTmp = parrVars[varTerm];
- if (objTmp == undefined || objTmp == null)
- throw "Variable [" + varTerm + "] not defined";
- else
- varTerm = objTmp;
- }
- if (varTerm == "MID" && intCntr <= 1 && !IsNumber(varTerm))
- throw varTmp + " oprator requires numaric lengths!";
- else if (varTerm == "IIF" && intCntr == 2 && !IsBoolean(varTerm))
- throw varTmp + " oprator requires boolean condition!";
- arrArgs[intCntr] = varTerm;
- }
- if (varTmp == "MID")
- {
- varTerm = new String(arrArgs[2]);
- objOp1 = ToNumber(arrArgs[1]);
- objOp2 = ToNumber(arrArgs[0]);
- pStack.Push(varTerm.substring(objOp1, objOp2));
- }
- else
- {
- varTerm = ToBoolean(arrArgs[2]);
- objOp1 = arrArgs[1];
- objOp2 = arrArgs[0];
- if (varTerm)
- pStack.Push(objOp1);
- else
- pStack.Push(objOp2);
- }
- break;
- case "AVG" :
- case "MAX" :
- case "MIN" :
- if (arrArgs.length < 2)
- throw varTmp + " requires atleast two operands!";
- objTmp = 0;
- for (intCntr = 0; intCntr < arrArgs.length; intCntr++)
- {
- varTerm = arrArgs[intCntr];
- if (IsVariable(varTerm))
- {
- objTmp = parrVars[varTerm];
- if (objTmp == undefined || objTmp == null)
- throw "Variable [" + varTerm + "] not defined";
- else
- varTerm = objTmp;
- }
- if (!IsNumber(varTerm))
- throw varTmp + " requires numaric operands only!";
- varTerm = ToNumber(varTerm);
- if (varTmp == "AVG")
- objTmp += varTerm;
- else if (varTmp == "MAX" && objTmp < varTerm)
- objTmp = varTerm;
- else if (varTmp == "MIN")
- {
- if (intCntr == 1)
- objTmp = varTerm;
- else if (objTmp > varTerm)
- objTmp = varTerm;
- }
- }
- if (varTmp == "AVG")
- pStack.Push(objTmp/arrArgs.length);
- else
- pStack.Push(objTmp);
- break;
- }
- }
- /*------------------------------------------------------------------------------
- * NAME : IsNumber
- * PURPOSE : Checks whether the specified parameter is a number.
- * RETURNS : True - If supplied parameter can be succesfully converted to a number
- * False - Otherwise
- *----------------------------------------------------------------------------*/
- function IsNumber(pstrVal)
- {
- var dblNo = Number.NaN;
- dblNo = new Number(pstrVal);
- if (isNaN(dblNo))
- return false;
- return true;
- }
- /*------------------------------------------------------------------------------
- * NAME : IsBoolean
- * PURPOSE : Checks whether the specified parameter is a boolean value.
- * PARAMETERS : pstrVal - The string to be checked.
- * RETURNS : True - If supplied parameter is a boolean constant
- * False - Otherwise
- *----------------------------------------------------------------------------*/
- function IsBoolean(pstrVal)
- {
- var varType = typeof(pstrVal);
- var strTmp = null;
- if (varType == "boolean") return true;
- if (varType == "number" || varType == "function" || varType == undefined)
- return false;
- if (IsNumber(pstrVal)) return false;
- if (varType == "object")
- {
- strTmp = pstrVal.toString();
- if (strTmp.toUpperCase() == "TRUE" || strTmp.toUpperCase() == "FALSE")
- return true;
- }
- if (pstrVal.toUpperCase() == "TRUE" || pstrVal.toUpperCase() == "FALSE")
- return true;
- return false;
- }
- /*------------------------------------------------------------------------------
- * NAME : IsVariable
- * PURPOSE : Checks whether the specified parameter is a user defined variable.
- * RETURNS : True - If supplied parameter identifies a user defined variable
- * False - Otherwise
- *----------------------------------------------------------------------------*/
- function IsVariable(pstrVal)
- {
- if (lstArithOps.indexOf(pstrVal) >= 0 || lstLogicOps.indexOf(pstrVal) >=0 ||
- lstCompaOps.indexOf(pstrVal) >= 0 ||
- (typeof(pstrVal) == "string" && (pstrVal.toUpperCase() == "TRUE" ||
- pstrVal.toUpperCase() == "FALSE" || parseDate(pstrVal) != null)) ||
- typeof(pstrVal) == "number" || typeof(pstrVal) == "boolean" ||
- typeof(pstrVal) == "object" || IsNumber(pstrVal) || IsFunction(pstrVal))
- return false;
- return true;
- }
- /*------------------------------------------------------------------------------
- * NAME : ToNumber
- * PURPOSE : Converts the supplied parameter to numaric type.
- * PARAMETERS : pobjVal - The string to be converted to equvalent number.
- * RETURNS : numaric value if string represents a number
- * THROWS : Exception if string can not be converted
- *----------------------------------------------------------------------------*/
- function ToNumber(pobjVal)
- {
- var dblRet = Number.NaN;
- if (typeof(pobjVal) == "number")
- return pobjVal;
- else
- {
- dblRet = new Number(pobjVal);
- return dblRet.valueOf();
- }
- }
- /*------------------------------------------------------------------------------
- * NAME : ToBoolean
- * PURPOSE : Converts the supplied parameter to boolean value
- * PARAMETERS : pobjVal - The parameter to be converted.
- * RETURNS : Boolean value
- *----------------------------------------------------------------------------*/
- function ToBoolean(pobjVal)
- {
- var dblNo = Number.NaN;
- var strTmp = null;
- if (pobjVal == null || pobjVal == undefined)
- throw "Boolean value is not defined!";
- else if (typeof(pobjVal) == "boolean")
- return pobjVal;
- else if (typeof(pobjVal) == "number")
- return (pobjval > 0);
- else if (IsNumber(pobjVal))
- {
- dblNo = ToNumber(pobjVal);
- if (isNaN(dblNo))
- return null;
- else
- return (dblNo > 0);
- }
- else if (typeof(pobjVal) == "object")
- {
- strTmp = pobjVal.toString();
- if (strTmp.toUpperCase() == "TRUE")
- return true;
- else if (strTmp.toUpperCase() == "FALSE")
- return false;
- else
- return null;
- }
- else if (typeof(pobjVal) == "string")
- {
- if (pobjVal.toUpperCase() == "TRUE")
- return true;
- else if (pobjVal.toUpperCase() == "FALSE")
- return false;
- else
- return null;
- }
- else
- return null;
- }
- /*------------------------------------------------------------------------------
- * NAME : Precedence
- * PURPOSE : Returns the precedence of a given operator
- * PARAMETERS : pstrTok - The operator token whose precedence is to be returned.
- * RETURNS : Integer
- *----------------------------------------------------------------------------*/
- function Precedence(pstrTok)
- {
- var intRet = 0;
- switch (pstrTok)
- {
- case "+" :
- case "-" :
- intRet = 5;
- break;
- case "*" :
- case "/" :
- case "%" :
- intRet = 6;
- break;
- case "^" :
- intRet = 7;
- break;
- case UNARY_NEG :
- case "!" :
- intRet = 10;
- break;
- case "(" :
- intRet = 99;
- break;
- case "&" :
- case "|" :
- intRet = 3;
- break;
- case ">" :
- case ">=" :
- case "<" :
- case "<=" :
- case "=" :
- case "<>" :
- intRet = 4;
- break;
- default :
- if (IsFunction(pstrTok))
- intRet = 9;
- else
- intRet = 0;
- break;
- }
- debugAssert ("Precedence of " + pstrTok + " is " + intRet);
- return intRet;
- }
- /*------------------------------------------------------------------------------
- * NAME : debugAssert
- * PURPOSE : Shows a messagebox displaying supplied message
- * PARAMETERS : pObject - The object whose string representation is to be displayed.
- * RETURNS : Nothing
- *----------------------------------------------------------------------------*/
- function debugAssert(pObject)
- {
- if (DEBUG_ON)
- alert (pObject.toString())
- }
|