2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
* Copyright ( c ) 2009 - 2013 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
// executes script functions
# include <C4Include.h>
# include <C4Aul.h>
2010-03-05 21:25:37 +00:00
# include <C4AulExec.h>
2009-04-21 21:44:56 +00:00
# include <C4AulDebug.h>
2009-05-08 13:28:41 +00:00
# include <C4Object.h>
# include <C4Config.h>
2009-06-12 18:52:21 +00:00
# include <C4Game.h>
# include <C4Log.h>
2009-08-25 15:50:51 +00:00
# include <C4Record.h>
2009-10-25 23:09:34 +00:00
# include <algorithm>
2009-05-08 13:28:41 +00:00
2010-01-14 22:31:38 +00:00
C4AulExec AulExec ;
2012-05-15 01:11:23 +00:00
C4AulExecError : : C4AulExecError ( const char * szError )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// direct error message string
2010-09-07 22:46:01 +00:00
sMessage . Format ( " ERROR: %s. " , szError ? szError : " (no error message) " ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-01-13 17:07:58 +00:00
StdStrBuf C4AulScriptContext : : ReturnDump ( StdStrBuf Dump )
2010-03-28 18:58:01 +00:00
{
2010-01-13 17:42:15 +00:00
if ( ! Func )
return StdStrBuf ( " " ) ;
2012-05-15 01:51:20 +00:00
// Context
if ( Obj & & Obj - > Status )
{
C4Value ObjVal ( Obj ) ;
Dump . Append ( ObjVal . GetDataString ( 0 ) ) ;
Dump . Append ( " -> " ) ;
}
2011-10-13 22:40:55 +00:00
bool fDirectExec = ! Func - > GetName ( ) ;
2010-03-28 18:58:01 +00:00
if ( ! fDirectExec )
{
2009-05-08 13:28:41 +00:00
// Function name
2011-10-13 22:40:55 +00:00
Dump . Append ( Func - > GetName ( ) ) ;
2009-05-08 13:28:41 +00:00
// Parameters
Dump . AppendChar ( ' ( ' ) ;
int iNullPars = 0 ;
2010-03-28 18:58:01 +00:00
for ( int i = 0 ; i < Func - > GetParCount ( ) ; i + + )
if ( Pars + i < Vars )
{
if ( ! Pars [ i ] )
2009-05-08 13:28:41 +00:00
iNullPars + + ;
else
2010-03-28 18:58:01 +00:00
{
if ( i > iNullPars )
2009-05-08 13:28:41 +00:00
Dump . AppendChar ( ' , ' ) ;
// Insert missing null parameters
2010-03-28 18:58:01 +00:00
while ( iNullPars > 0 )
{
2009-05-08 13:28:41 +00:00
Dump . Append ( " 0, " ) ;
iNullPars - - ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Insert parameter
Dump . Append ( Pars [ i ] . GetDataString ( ) ) ;
2010-01-25 04:00:59 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
Dump . AppendChar ( ' ) ' ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
Dump . Append ( Func - > Owner - > ScriptName ) ;
// Script
2010-10-25 21:48:08 +00:00
if ( ! fDirectExec & & Func - > pOrgScript )
2009-05-08 13:28:41 +00:00
Dump . AppendFormat ( " (%s:%d) " ,
2010-03-28 18:58:01 +00:00
Func - > pOrgScript - > ScriptName . getData ( ) ,
2010-12-22 01:10:58 +00:00
CPos ? Func - > GetLineOfCode ( CPos ) : SGetLine ( Func - > pOrgScript - > GetScript ( ) , Func - > Script ) ) ;
2010-01-13 18:20:42 +00:00
// Return it
2009-04-21 21:44:56 +00:00
return Dump ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-04-21 21:44:56 +00:00
void C4AulScriptContext : : dump ( StdStrBuf Dump )
{
2010-01-13 18:20:42 +00:00
// Log it
DebugLog ( ReturnDump ( Dump ) . getData ( ) ) ;
2009-04-21 21:44:56 +00:00
}
2009-05-08 13:28:41 +00:00
2011-02-23 20:06:14 +00:00
void C4AulExec : : LogCallStack ( )
{
for ( C4AulScriptContext * pCtx = pCurCtx ; pCtx > = Contexts ; pCtx - - )
pCtx - > dump ( StdStrBuf ( " by: " ) ) ;
}
2012-05-15 01:03:47 +00:00
C4String * C4AulExec : : FnTranslate ( C4PropList * _this , C4String * text )
2012-04-28 19:32:29 +00:00
{
if ( ! text | | text - > GetData ( ) . isNull ( ) ) return NULL ;
// Find correct script: translations of the context if possible, containing script as fallback
C4AulScript * script = NULL ;
2012-05-15 01:03:47 +00:00
if ( _this & & _this - > GetDef ( ) )
script = & ( _this - > GetDef ( ) - > Script ) ;
2012-04-28 19:32:29 +00:00
else
script = AulExec . pCurCtx [ - 1 ] . Func - > pOrgScript ;
2012-10-27 21:53:42 +00:00
if ( ! script ) return NULL ;
2012-04-28 19:32:29 +00:00
try
{
return : : Strings . RegString ( script - > Translate ( text - > GetCStr ( ) ) . c_str ( ) ) ;
}
catch ( C4LangStringTable : : NoSuchTranslation & )
{
DebugLogF ( " WARNING: Translate: no translation for string \" %s \" " , text - > GetCStr ( ) ) ;
// Trace
AulExec . LogCallStack ( ) ;
return text ;
}
}
2014-01-04 13:22:41 +00:00
bool C4AulExec : : FnLogCallStack ( C4PropList * _this )
{
AulExec . LogCallStack ( ) ;
return true ;
}
2012-04-13 18:28:30 +00:00
void C4AulExec : : ClearPointers ( C4Object * obj )
{
2012-04-29 14:53:29 +00:00
#if 0
// FIXME: reactivate this code and remove the checks from Call once scripts are fixed
2012-04-13 18:28:30 +00:00
for ( C4AulScriptContext * pCtx = pCurCtx ; pCtx > = Contexts ; pCtx - - )
{
if ( pCtx - > Obj = = obj )
pCtx - > Obj = NULL ;
}
2012-04-29 14:53:29 +00:00
# endif
2012-04-13 18:28:30 +00:00
}
2012-10-27 21:53:42 +00:00
C4Value C4AulExec : : Exec ( C4AulScriptFunc * pSFunc , C4PropList * p , C4Value * pnPars , bool fPassErrors )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Push parameters
C4Value * pPars = pCurVal + 1 ;
2010-03-28 18:58:01 +00:00
if ( pnPars )
for ( int i = 0 ; i < C4AUL_MAX_Par ; i + + )
2009-05-08 13:28:41 +00:00
PushValue ( pnPars [ i ] ) ;
2011-04-17 23:48:37 +00:00
if ( pCurVal + 1 - pPars > pSFunc - > GetParCount ( ) )
PopValues ( pCurVal + 1 - pPars - pSFunc - > GetParCount ( ) ) ;
else
PushNullVals ( pSFunc - > GetParCount ( ) - ( pCurVal + 1 - pPars ) ) ;
2009-05-08 13:28:41 +00:00
// Push a new context
C4AulScriptContext ctx ;
2010-01-25 04:00:59 +00:00
ctx . tTime = 0 ;
2012-06-03 22:03:49 +00:00
ctx . Obj = p ;
2009-05-08 13:28:41 +00:00
ctx . Return = NULL ;
ctx . Pars = pPars ;
2011-04-17 21:52:55 +00:00
ctx . Vars = pCurVal + 1 ;
2009-05-08 13:28:41 +00:00
ctx . Func = pSFunc ;
ctx . CPos = NULL ;
PushContext ( ctx ) ;
// Execute
2010-12-22 01:10:58 +00:00
return Exec ( pSFunc - > GetCode ( ) , fPassErrors ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4Value C4AulExec : : Exec ( C4AulBCC * pCPos , bool fPassErrors )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Save start context
C4AulScriptContext * pOldCtx = pCurCtx ;
try
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
for ( ; ; )
{
2009-05-08 13:28:41 +00:00
bool fJump = false ;
2010-03-28 18:58:01 +00:00
switch ( pCPos - > bccType )
{
case AB_INT :
2011-04-10 00:00:27 +00:00
PushInt ( pCPos - > Par . i ) ;
2010-03-28 18:58:01 +00:00
break ;
case AB_BOOL :
2011-04-10 00:00:27 +00:00
PushBool ( ! ! pCPos - > Par . i ) ;
2010-03-28 18:58:01 +00:00
break ;
case AB_STRING :
PushString ( pCPos - > Par . s ) ;
break ;
2010-09-09 00:18:19 +00:00
case AB_CPROPLIST :
PushPropList ( pCPos - > Par . p ) ;
break ;
case AB_CARRAY :
PushArray ( pCPos - > Par . a ) ;
2010-03-28 18:58:01 +00:00
break ;
2011-09-24 23:20:18 +00:00
case AB_CFUNCTION :
PushFunction ( pCPos - > Par . f ) ;
break ;
2010-03-28 18:58:01 +00:00
case AB_NIL :
PushValue ( C4VNull ) ;
break ;
2010-04-07 13:04:19 +00:00
case AB_DUP :
2011-05-02 19:53:58 +00:00
PushValue ( pCurVal [ pCPos - > Par . i ] ) ;
break ;
case AB_STACK_SET :
pCurVal [ pCPos - > Par . i ] = pCurVal [ 0 ] ;
break ;
case AB_POP_TO :
pCurVal [ pCPos - > Par . i ] = pCurVal [ 0 ] ;
PopValue ( ) ;
2010-04-07 13:04:19 +00:00
break ;
2012-10-21 16:14:32 +00:00
case AB_EOFN :
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( " internal error: function didn't return " ) ;
2010-03-28 18:58:01 +00:00
case AB_ERR :
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( " syntax error: see above for details " ) ;
2010-03-28 18:58:01 +00:00
2010-04-26 20:16:45 +00:00
case AB_PARN_CONTEXT :
2010-08-01 15:23:36 +00:00
PushValue ( AulExec . GetContext ( AulExec . GetContextDepth ( ) - 2 ) - > Pars [ pCPos - > Par . i ] ) ;
2010-04-26 20:16:45 +00:00
break ;
case AB_VARN_CONTEXT :
2010-08-01 15:23:36 +00:00
PushValue ( AulExec . GetContext ( AulExec . GetContextDepth ( ) - 2 ) - > Vars [ pCPos - > Par . i ] ) ;
2010-04-26 20:16:45 +00:00
break ;
2010-03-28 18:58:01 +00:00
2010-04-07 13:04:19 +00:00
case AB_LOCALN :
2012-06-03 22:03:49 +00:00
if ( ! pCurCtx - > Obj )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( " can't access local variables without this " ) ;
2010-03-28 18:58:01 +00:00
PushNullVals ( 1 ) ;
2012-06-03 22:03:49 +00:00
pCurCtx - > Obj - > GetPropertyByS ( pCPos - > Par . s , pCurVal ) ;
2010-03-28 18:58:01 +00:00
break ;
2010-04-07 13:04:19 +00:00
case AB_LOCALN_SET :
2012-06-03 22:03:49 +00:00
if ( ! pCurCtx - > Obj )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( " can't access local variables without this " ) ;
2012-06-03 22:03:49 +00:00
if ( pCurCtx - > Obj - > IsFrozen ( ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( " local variable: this is readonly " ) ;
2012-06-03 22:03:49 +00:00
pCurCtx - > Obj - > SetPropertyByS ( pCPos - > Par . s , pCurVal [ 0 ] ) ;
2010-03-28 18:58:01 +00:00
break ;
2010-04-07 13:04:19 +00:00
2010-08-14 23:53:18 +00:00
case AB_PROP :
2011-08-20 23:47:38 +00:00
if ( ! pCurVal - > CheckConversion ( C4V_PropList ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( FormatString ( " proplist access: proplist expected, got %s " , pCurVal - > GetTypeName ( ) ) . getData ( ) ) ;
2010-12-06 15:19:15 +00:00
if ( ! pCurVal - > _getPropList ( ) - > GetPropertyByS ( pCPos - > Par . s , pCurVal ) )
2010-10-17 23:45:49 +00:00
pCurVal - > Set0 ( ) ;
2010-08-14 23:53:18 +00:00
break ;
case AB_PROP_SET :
{
C4Value * pPropList = pCurVal - 1 ;
2011-08-20 23:47:38 +00:00
if ( ! pPropList - > CheckConversion ( C4V_PropList ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( FormatString ( " proplist write: proplist expected, got %s " , pPropList - > GetTypeName ( ) ) . getData ( ) ) ;
2010-09-08 12:54:39 +00:00
if ( pPropList - > _getPropList ( ) - > IsFrozen ( ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( " proplist write: proplist is readonly " ) ;
2010-12-06 15:19:15 +00:00
pPropList - > _getPropList ( ) - > SetPropertyByS ( pCPos - > Par . s , pCurVal [ 0 ] ) ;
2010-08-14 23:53:18 +00:00
pPropList - > Set ( pCurVal [ 0 ] ) ;
PopValue ( ) ;
break ;
}
2010-04-07 13:04:19 +00:00
case AB_GLOBALN :
2010-03-28 18:58:01 +00:00
PushValue ( * : : ScriptEngine . GlobalNamed . GetItem ( pCPos - > Par . i ) ) ;
break ;
2010-04-07 13:04:19 +00:00
case AB_GLOBALN_SET :
: : ScriptEngine . GlobalNamed . GetItem ( pCPos - > Par . i ) - > Set ( pCurVal [ 0 ] ) ;
2010-03-28 18:58:01 +00:00
break ;
2010-04-07 13:04:19 +00:00
// prefix
2010-03-28 18:58:01 +00:00
case AB_BitNot : // ~
2011-05-01 15:16:02 +00:00
CheckOpPar ( C4V_Int , " ~ " ) ;
2010-03-28 18:58:01 +00:00
pCurVal - > SetInt ( ~ pCurVal - > _getInt ( ) ) ;
break ;
case AB_Not : // !
2011-05-01 15:16:02 +00:00
pCurVal - > SetBool ( ! pCurVal - > getBool ( ) ) ;
2010-03-28 18:58:01 +00:00
break ;
case AB_Neg : // -
2011-05-01 15:16:02 +00:00
CheckOpPar ( C4V_Int , " - " ) ;
2010-03-28 18:58:01 +00:00
pCurVal - > SetInt ( - pCurVal - > _getInt ( ) ) ;
break ;
2010-04-07 13:04:19 +00:00
case AB_Inc : // ++
2011-05-01 15:16:02 +00:00
CheckOpPar ( C4V_Int , " ++ " ) ;
+ + ( * pCurVal ) ;
2010-03-28 18:58:01 +00:00
break ;
2010-04-07 13:04:19 +00:00
case AB_Dec : // --
2011-05-01 15:16:02 +00:00
CheckOpPar ( C4V_Int , " -- " ) ;
- - ( * pCurVal ) ;
2010-03-28 18:58:01 +00:00
break ;
2011-05-01 15:16:02 +00:00
// postfix
2010-03-28 18:58:01 +00:00
case AB_Pow : // **
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " ** " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetInt ( Pow ( pPar1 - > _getInt ( ) , pPar2 - > _getInt ( ) ) ) ;
PopValue ( ) ;
break ;
}
case AB_Div : // /
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " / " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
if ( ! pPar2 - > _getInt ( ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( " division by zero " ) ;
2013-02-26 20:41:27 +00:00
// INT_MIN/-1 cannot be represented in an int and would cause an uncaught exception
2015-08-31 18:52:39 +00:00
if ( pPar1 - > _getInt ( ) = = INT32_MAX & & pPar2 - > _getInt ( ) = = - 1 )
2013-02-26 20:41:27 +00:00
throw new C4AulExecError ( " division overflow " ) ;
2010-03-28 18:58:01 +00:00
pPar1 - > SetInt ( pPar1 - > _getInt ( ) / pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
case AB_Mul : // *
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " * " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetInt ( pPar1 - > _getInt ( ) * pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
case AB_Mod : // %
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " % " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
2013-02-26 20:41:27 +00:00
// INT_MIN%-1 cannot be represented in an int and would cause an uncaught exception
2015-08-31 18:52:39 +00:00
if ( pPar1 - > _getInt ( ) = = INT32_MAX & & pPar2 - > _getInt ( ) = = - 1 )
2013-02-26 20:41:27 +00:00
throw new C4AulExecError ( " modulo division overflow " ) ;
2010-03-28 18:58:01 +00:00
if ( pPar2 - > _getInt ( ) )
pPar1 - > SetInt ( pPar1 - > _getInt ( ) % pPar2 - > _getInt ( ) ) ;
else
pPar1 - > Set0 ( ) ;
PopValue ( ) ;
break ;
}
case AB_Sub : // -
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " - " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetInt ( pPar1 - > _getInt ( ) - pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
case AB_Sum : // +
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " + " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetInt ( pPar1 - > _getInt ( ) + pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
case AB_LeftShift : // <<
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " << " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetInt ( pPar1 - > _getInt ( ) < < pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
case AB_RightShift : // >>
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " >> " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetInt ( pPar1 - > _getInt ( ) > > pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
case AB_LessThan : // <
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " < " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetBool ( pPar1 - > _getInt ( ) < pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
case AB_LessThanEqual : // <=
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " <= " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetBool ( pPar1 - > _getInt ( ) < = pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
case AB_GreaterThan : // >
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " > " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetBool ( pPar1 - > _getInt ( ) > pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
case AB_GreaterThanEqual : // >=
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " >= " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetBool ( pPar1 - > _getInt ( ) > = pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
case AB_Equal : // ==
{
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
2014-04-19 20:33:31 +00:00
pPar1 - > SetBool ( pPar1 - > IsIdenticalTo ( * pPar2 ) ) ;
2010-03-28 18:58:01 +00:00
PopValue ( ) ;
break ;
}
case AB_NotEqual : // !=
{
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
2014-04-19 20:33:31 +00:00
pPar1 - > SetBool ( ! pPar1 - > IsIdenticalTo ( * pPar2 ) ) ;
2010-03-28 18:58:01 +00:00
PopValue ( ) ;
break ;
}
case AB_BitAnd : // &
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " & " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetInt ( pPar1 - > _getInt ( ) & pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
case AB_BitXOr : // ^
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " ^ " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetInt ( pPar1 - > _getInt ( ) ^ pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
case AB_BitOr : // |
{
2011-05-01 15:16:02 +00:00
CheckOpPars ( C4V_Int , C4V_Int , " | " ) ;
2010-03-28 18:58:01 +00:00
C4Value * pPar1 = pCurVal - 1 , * pPar2 = pCurVal ;
pPar1 - > SetInt ( pPar1 - > _getInt ( ) | pPar2 - > _getInt ( ) ) ;
PopValue ( ) ;
break ;
}
2011-05-01 15:16:02 +00:00
2011-04-09 19:35:16 +00:00
case AB_NEW_ARRAY :
2010-03-28 18:58:01 +00:00
{
// Create array
C4ValueArray * pArray = new C4ValueArray ( pCPos - > Par . i ) ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Pop values from stack
for ( int i = 0 ; i < pCPos - > Par . i ; i + + )
2010-09-20 17:49:00 +00:00
( * pArray ) [ i ] = pCurVal [ i - pCPos - > Par . i + 1 ] ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Push array
2011-04-09 19:35:16 +00:00
PopValues ( pCPos - > Par . i ) ;
PushArray ( pArray ) ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
break ;
}
2009-05-08 13:28:41 +00:00
2011-04-09 19:35:16 +00:00
case AB_NEW_PROPLIST :
2010-03-28 18:58:01 +00:00
{
2011-04-09 19:35:16 +00:00
C4PropList * pPropList = C4PropList : : New ( ) ;
for ( int i = 0 ; i < pCPos - > Par . i ; i + + )
pPropList - > SetPropertyByS ( pCurVal [ - 2 * i - 1 ] . _getStr ( ) , pCurVal [ - 2 * i ] ) ;
PopValues ( pCPos - > Par . i * 2 ) ;
PushPropList ( pPropList ) ;
2010-03-28 18:58:01 +00:00
break ;
}
2009-05-08 13:28:41 +00:00
2010-04-07 13:04:19 +00:00
case AB_ARRAYA :
2010-03-28 18:58:01 +00:00
{
2010-04-07 13:04:19 +00:00
C4Value * pIndex = pCurVal , * pStruct = pCurVal - 1 , * pResult = pCurVal - 1 ;
// Typcheck to determine whether it's an array or a proplist
if ( CheckArrayAccess ( pStruct , pIndex ) = = C4V_Array )
2010-03-28 18:58:01 +00:00
{
2010-04-08 00:47:45 +00:00
* pResult = pStruct - > _getArray ( ) - > GetItem ( pIndex - > _getInt ( ) ) ;
2010-03-28 18:58:01 +00:00
}
else
{
2011-09-26 18:22:31 +00:00
assert ( pStruct - > GetType ( ) = = C4V_PropList ) ;
2010-04-08 00:47:45 +00:00
C4PropList * pPropList = pStruct - > _getPropList ( ) ;
2010-12-06 15:19:15 +00:00
if ( ! pPropList - > GetPropertyByS ( pIndex - > _getStr ( ) , pResult ) )
2010-04-07 13:04:19 +00:00
pResult - > Set0 ( ) ;
2010-03-28 18:58:01 +00:00
}
// Remove index
PopValue ( ) ;
break ;
}
2010-04-07 13:04:19 +00:00
case AB_ARRAYA_SET :
{
C4Value * pValue = pCurVal , * pIndex = pCurVal - 1 , * pStruct = pCurVal - 2 , * pResult = pCurVal - 2 ;
// Typcheck to determine whether it's an array or a proplist
if ( CheckArrayAccess ( pStruct , pIndex ) = = C4V_Array )
{
2010-04-08 00:47:45 +00:00
pStruct - > _getArray ( ) - > SetItem ( pIndex - > _getInt ( ) , * pValue ) ;
2010-04-07 13:04:19 +00:00
}
else
{
2011-09-26 18:22:31 +00:00
assert ( pStruct - > GetType ( ) = = C4V_PropList ) ;
2010-04-08 00:47:45 +00:00
C4PropList * pPropList = pStruct - > _getPropList ( ) ;
2010-09-08 12:54:39 +00:00
if ( pPropList - > IsFrozen ( ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( " proplist write: proplist is readonly " ) ;
2010-12-06 15:19:15 +00:00
pPropList - > SetPropertyByS ( pIndex - > _getStr ( ) , * pValue ) ;
2010-04-07 13:04:19 +00:00
}
// Set result, remove array and index from stack
* pResult = * pValue ;
PopValues ( 2 ) ;
break ;
}
2010-04-05 15:41:36 +00:00
case AB_ARRAY_SLICE :
{
C4Value & Array = pCurVal [ - 2 ] ;
C4Value & StartIndex = pCurVal [ - 1 ] ;
C4Value & EndIndex = pCurVal [ 0 ] ;
// Typcheck
2011-08-20 23:47:38 +00:00
if ( ! Array . CheckConversion ( C4V_Array ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( FormatString ( " array slice: can't access %s as an array " , Array . GetTypeName ( ) ) . getData ( ) ) ;
2011-08-20 23:47:38 +00:00
if ( ! StartIndex . CheckConversion ( C4V_Int ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( FormatString ( " array slice: start index of type %s, int expected " , StartIndex . GetTypeName ( ) ) . getData ( ) ) ;
2011-08-20 23:47:38 +00:00
if ( ! EndIndex . CheckConversion ( C4V_Int ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( FormatString ( " array slice: end index of type %s, int expected " , EndIndex . GetTypeName ( ) ) . getData ( ) ) ;
2010-04-05 15:41:36 +00:00
Array . SetArray ( Array . GetData ( ) . Array - > GetSlice ( StartIndex . _getInt ( ) , EndIndex . _getInt ( ) ) ) ;
// Remove both indices
PopValues ( 2 ) ;
break ;
}
2009-05-08 13:28:41 +00:00
2010-08-03 20:47:45 +00:00
case AB_ARRAY_SLICE_SET :
{
C4Value & Array = pCurVal [ - 3 ] ;
C4Value & StartIndex = pCurVal [ - 2 ] ;
C4Value & EndIndex = pCurVal [ - 1 ] ;
C4Value & Value = pCurVal [ 0 ] ;
// Typcheck
2011-08-20 23:47:38 +00:00
if ( ! Array . CheckConversion ( C4V_Array ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( FormatString ( " array slice: can't access %s as an array " , Array . GetTypeName ( ) ) . getData ( ) ) ;
2011-08-20 23:47:38 +00:00
if ( ! StartIndex . CheckConversion ( C4V_Int ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( FormatString ( " array slice: start index of type %s, int expected " , StartIndex . GetTypeName ( ) ) . getData ( ) ) ;
2011-08-20 23:47:38 +00:00
if ( ! EndIndex . CheckConversion ( C4V_Int ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( FormatString ( " array slice: end index of type %s, int expected " , EndIndex . GetTypeName ( ) ) . getData ( ) ) ;
2010-08-03 20:47:45 +00:00
C4ValueArray * pArray = Array . _getArray ( ) ;
pArray - > SetSlice ( StartIndex . _getInt ( ) , EndIndex . _getInt ( ) , Value ) ;
// Set value as result, remove both indices and first copy of value
Array = Value ;
PopValues ( 3 ) ;
break ;
}
2010-03-28 18:58:01 +00:00
case AB_STACK :
if ( pCPos - > Par . i < 0 )
PopValues ( - pCPos - > Par . i ) ;
else
PushNullVals ( pCPos - > Par . i ) ;
break ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
case AB_JUMP :
fJump = true ;
pCPos + = pCPos - > Par . i ;
break ;
case AB_JUMPAND :
if ( ! pCurVal [ 0 ] )
{
fJump = true ;
pCPos + = pCPos - > Par . i ;
}
else
{
2009-05-08 13:28:41 +00:00
PopValue ( ) ;
2010-03-28 18:58:01 +00:00
}
break ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
case AB_JUMPOR :
if ( ! ! pCurVal [ 0 ] )
{
fJump = true ;
pCPos + = pCPos - > Par . i ;
}
else
{
2009-08-28 02:44:53 +00:00
PopValue ( ) ;
2010-03-28 18:58:01 +00:00
}
break ;
2009-08-28 02:44:53 +00:00
2012-04-15 13:44:01 +00:00
case AB_JUMPNNIL : // ??
{
if ( pCurVal [ 0 ] . GetType ( ) ! = C4V_Nil )
{
fJump = true ;
pCPos + = pCPos - > Par . i ;
}
else
{
PopValue ( ) ;
}
break ;
}
2010-03-28 18:58:01 +00:00
case AB_CONDN :
if ( ! pCurVal [ 0 ] )
{
fJump = true ;
pCPos + = pCPos - > Par . i ;
}
PopValue ( ) ;
break ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
case AB_COND :
if ( pCurVal [ 0 ] )
{
fJump = true ;
pCPos + = pCPos - > Par . i ;
}
PopValue ( ) ;
break ;
case AB_RETURN :
{
// Trace
if ( iTraceStart > = 0 )
{
StdStrBuf Buf ( " T " ) ;
Buf . AppendChars ( ' > ' , ContextStackSize ( ) - iTraceStart ) ;
2011-10-13 22:40:55 +00:00
LogF ( " %s%s returned %s " , Buf . getData ( ) , pCurCtx - > Func - > GetName ( ) , pCurVal - > GetDataString ( ) . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
C4Value * pReturn = pCurCtx - > Return ;
2009-04-21 21:44:56 +00:00
2010-03-28 18:58:01 +00:00
// External call?
if ( ! pReturn )
{
// Get return value and stop executing.
C4Value rVal = * pCurVal ;
PopValuesUntil ( pCurCtx - > Pars - 1 ) ;
PopContext ( ) ;
return rVal ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Save return value
if ( pCurVal ! = pReturn )
pReturn - > Set ( * pCurVal ) ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Pop context
PopContext ( ) ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Clear value stack, except return value
PopValuesUntil ( pReturn ) ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Jump back, continue.
pCPos = pCurCtx - > CPos + 1 ;
fJump = true ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
break ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
case AB_FUNC :
{
// Get function call data
C4AulFunc * pFunc = pCPos - > Par . f ;
C4Value * pPars = pCurVal - pFunc - > GetParCount ( ) + 1 ;
// Save current position
pCurCtx - > CPos = pCPos ;
2011-04-11 22:10:51 +00:00
assert ( pCurCtx - > Func - > GetCode ( ) < = pCPos ) ;
2010-03-28 18:58:01 +00:00
// Do the call
C4AulBCC * pJump = Call ( pFunc , pPars , pPars , NULL ) ;
if ( pJump )
{
pCPos = pJump ;
fJump = true ;
}
break ;
}
2009-05-08 13:28:41 +00:00
2010-04-07 13:04:19 +00:00
case AB_PAR :
2011-08-20 23:47:38 +00:00
if ( ! pCurVal - > CheckConversion ( C4V_Int ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( FormatString ( " Par: index of type %s, int expected " , pCurVal - > GetTypeName ( ) ) . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
// Push reference to parameter on the stack
2011-04-17 23:48:37 +00:00
if ( pCurVal - > _getInt ( ) > = 0 & & pCurVal - > _getInt ( ) < pCurCtx - > Func - > GetParCount ( ) )
2010-04-07 13:04:19 +00:00
pCurVal - > Set ( pCurCtx - > Pars [ pCurVal - > _getInt ( ) ] ) ;
2010-03-28 18:58:01 +00:00
else
pCurVal - > Set0 ( ) ;
break ;
2009-05-08 13:28:41 +00:00
2012-06-18 02:07:36 +00:00
case AB_THIS :
if ( ! pCurCtx - > Obj | | ! pCurCtx - > Obj - > Status )
PushNullVals ( 1 ) ;
else
PushPropList ( pCurCtx - > Obj ) ;
break ;
2010-03-28 18:58:01 +00:00
case AB_FOREACH_NEXT :
{
// This should always hold
2011-08-20 23:47:38 +00:00
assert ( pCurVal - > CheckConversion ( C4V_Int ) ) ;
2010-03-28 18:58:01 +00:00
int iItem = pCurVal - > _getInt ( ) ;
// Check array the first time only
if ( ! iItem )
{
2011-08-20 23:47:38 +00:00
if ( ! pCurVal [ - 1 ] . CheckConversion ( C4V_Array ) )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( FormatString ( " for: array expected, but got %s " , pCurVal [ - 1 ] . GetTypeName ( ) ) . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
}
C4ValueArray * pArray = pCurVal [ - 1 ] . _getArray ( ) ;
// No more entries?
if ( pCurVal - > _getInt ( ) > = pArray - > GetSize ( ) )
break ;
// Get next
pCurCtx - > Vars [ pCPos - > Par . i ] = pArray - > GetItem ( iItem ) ;
// Save position
pCurVal - > SetInt ( iItem + 1 ) ;
// Jump over next instruction
pCPos + = 2 ;
fJump = true ;
break ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
case AB_CALL :
case AB_CALLFS :
{
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
C4Value * pPars = pCurVal - C4AUL_MAX_Par + 1 ;
C4Value * pTargetVal = pCurVal - C4AUL_MAX_Par ;
2009-05-08 13:28:41 +00:00
2011-10-15 00:30:30 +00:00
C4PropList * pDest ;
2011-09-26 18:29:32 +00:00
if ( pTargetVal - > CheckConversion ( C4V_PropList ) )
2010-03-28 18:58:01 +00:00
{
2011-10-15 00:30:30 +00:00
pDest = pTargetVal - > _getPropList ( ) ;
2010-03-28 18:58:01 +00:00
}
else
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( FormatString ( " '->': invalid target type %s, expected proplist " , pTargetVal - > GetTypeName ( ) ) . getData ( ) ) ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Search function for given context
2011-10-15 00:30:30 +00:00
C4AulFunc * pFunc = pDest - > GetFunc ( pCPos - > Par . s ) ;
2010-03-28 18:58:01 +00:00
if ( ! pFunc & & pCPos - > bccType = = AB_CALLFS )
{
PopValuesUntil ( pTargetVal ) ;
pTargetVal - > Set0 ( ) ;
break ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Function not found?
if ( ! pFunc )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( FormatString ( " '->': no function \" %s \" in object \" %s \" " , pCPos - > Par . s - > GetCStr ( ) , pTargetVal - > GetDataString ( ) . getData ( ) ) . getData ( ) ) ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// Save current position
pCurCtx - > CPos = pCPos ;
2011-05-08 17:28:48 +00:00
assert ( pCurCtx - > Func - > GetCode ( ) < = pCPos ) ;
2009-05-08 13:28:41 +00:00
2011-04-17 23:48:37 +00:00
// adjust parameter count
if ( pCurVal + 1 - pPars > pFunc - > GetParCount ( ) )
PopValues ( pCurVal + 1 - pPars - pFunc - > GetParCount ( ) ) ;
else
PushNullVals ( pFunc - > GetParCount ( ) - ( pCurVal + 1 - pPars ) ) ;
2010-03-28 18:58:01 +00:00
// Call function
2011-10-15 00:30:30 +00:00
C4AulBCC * pNewCPos = Call ( pFunc , pTargetVal , pPars , pDest ) ;
2010-03-28 18:58:01 +00:00
if ( pNewCPos )
{
// Jump
pCPos = pNewCPos ;
fJump = true ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
break ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
case AB_DEBUG :
2010-02-23 18:29:26 +00:00
# ifndef NOAULDEBUG
2013-10-13 19:44:17 +00:00
if ( C4AulDebug * pDebug = C4AulDebug : : GetDebugger ( ) )
pDebug - > DebugStep ( pCPos , pCurVal ) ;
2010-02-23 18:29:26 +00:00
# endif
2010-03-28 18:58:01 +00:00
break ;
}
2009-05-08 13:28:41 +00:00
// Continue
2010-03-28 18:58:01 +00:00
if ( ! fJump )
2009-05-08 13:28:41 +00:00
pCPos + + ;
}
2010-03-28 18:58:01 +00:00
}
catch ( C4AulError * e )
{
2010-12-22 03:26:37 +00:00
if ( ! e - > shown ) e - > show ( ) ;
// Save current position
2011-05-08 17:28:48 +00:00
assert ( pCurCtx - > Func - > GetCode ( ) < = pCPos ) ;
2010-12-22 03:26:37 +00:00
pCurCtx - > CPos = pCPos ;
2009-05-08 13:28:41 +00:00
// Unwind stack
C4Value * pUntil = NULL ;
2010-03-28 18:58:01 +00:00
while ( pCurCtx > = pOldCtx )
{
2010-12-22 03:26:37 +00:00
pCurCtx - > dump ( StdStrBuf ( " by: " ) ) ;
2009-05-08 13:28:41 +00:00
pUntil = pCurCtx - > Pars - 1 ;
PopContext ( ) ;
}
2010-03-28 18:58:01 +00:00
if ( pUntil )
PopValuesUntil ( pUntil ) ;
2010-12-22 03:26:37 +00:00
// Pass?
if ( fPassErrors )
throw ;
// Trace
2011-02-23 20:06:14 +00:00
LogCallStack ( ) ;
2010-12-22 03:26:37 +00:00
delete e ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Return nothing
return C4VNull ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-10-13 21:39:35 +00:00
C4AulBCC * C4AulExec : : Call ( C4AulFunc * pFunc , C4Value * pReturn , C4Value * pPars , C4PropList * pContext )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// No object given? Use current context
2011-10-13 21:39:35 +00:00
if ( ! pContext )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( pCurCtx > = Contexts ) ;
2012-06-03 22:03:49 +00:00
pContext = pCurCtx - > Obj ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2014-04-17 15:20:46 +00:00
pFunc - > CheckParTypes ( pPars ) ;
2009-05-08 13:28:41 +00:00
// Script function?
C4AulScriptFunc * pSFunc = pFunc - > SFunc ( ) ;
2010-03-28 18:58:01 +00:00
if ( pSFunc )
{
2009-05-08 13:28:41 +00:00
// Push a new context
C4AulScriptContext ctx ;
2012-06-03 22:03:49 +00:00
ctx . Obj = pContext ;
2012-04-29 14:53:29 +00:00
if ( ctx . Obj & & ! ctx . Obj - > Status )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( " using removed object " ) ;
2009-05-08 13:28:41 +00:00
ctx . Return = pReturn ;
ctx . Pars = pPars ;
2011-04-17 21:52:55 +00:00
ctx . Vars = pCurVal + 1 ;
2009-05-08 13:28:41 +00:00
ctx . Func = pSFunc ;
ctx . CPos = NULL ;
PushContext ( ctx ) ;
// Jump to code
2010-12-22 01:10:58 +00:00
return pSFunc - > GetCode ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2012-05-27 21:35:23 +00:00
if ( pContext & & ! pContext - > Status )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( " using removed object " ) ;
2009-05-08 13:28:41 +00:00
# ifdef DEBUGREC_SCRIPT
2013-05-25 21:01:41 +00:00
if ( Config . General . DebugRec )
2010-03-28 18:58:01 +00:00
{
2013-05-25 21:01:41 +00:00
StdStrBuf sCallText ;
if ( pContext & & pContext - > GetObject ( ) )
sCallText . AppendFormat ( " Object(%d): " , pContext - > GetObject ( ) - > Number ) ;
sCallText . Append ( pFunc - > GetName ( ) ) ;
sCallText . AppendChar ( ' ( ' ) ;
for ( int i = 0 ; i < C4AUL_MAX_Par ; + + i )
2010-03-28 18:58:01 +00:00
{
2013-05-25 21:01:41 +00:00
if ( i ) sCallText . AppendChar ( ' , ' ) ;
C4Value & rV = pPars [ i ] ;
if ( rV . GetType ( ) = = C4V_String )
2010-03-28 18:58:01 +00:00
{
2013-05-25 21:01:41 +00:00
C4String * s = rV . getStr ( ) ;
if ( ! s )
sCallText . Append ( " (Snull) " ) ;
else
{
sCallText . Append ( " \" " ) ;
sCallText . Append ( s - > GetData ( ) ) ;
sCallText . Append ( " \" " ) ;
}
2010-03-28 18:58:01 +00:00
}
2013-05-25 21:01:41 +00:00
else
sCallText . Append ( rV . GetDataString ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2013-05-25 21:01:41 +00:00
sCallText . AppendChar ( ' ) ' ) ;
sCallText . AppendChar ( ' ; ' ) ;
AddDbgRec ( RCT_AulFunc , sCallText . getData ( ) , sCallText . getLength ( ) + 1 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
# endif
2009-04-21 21:44:56 +00:00
2009-05-08 13:28:41 +00:00
// Execute
# ifdef _DEBUG
C4AulScriptContext * pCtx = pCurCtx ;
2010-03-28 18:58:01 +00:00
# endif
if ( pReturn > pCurVal )
2012-05-27 21:35:23 +00:00
PushValue ( pFunc - > Exec ( pContext , pPars , true ) ) ;
2009-05-08 13:28:41 +00:00
else
2012-05-27 21:35:23 +00:00
pReturn - > Set ( pFunc - > Exec ( pContext , pPars , true ) ) ;
2009-05-08 13:28:41 +00:00
# ifdef _DEBUG
assert ( pCtx = = pCurCtx ) ;
# endif
// Remove parameters from stack
PopValuesUntil ( pReturn ) ;
// Continue
return NULL ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4AulStartTrace ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
AulExec . StartTrace ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4AulExec : : StartTrace ( )
2010-03-28 18:58:01 +00:00
{
if ( iTraceStart < 0 )
2009-05-08 13:28:41 +00:00
iTraceStart = ContextStackSize ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4AulExec : : StartProfiling ( C4AulScript * pProfiledScript )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// stop previous profiler run
if ( fProfiling ) AbortProfiling ( ) ;
fProfiling = true ;
// resets profling times and starts recording the times
this - > pProfiledScript = pProfiledScript ;
2013-12-07 14:27:01 +00:00
C4TimeMilliseconds tNow = C4TimeMilliseconds : : Now ( ) ;
2009-05-08 13:28:41 +00:00
tDirectExecStart = tNow ; // in case profiling is started from DirectExec
tDirectExecTotal = 0 ;
pProfiledScript - > ResetProfilerTimes ( ) ;
for ( C4AulScriptContext * pCtx = Contexts ; pCtx < = pCurCtx ; + + pCtx )
pCtx - > tTime = tNow ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4AulExec : : StopProfiling ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// stop the profiler and displays results
if ( ! fProfiling ) return ;
fProfiling = false ;
// collect profiler times
C4AulProfiler Profiler ;
Profiler . CollectEntry ( NULL , tDirectExecTotal ) ;
pProfiledScript - > CollectProfilerTimes ( Profiler ) ;
Profiler . Show ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-05 21:25:37 +00:00
void C4AulExec : : PushContext ( const C4AulScriptContext & rContext )
{
2010-03-28 18:58:01 +00:00
if ( pCurCtx > = Contexts + MAX_CONTEXT_STACK - 1 )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( " context stack overflow " ) ;
2010-03-05 21:25:37 +00:00
* + + pCurCtx = rContext ;
// Trace?
2010-03-28 18:58:01 +00:00
if ( iTraceStart > = 0 )
{
2010-03-05 21:25:37 +00:00
StdStrBuf Buf ( " T " ) ;
Buf . AppendChars ( ' > ' , ContextStackSize ( ) - iTraceStart ) ;
pCurCtx - > dump ( Buf ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-05 21:25:37 +00:00
// Profiler: Safe time to measure difference afterwards
2013-12-07 14:27:01 +00:00
if ( fProfiling ) pCurCtx - > tTime = C4TimeMilliseconds : : Now ( ) ;
2010-03-05 21:25:37 +00:00
}
void C4AulExec : : PopContext ( )
{
2010-03-28 18:58:01 +00:00
if ( pCurCtx < Contexts )
2012-05-15 01:11:23 +00:00
throw new C4AulExecError ( " internal error: context stack underflow " ) ;
2010-03-05 21:25:37 +00:00
// Profiler adding up times
if ( fProfiling )
2010-03-28 18:58:01 +00:00
{
2013-12-07 14:27:01 +00:00
uint32_t dt = C4TimeMilliseconds : : Now ( ) - pCurCtx - > tTime ;
2013-12-04 12:35:07 +00:00
if ( pCurCtx - > Func )
2010-03-05 21:25:37 +00:00
pCurCtx - > Func - > tProfileTime + = dt ;
2010-03-28 18:58:01 +00:00
}
2010-03-05 21:25:37 +00:00
// Trace done?
2010-03-28 18:58:01 +00:00
if ( iTraceStart > = 0 )
{
if ( ContextStackSize ( ) < = iTraceStart )
2010-03-05 21:25:37 +00:00
{
iTraceStart = - 1 ;
}
2010-03-28 18:58:01 +00:00
}
2010-03-05 21:25:37 +00:00
pCurCtx - - ;
}
2009-05-08 13:28:41 +00:00
void C4AulProfiler : : StartProfiling ( C4AulScript * pScript )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
AulExec . StartProfiling ( pScript ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4AulProfiler : : StopProfiling ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
AulExec . StopProfiling ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4AulProfiler : : Abort ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
AulExec . AbortProfiling ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-12-04 12:35:07 +00:00
void C4AulProfiler : : CollectEntry ( C4AulScriptFunc * pFunc , uint32_t tProfileTime )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// zero entries are not collected to have a cleaner list
if ( ! tProfileTime ) return ;
// add entry to list
Entry e ;
e . pFunc = pFunc ;
e . tProfileTime = tProfileTime ;
Times . push_back ( e ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4AulProfiler : : Show ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// sort by time
std : : sort ( Times . rbegin ( ) , Times . rend ( ) ) ;
// display them
Log ( " Profiler statistics: " ) ;
Log ( " ============================== " ) ;
typedef std : : vector < Entry > EntryList ;
for ( EntryList : : iterator i = Times . begin ( ) ; i ! = Times . end ( ) ; + + i )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Entry & e = ( * i ) ;
2013-12-04 12:35:07 +00:00
LogF ( " %05ums \t %s " , e . tProfileTime , e . pFunc ? ( e . pFunc - > GetFullName ( ) . getData ( ) ) : " Direct exec " ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
Log ( " ============================== " ) ;
// done!
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2012-05-27 21:35:23 +00:00
C4Value C4AulScriptFunc : : Exec ( C4PropList * p , C4Value pPars [ ] , bool fPassErrors )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// handle easiest case first
2012-05-27 21:35:23 +00:00
if ( Owner - > State ! = ASS_PARSED ) return C4Value ( ) ;
2009-05-08 13:28:41 +00:00
// execute
2012-05-27 21:35:23 +00:00
return AulExec . Exec ( this , p , pPars , fPassErrors ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-09-29 01:49:21 +00:00
C4Value C4AulScript : : DirectExec ( C4Object * pObj , const char * szScript , const char * szContext , bool fPassErrors , C4AulScriptContext * context )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
# ifdef DEBUGREC_SCRIPT
2013-05-25 21:01:41 +00:00
if ( Config . General . DebugRec )
{
AddDbgRec ( RCT_DirectExec , szScript , strlen ( szScript ) + 1 ) ;
int32_t iObjNumber = pObj ? pObj - > Number : - 1 ;
AddDbgRec ( RCT_DirectExec , & iObjNumber , sizeof ( int32_t ) ) ;
}
2009-05-08 13:28:41 +00:00
# endif
// profiler
AulExec . StartDirectExec ( ) ;
// Add a new function
2012-10-27 21:53:42 +00:00
C4AulScriptFunc * pFunc = new C4AulScriptFunc ( this , GetScriptHost ( ) , 0 , szScript ) ;
2009-05-08 13:28:41 +00:00
// Parse function
try
2010-03-28 18:58:01 +00:00
{
2012-01-26 23:42:41 +00:00
pFunc - > ParseFn ( context ) ;
2012-10-27 21:53:42 +00:00
C4Value vRetVal ( AulExec . Exec ( pFunc , pObj , NULL , fPassErrors ) ) ;
delete pFunc ; pFunc = 0 ;
// profiler
AulExec . StopDirectExec ( ) ;
return vRetVal ;
2010-03-28 18:58:01 +00:00
}
catch ( C4AulError * ex )
{
2009-05-08 13:28:41 +00:00
delete pFunc ;
2012-03-09 10:45:25 +00:00
if ( fPassErrors )
throw ;
2012-10-27 21:53:42 +00:00
ex - > show ( ) ;
2012-03-09 10:45:25 +00:00
delete ex ;
2009-05-08 13:28:41 +00:00
return C4VNull ;
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
void C4AulScript : : ResetProfilerTimes ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// zero all profiler times of owned functions
C4AulScriptFunc * pSFunc ;
2012-05-27 22:50:13 +00:00
for ( C4String * pFn = GetPropList ( ) - > EnumerateOwnFuncs ( ) ; pFn ; pFn = GetPropList ( ) - > EnumerateOwnFuncs ( pFn ) )
if ( ( pSFunc = GetPropList ( ) - > GetFunc ( pFn ) - > SFunc ( ) ) )
2009-05-08 13:28:41 +00:00
pSFunc - > tProfileTime = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2012-01-25 03:15:39 +00:00
void C4AulScript : : CollectProfilerTimes ( C4AulProfiler & rProfiler )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// collect all profiler times of owned functions
C4AulScriptFunc * pSFunc ;
2012-05-27 22:50:13 +00:00
for ( C4String * pFn = GetPropList ( ) - > EnumerateOwnFuncs ( ) ; pFn ; pFn = GetPropList ( ) - > EnumerateOwnFuncs ( pFn ) )
if ( ( pSFunc = GetPropList ( ) - > GetFunc ( pFn ) - > SFunc ( ) ) )
2009-05-08 13:28:41 +00:00
rProfiler . CollectEntry ( pSFunc , pSFunc - > tProfileTime ) ;
2012-01-25 03:15:39 +00:00
}
void C4AulScriptEngine : : ResetProfilerTimes ( )
{
// zero all profiler times of owned functions
C4AulScript : : ResetProfilerTimes ( ) ;
// reset sub-scripts
2012-06-07 19:07:31 +00:00
for ( C4AulScript * pScript = Child0 ; pScript ; pScript = pScript - > Next )
2012-01-25 03:15:39 +00:00
pScript - > ResetProfilerTimes ( ) ;
}
void C4AulScriptEngine : : CollectProfilerTimes ( C4AulProfiler & rProfiler )
{
// collect all profiler times of owned functions
C4AulScript : : CollectProfilerTimes ( rProfiler ) ;
2009-05-08 13:28:41 +00:00
// collect sub-scripts
2012-06-07 19:07:31 +00:00
for ( C4AulScript * pScript = Child0 ; pScript ; pScript = pScript - > Next )
2009-05-08 13:28:41 +00:00
pScript - > CollectProfilerTimes ( rProfiler ) ;
2010-03-28 18:58:01 +00:00
}