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.
332 lines
9.1 KiB
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)debug("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)debug("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;
|
|
}
|