//=============================================================================
//
// 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 ;
}