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/
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2009 - 2016 , 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
2016-04-03 18:07:56 +00:00
# include "C4Include.h"
# include "script/C4AulExec.h"
2009-05-08 13:28:41 +00:00
2016-04-03 18:07:56 +00:00
# include "script/C4Aul.h"
# include "script/C4AulScriptFunc.h"
# include "script/C4AulDebug.h"
# include "object/C4Object.h"
# include "config/C4Config.h"
# include "game/C4Game.h"
# include "lib/C4Log.h"
# include "control/C4Record.h"
2016-04-02 17:44:44 +00:00
# include "object/C4Def.h"
# include "script/C4ScriptHost.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 + + )
2016-01-16 22:03:40 +00:00
{
if ( ! Pars [ i ] )
iNullPars + + ;
else
2010-03-28 18:58:01 +00:00
{
2016-01-16 22:03:40 +00:00
if ( i > iNullPars )
Dump . AppendChar ( ' , ' ) ;
// Insert missing null parameters
while ( iNullPars > 0 )
2010-03-28 18:58:01 +00:00
{
2016-01-16 22:03:40 +00:00
Dump . Append ( " 0, " ) ;
iNullPars - - ;
2010-01-25 04:00:59 +00:00
}
2016-01-16 22:03:40 +00:00
// Insert parameter
Dump . Append ( Pars [ i ] . GetDataString ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2016-01-16 22:03:40 +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
2014-04-20 13:52:09 +00:00
Dump . Append ( Func - > Parent - > GetDataString ( ) ) ;
2009-05-08 13:28:41 +00:00
// 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
{
2015-12-17 17:56:05 +00:00
# define ReturnIfTranslationAvailable(script, key) do \
{ \
const auto & s = script ; \
const auto & k = key ; \
if ( s ) \
{ \
try \
{ \
return : : Strings . RegString ( s - > Translate ( k ) . c_str ( ) ) ; \
} \
catch ( C4LangStringTable : : NoSuchTranslation & ) { } \
} \
} while ( 0 )
2016-11-02 23:58:02 +00:00
if ( ! text | | text - > GetData ( ) . isNull ( ) ) return nullptr ;
2012-04-28 19:32:29 +00:00
// Find correct script: translations of the context if possible, containing script as fallback
2012-05-15 01:03:47 +00:00
if ( _this & & _this - > GetDef ( ) )
2015-12-17 17:56:05 +00:00
ReturnIfTranslationAvailable ( & ( _this - > GetDef ( ) - > Script ) , text - > GetCStr ( ) ) ;
ReturnIfTranslationAvailable ( AulExec . pCurCtx [ 0 ] . Func - > pOrgScript , text - > GetCStr ( ) ) ;
// No translation available, log
DebugLogF ( " WARNING: Translate: no translation for string \" %s \" " , text - > GetCStr ( ) ) ;
// Trace
AulExec . LogCallStack ( ) ;
return text ;
# undef ReturnIfTranslationAvailable
2012-04-28 19:32:29 +00:00
}
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 )
{
for ( C4AulScriptContext * pCtx = pCurCtx ; pCtx > = Contexts ; pCtx - - )
{
if ( pCtx - > Obj = = obj )
2016-11-02 23:58:02 +00:00
pCtx - > Obj = nullptr ;
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
{
2016-01-15 22:39:44 +00:00
// Save start context
C4AulScriptContext * pOldCtx = pCurCtx ;
2009-05-08 13:28:41 +00:00
C4Value * pPars = pCurVal + 1 ;
2016-01-15 22:39:44 +00:00
try
{
// Push parameters
assert ( pnPars ) ;
for ( int i = 0 ; i < pSFunc - > GetParCount ( ) ; i + + )
2009-05-08 13:28:41 +00:00
PushValue ( pnPars [ i ] ) ;
2016-01-15 22:39:44 +00:00
// Push a new context
C4AulScriptContext ctx ;
ctx . tTime = 0 ;
ctx . Obj = p ;
2016-11-02 23:58:02 +00:00
ctx . Return = nullptr ;
2016-01-15 22:39:44 +00:00
ctx . Pars = pPars ;
ctx . Func = pSFunc ;
2016-11-02 23:58:02 +00:00
ctx . CPos = nullptr ;
2016-01-15 22:39:44 +00:00
PushContext ( ctx ) ;
2009-05-08 13:28:41 +00:00
2016-01-15 22:39:44 +00:00
// Execute
return Exec ( pSFunc - > GetCode ( ) ) ;
}
catch ( C4AulError & e )
{
2016-07-25 12:57:54 +00:00
if ( ! fPassErrors )
: : ScriptEngine . GetErrorHandler ( ) - > OnError ( e . what ( ) ) ;
2016-01-15 22:39:44 +00:00
// Unwind stack
2016-07-25 12:57:54 +00:00
// TODO: The stack dump should be passed to the error handler somehow
2016-01-15 22:39:44 +00:00
while ( pCurCtx > pOldCtx )
{
pCurCtx - > dump ( StdStrBuf ( " by: " ) ) ;
PopContext ( ) ;
}
PopValuesUntil ( pPars - 1 ) ;
// Pass?
if ( fPassErrors )
throw ;
// Trace
LogCallStack ( ) ;
}
2009-05-08 13:28:41 +00:00
2016-01-15 22:39:44 +00:00
// Return nothing
return C4VNull ;
}
C4Value C4AulExec : : Exec ( C4AulBCC * pCPos )
{
2009-05-08 13:28:41 +00:00
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 :
2015-12-07 14:15:49 +00:00
throw C4AulExecError ( " internal error: function didn't return " ) ;
2010-03-28 18:58:01 +00:00
case AB_ERR :
2016-04-07 17:35:45 +00:00
if ( pCPos - > Par . s )
throw C4AulExecError ( ( std : : string ( " syntax error: " ) + pCPos - > Par . s - > GetCStr ( ) ) . c_str ( ) ) ;
else
throw C4AulExecError ( " syntax error: see above for details " ) ;
2010-03-28 18:58:01 +00:00
2016-01-16 22:03:40 +00:00
case AB_DUP_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 ;
2010-04-07 13:04:19 +00:00
case AB_LOCALN :
2012-06-03 22:03:49 +00:00
if ( ! pCurCtx - > Obj )
2015-12-07 14:15:49 +00:00
throw 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 )
2015-12-07 14:15:49 +00:00
throw C4AulExecError ( " can't access local variables without this " ) ;
2012-06-03 22:03:49 +00:00
if ( pCurCtx - > Obj - > IsFrozen ( ) )
2015-12-07 14:15:49 +00:00
throw 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 ) )
2015-12-07 14:15:49 +00:00
throw 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 ) )
2015-12-07 14:15:49 +00:00
throw C4AulExecError ( FormatString ( " proplist write: proplist expected, got %s " , pPropList - > GetTypeName ( ) ) . getData ( ) ) ;
2010-09-08 12:54:39 +00:00
if ( pPropList - > _getPropList ( ) - > IsFrozen ( ) )
2015-12-07 14:15:49 +00:00
throw 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 , " ++ " ) ;
2016-01-15 19:13:52 +00:00
pCurVal - > SetInt ( pCurVal - > _getInt ( ) + 1 ) ;
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 , " -- " ) ;
2016-01-15 19:13:52 +00:00
pCurVal - > SetInt ( pCurVal - > _getInt ( ) - 1 ) ;
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 ( ) )
2015-12-07 14:15:49 +00:00
throw 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_MIN & & pPar2 - > _getInt ( ) = = - 1 )
2015-12-07 14:15:49 +00:00
throw 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_MIN & & pPar2 - > _getInt ( ) = = - 1 )
2015-12-07 14:15:49 +00:00
throw 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 )
{
2016-05-01 22:34:18 +00:00
if ( pStruct - > _getArray ( ) - > IsFrozen ( ) )
throw C4AulExecError ( " array write: array is readonly " ) ;
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 ( ) )
2015-12-07 14:15:49 +00:00
throw 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 ) )
2015-12-07 14:15:49 +00:00
throw 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 ) )
2015-12-07 14:15:49 +00:00
throw 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 ) )
2015-12-07 14:15:49 +00:00
throw 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 ) )
2015-12-07 14:15:49 +00:00
throw 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 ) )
2015-12-07 14:15:49 +00:00
throw 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 ) )
2015-12-07 14:15:49 +00:00
throw 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 ( ) ;
2016-05-01 22:34:18 +00:00
if ( pArray - > IsFrozen ( ) ) throw C4AulExecError ( " array write: array is readonly " ) ;
2010-08-03 20:47:45 +00:00
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
2016-11-02 23:58:02 +00:00
C4AulBCC * pJump = Call ( pFunc , pPars , pPars , nullptr ) ;
2010-03-28 18:58:01 +00:00
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 ) )
2015-12-07 14:15:49 +00:00
throw 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 ) )
2015-12-07 14:15:49 +00:00
throw 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
2016-01-16 22:03:40 +00:00
pCurVal [ pCPos - > Par . i ] = pArray - > GetItem ( iItem ) ;
2010-03-28 18:58:01 +00:00
// 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
2015-12-07 14:15:49 +00:00
throw 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 )
2015-12-07 14:15:49 +00:00
throw 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
}
2016-06-20 19:36:20 +00:00
catch ( C4AulError & )
2010-03-28 18:58:01 +00:00
{
2010-12-22 03:26:37 +00:00
// 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 ;
2016-01-15 22:39:44 +00:00
throw ;
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
2015-01-30 19:33:57 +00:00
pFunc - > CheckParTypes ( pPars , true ) ;
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 )
2015-12-07 14:15:49 +00:00
throw C4AulExecError ( " using removed object " ) ;
2009-05-08 13:28:41 +00:00
ctx . Return = pReturn ;
ctx . Pars = pPars ;
ctx . Func = pSFunc ;
2016-11-02 23:58:02 +00:00
ctx . CPos = nullptr ;
2009-05-08 13:28:41 +00:00
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 )
2015-12-07 14:15:49 +00:00
throw 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
2016-11-02 23:58:02 +00:00
return nullptr ;
2009-05-08 13:28:41 +00:00
}
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
2016-01-03 19:01:37 +00:00
void C4AulExec : : StartProfiling ( C4ScriptHost * pProfiledScript )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// stop previous profiler run
2016-01-03 19:01:37 +00:00
if ( fProfiling ) StopProfiling ( ) ;
2009-05-08 13:28:41 +00:00
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 ;
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
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 )
2015-12-07 14:15:49 +00:00
throw 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 )
2015-12-07 14:15:49 +00:00
throw 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 - - ;
}
2016-01-03 19:01:37 +00:00
void C4AulProfiler : : StartProfiling ( C4ScriptHost * pScript )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
AulExec . StartProfiling ( pScript ) ;
2016-01-03 19:01:37 +00:00
if ( pScript )
ResetTimes ( pScript - > GetPropList ( ) ) ;
else
ResetTimes ( ) ;
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
{
2016-01-03 19:01:37 +00:00
if ( ! AulExec . IsProfiling ( ) ) return ;
2009-05-08 13:28:41 +00:00
AulExec . StopProfiling ( ) ;
2016-01-03 19:01:37 +00:00
// collect profiler times
C4AulProfiler Profiler ;
2016-11-02 23:58:02 +00:00
Profiler . CollectEntry ( nullptr , AulExec . tDirectExecTotal ) ;
2016-01-03 19:01:37 +00:00
if ( AulExec . pProfiledScript )
Profiler . CollectTimes ( AulExec . pProfiledScript - > GetPropList ( ) ) ;
else
Profiler . CollectTimes ( ) ;
Profiler . Show ( ) ;
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
2016-06-20 05:37:04 +00:00
C4Value C4AulExec : : DirectExec ( C4PropList * p , const char * szScript , const char * szContext , bool fPassErrors , C4AulScriptContext * context , bool parse_function )
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 ) ;
2015-02-01 21:20:52 +00:00
int32_t iObjNumber = p & & p - > GetPropListNumbered ( ) ? p - > GetPropListNumbered ( ) - > Number : - 1 ;
2013-05-25 21:01:41 +00:00
AddDbgRec ( RCT_DirectExec , & iObjNumber , sizeof ( int32_t ) ) ;
}
2009-05-08 13:28:41 +00:00
# endif
// profiler
2015-02-01 21:20:52 +00:00
StartDirectExec ( ) ;
2016-01-15 21:31:52 +00:00
C4PropListStatic * script = : : GameScript . GetPropList ( ) ;
if ( p & & p - > IsStatic ( ) )
script = p - > IsStatic ( ) ;
2015-02-01 21:20:52 +00:00
else if ( p & & p - > GetDef ( ) )
2016-01-15 21:31:52 +00:00
script = p - > GetDef ( ) ;
2009-05-08 13:28:41 +00:00
// Add a new function
2016-01-15 21:31:52 +00:00
auto pFunc = std : : make_unique < C4AulScriptFunc > ( script , nullptr , nullptr , szScript ) ;
2009-05-08 13:28:41 +00:00
// Parse function
try
2010-03-28 18:58:01 +00:00
{
2016-06-20 05:37:04 +00:00
if ( parse_function )
{
// Expect a full function (e.g. "func foo() { return bar(); }")
pFunc - > ParseDirectExecFunc ( & : : ScriptEngine , context ) ;
}
else
{
// Expect a single statement (e.g. "bar()")
pFunc - > ParseDirectExecStatement ( & : : ScriptEngine , context ) ;
}
2016-01-15 22:39:44 +00:00
C4AulParSet Pars ;
C4Value vRetVal ( Exec ( pFunc . get ( ) , p , Pars . Par , fPassErrors ) ) ;
2012-10-27 21:53:42 +00:00
// profiler
2015-02-01 21:20:52 +00:00
StopDirectExec ( ) ;
2012-10-27 21:53:42 +00:00
return vRetVal ;
2010-03-28 18:58:01 +00:00
}
2015-12-07 14:15:49 +00:00
catch ( C4AulError & ex )
2010-03-28 18:58:01 +00:00
{
2012-03-09 10:45:25 +00:00
if ( fPassErrors )
throw ;
2016-07-25 12:57:54 +00:00
: : ScriptEngine . GetErrorHandler ( ) - > OnError ( ex . what ( ) ) ;
2016-01-15 21:31:52 +00:00
LogCallStack ( ) ;
StopDirectExec ( ) ;
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
2016-01-03 19:01:37 +00:00
void C4AulProfiler : : ResetTimes ( C4PropListStatic * p )
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 ;
2016-01-03 19:01:37 +00:00
for ( C4String * pFn = p - > EnumerateOwnFuncs ( ) ; pFn ; pFn = p - > EnumerateOwnFuncs ( pFn ) )
if ( ( pSFunc = p - > 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
2016-01-03 19:01:37 +00:00
void C4AulProfiler : : CollectTimes ( C4PropListStatic * p )
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 ;
2016-01-03 19:01:37 +00:00
for ( C4String * pFn = p - > EnumerateOwnFuncs ( ) ; pFn ; pFn = p - > EnumerateOwnFuncs ( pFn ) )
if ( ( pSFunc = p - > GetFunc ( pFn ) - > SFunc ( ) ) )
CollectEntry ( pSFunc , pSFunc - > tProfileTime ) ;
2012-01-25 03:15:39 +00:00
}
2016-01-03 19:01:37 +00:00
void C4AulProfiler : : ResetTimes ( )
2012-01-25 03:15:39 +00:00
{
// zero all profiler times of owned functions
2016-01-03 19:01:37 +00:00
ResetTimes ( : : ScriptEngine . GetPropList ( ) ) ;
2012-01-25 03:15:39 +00:00
// reset sub-scripts
2016-01-03 19:37:05 +00:00
for ( C4ScriptHost * pScript = : : ScriptEngine . Child0 ; pScript ; pScript = pScript - > Next )
2016-01-03 19:01:37 +00:00
ResetTimes ( pScript - > GetPropList ( ) ) ;
2012-01-25 03:15:39 +00:00
}
2016-01-03 19:01:37 +00:00
void C4AulProfiler : : CollectTimes ( )
2012-01-25 03:15:39 +00:00
{
// collect all profiler times of owned functions
2016-01-03 19:01:37 +00:00
CollectTimes ( : : ScriptEngine . GetPropList ( ) ) ;
2009-05-08 13:28:41 +00:00
// collect sub-scripts
2016-01-03 19:37:05 +00:00
for ( C4ScriptHost * pScript = : : ScriptEngine . Child0 ; pScript ; pScript = pScript - > Next )
2016-01-03 19:01:37 +00:00
CollectTimes ( pScript - > GetPropList ( ) ) ;
2010-03-28 18:58:01 +00:00
}