You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kvirc/src/kvirc/kvs/kvi_kvs_parser_dollar.cpp

332 lines
9.1 KiB

//=============================================================================
//
// 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
// <namespace>::{<namespace>::}<alias_name>
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 '...<namespace>::<alias_name>' ?"));
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 "<namespace>::<namespace>::..::<classname>
// 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;
}