//============================================================================= // // File : kvi_kvs_parser_dollar.cpp // Creation date : Thu 5 Oct 2003 20.20 CEST by Szymon Stefanek // // This file is part of the KVirc irc client distribution // Copyright (C) 2003 Szymon Stefanek (pragma at kvirc dot net) // // 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 2 // of the License, or (at your opinion) 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, write to the Free Software Foundation, // Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //============================================================================= #define __KVIRC__ #include "kvi_kvs_parser.h" #include "kvi_kvs_treenode.h" #include "kvi_kvs_report.h" #include "kvi_kvs_kernel.h" #include "kvi_kvs_parser_macros.h" #include "kvi_locale.h" KviKvsTreeNodeData * KviKvsParser::parseDollar(bool bInObjScope) { KVSP_ASSERT(KVSP_curCharUnicode == '$'); const TQChar * pDollarBegin = KVSP_curCharPointer; const TQChar * pBegin = KVSP_curCharPointer; KVSP_skipChar; if(!KVSP_curCharIsFunctionStart) { if(KVSP_curCharUnicode == 0)warning(KVSP_curCharPointer,__tr2qs("Unexpected end of script after '$' function call prefix")); else warning(KVSP_curCharPointer,__tr2qs("Unexpected character %q (unicode %x) after '$' function call prefix"),KVSP_curCharPointer,KVSP_curCharUnicode); error(KVSP_curCharPointer,__tr2qs("Syntax error after '$' function call prefix. If you want to use a plain '$' in the code you need to escape it")); return 0; } if(KVSP_curCharUnicode == '(') { // expression eval if(bInObjScope) { error(KVSP_curCharPointer,__tr2qs("Invalid expression evaluation in object scope")); return 0; } KVSP_skipChar; skipSpaces(); return parseExpression(')'); } if(KVSP_curCharUnicode == '{') { // command block eval <--- senseless ??? if(bInObjScope) { error(KVSP_curCharPointer,__tr2qs("Invalid command evaluation in object scope")); return 0; } KviKvsTreeNodeInstruction * i = parseInstructionBlock(); if(!i) { if(error())return 0; // trigger an error anyway: this is abused syntax :D error(KVSP_curCharPointer,__tr2qs("Empty instruction block for command evaluation")); return 0; } return new KviKvsTreeNodeCommandEvaluation(pDollarBegin,i); } if(KVSP_curCharIsNumber) { // this is a parameter identifier // $1-4 $1- $3 if(bInObjScope) { error(KVSP_curCharPointer,__tr2qs("Parameter identifiers are forbidden in object scope (after the '->' operator)")); return 0; } pBegin = KVSP_curCharPointer; while(KVSP_curCharIsNumber) KVSP_skipChar; TQString szNum1(pBegin,KVSP_curCharPointer - pBegin); bool bOk; int iNum1 = szNum1.toInt(&bOk); if(!bOk)tqDebug("Ops... a non-number made by numbers ?"); if(KVSP_curCharUnicode != '-') { // end return new KviKvsTreeNodeSingleParameterIdentifier(pDollarBegin,iNum1); } // dash... make sure it's not $N->$something KVSP_skipChar; if(KVSP_curCharUnicode == '>') { // object scope operator in fact... // go back to the - and return a single parameter identifier KVSP_backChar; return new KviKvsTreeNodeSingleParameterIdentifier(pDollarBegin,iNum1); } if(!KVSP_curCharIsNumber) { // from iNum1 to the end return new KviKvsTreeNodeMultipleParameterIdentifier(pDollarBegin,iNum1,-1); } pBegin = KVSP_curCharPointer; while(KVSP_curCharIsNumber) KVSP_skipChar; TQString szNum2(pBegin,KVSP_curCharPointer - pBegin); int iNum2 = szNum2.toInt(&bOk); if(!bOk)tqDebug("Ops... a non-number made by numbers (2) ?"); if(iNum1 < iNum2)return new KviKvsTreeNodeMultipleParameterIdentifier(pDollarBegin,iNum1,iNum2); else { warning(pBegin,__tr2qs("Ending index of a multiple parameter identifier is lower or equal to the starting index. This will evaluate to a single parameter identifier.")); return new KviKvsTreeNodeSingleParameterIdentifier(pDollarBegin,iNum1); } } pBegin = KVSP_curCharPointer; //KVSP_skipChar; bool bHasNamespaceNotInObjScopeSoMustBeAlias = false; // ;D bool bIsThis = false; if(KVSP_curCharUnicode == '$') { if(bInObjScope) { error(KVSP_curCharPointer,__tr2qs("Syntax error: invalid $$ ($this) function call in object scope")); return 0; } // handle $$ KVSP_skipChar; } else { while((KVSP_curCharIsLetterOrNumber) || (KVSP_curCharUnicode == '_'))KVSP_skipChar; if(!bInObjScope) { while(KVSP_curCharUnicode == ':') { // check for namespaces // here we allow the syntax of the form // ::{::} bHasNamespaceNotInObjScopeSoMustBeAlias = true; // ;D KVSP_skipChar; if(KVSP_curCharUnicode == ':') { KVSP_skipChar; if(!KVSP_curCharIsLetter) { warning(KVSP_curCharPointer - 1,__tr2qs("Stray '::' sequence or invalid following alias name")); error(KVSP_curCharPointer,__tr2qs("Syntax error: malformed alias function call identifier")); return 0; } KVSP_skipChar; while(KVSP_curCharIsLetterOrNumber || (KVSP_curCharUnicode == '_'))KVSP_skipChar; } else { warning(KVSP_curCharPointer - 1,__tr2qs("Stray ':' character: did you mean '...::' ?")); error(KVSP_curCharPointer,__tr2qs("Syntax error: malformed (alias?) function call identifier")); return 0; } } } } TQString szIdentifier1(pBegin,KVSP_curCharPointer - pBegin); const TQChar * pId2 = 0; int iId2Len = 0; bool bModuleFunctionCall = false; if(!bHasNamespaceNotInObjScopeSoMustBeAlias) { if(!bInObjScope) { if(KVSP_curCharUnicode == '.') { KVSP_skipChar; if(KVSP_curCharIsLetter) { pId2 = KVSP_curCharPointer; while((KVSP_curCharIsLetterOrNumber) || (KVSP_curCharUnicode == '_')) KVSP_skipChar; iId2Len = KVSP_curCharPointer - pId2; bModuleFunctionCall = true; } else { KVSP_backChar; } } } else { // object scope, check for "class name" namespace // the class name namespace has the format "::::..:: // so the last :: is the delimiter of the function name const TQChar * pOriginalEndOfId1 = KVSP_curCharPointer; const TQChar * pEndOfId1 = pOriginalEndOfId1; while(KVSP_curCharUnicode == ':') { const TQChar * pEndOfId1 = KVSP_curCharPointer; // base class function call ? KVSP_skipChar; if(KVSP_curCharUnicode == ':') { KVSP_skipChar; if(KVSP_curCharIsLetter) { pId2 = KVSP_curCharPointer; while((KVSP_curCharIsLetterOrNumber) || (KVSP_curCharUnicode == '_')) KVSP_skipChar; iId2Len = KVSP_curCharPointer - pId2; } else { KVSP_setCurCharPointer(pOriginalEndOfId1); pId2 = 0; iId2Len = 0; break; } } else { KVSP_setCurCharPointer(pOriginalEndOfId1); pId2 = 0; iId2Len = 0; break; } } if(pId2) { // yes, that's fine: reset it szIdentifier1.setUnicode(pBegin,pEndOfId1 - pBegin); } } } KviKvsTreeNodeDataList * l; if(KVSP_curCharUnicode != '(') { // no parameters passed //KVSP_setCurCharPointer(pBegin); // will get an empty data list l = new KviKvsTreeNodeDataList(pDollarBegin); } else { // check for the special syntax () KVSP_skipChar; if(KVSP_curCharUnicode == ')') { // $call(), assume no parameters passed l = new KviKvsTreeNodeDataList(pDollarBegin); KVSP_skipChar; } else { KVSP_backChar; l = parseCommaSeparatedParameterList(); if(!l)return 0; // error } } if(bHasNamespaceNotInObjScopeSoMustBeAlias) { // namespace::alias function call return new KviKvsTreeNodeAliasFunctionCall(pDollarBegin,szIdentifier1,l); } else if(bModuleFunctionCall) { // module function call return new KviKvsTreeNodeModuleFunctionCall(pDollarBegin,szIdentifier1,TQString(pId2,iId2Len),l); } else { if(bInObjScope) { // object function call (our parent will be a scope operator) if(pId2) { // base class object function call return new KviKvsTreeNodeBaseObjectFunctionCall(pDollarBegin,szIdentifier1,TQString(pId2,iId2Len),l); } else { // plain object function call return new KviKvsTreeNodeThisObjectFunctionCall(pDollarBegin,szIdentifier1,l); } } else { // core or alias function call KviKvsCoreFunctionExecRoutine * r = KviKvsKernel::instance()->findCoreFunctionExecRoutine(szIdentifier1); if(r) { // core function call return new KviKvsTreeNodeCoreFunctionCall(pDollarBegin,szIdentifier1,r,l); } else { // root namespace alias function call return new KviKvsTreeNodeAliasFunctionCall(pDollarBegin,szIdentifier1,l); } } } // not reached KVSP_ASSERT(false); return 0; }