2012-09-19 15:15:01 +00:00
//-----------------------------------------------------------------------------
2021-03-30 23:33:19 +00:00
// Copyright (c) 2013 GarageGames, LLC
// Copyright (c) 2015 Faust Logic, Inc.
// Copyright (c) 2021 TGEMIT Authors & Contributors
2012-09-19 15:15:01 +00:00
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
# include "platform/platform.h"
# include "console/console.h"
# include "console/ast.h"
# include "core/tAlgorithm.h"
# include "core/strings/findMatch.h"
# include "core/strings/stringUnit.h"
# include "console/consoleInternal.h"
# include "core/stream/fileStream.h"
# include "console/compiler.h"
# include "console/simBase.h"
# include "console/telnetDebugger.h"
# include "sim/netStringTable.h"
# include "console/ICallMethod.h"
# include "console/stringStack.h"
# include "util/messaging/message.h"
# include "core/frameAllocator.h"
2018-03-29 00:52:46 +00:00
# include "console/returnBuffer.h"
2021-03-30 23:33:19 +00:00
# include "console/consoleValueStack.h"
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
# ifndef TORQUE_TGB_ONLY
# include "materials/materialDefinition.h"
# include "materials/materialManager.h"
# endif
using namespace Compiler ;
2021-03-30 23:33:19 +00:00
enum EvalConstants
{
MaxStackSize = 1024 ,
FieldBufferSizeString = 2048 ,
FieldBufferSizeNumeric = 128 ,
2021-04-30 05:20:01 +00:00
ConcatBufferInitialSize = 8192 ,
2021-03-30 23:33:19 +00:00
MethodOnComponent = - 2
} ;
/// Frame data for a foreach/foreach$ loop.
struct IterStackRecord
{
/// If true, this is a foreach$ loop; if not, it's a foreach loop.
bool mIsStringIter ;
2021-04-04 04:50:37 +00:00
/// True if the variable referenced is a global
bool mIsGlobalVariable ;
union
{
/// The iterator variable if we are a global variable
Dictionary : : Entry * mVariable ;
/// The register variable if we are a local variable
S32 mRegister ;
} mVar ;
2021-03-30 23:33:19 +00:00
/// Information for an object iterator loop.
struct ObjectPos
{
/// The set being iterated over.
SimSet * mSet ;
/// Current index in the set.
U32 mIndex ;
} ;
/// Information for a string iterator loop.
struct StringPos
{
/// The raw string data on the string stack.
const char * mString ;
/// Current parsing position.
U32 mIndex ;
} ;
union
{
ObjectPos mObj ;
StringPos mStr ;
} mData ;
} ;
ConsoleValueStack < 4096 > gCallStack ;
StringStack STR ;
IterStackRecord iterStack [ MaxStackSize ] ;
2021-04-27 02:52:58 +00:00
U32 _ITER = 0 ; ///< Stack pointer for iterStack.
2021-03-30 23:33:19 +00:00
2021-04-27 02:52:58 +00:00
ConsoleValue stack [ MaxStackSize ] ;
S32 _STK = 0 ;
2021-03-30 23:33:19 +00:00
2021-04-30 05:20:01 +00:00
const char * tsconcat ( const char * strA , const char * strB , S32 & outputLen )
{
S32 lenA = dStrlen ( strA ) ;
S32 lenB = dStrlen ( strB ) ;
S32 len = lenA + lenB + 1 ;
char * concatBuffer = ( char * ) dMalloc ( len ) ;
concatBuffer [ len - 1 ] = ' \0 ' ;
memcpy ( concatBuffer , strA , lenA ) ;
memcpy ( concatBuffer + lenA , strB , lenB ) ;
outputLen = lenA + lenB ;
return concatBuffer ;
}
2012-09-19 15:15:01 +00:00
namespace Con
{
2017-11-06 04:33:32 +00:00
// Current script file name and root, these are registered as
// console variables.
extern StringTableEntry gCurrentFile ;
extern StringTableEntry gCurrentRoot ;
2021-09-13 23:46:21 +00:00
extern S32 gObjectCopyFailures ;
2012-09-19 15:15:01 +00:00
}
namespace Con
{
const char * getNamespaceList ( Namespace * ns )
{
U32 size = 1 ;
Namespace * walk ;
2017-11-06 04:33:32 +00:00
for ( walk = ns ; walk ; walk = walk - > mParent )
2012-09-19 15:15:01 +00:00
size + = dStrlen ( walk - > mName ) + 4 ;
char * ret = Con : : getReturnBuffer ( size ) ;
ret [ 0 ] = 0 ;
2017-11-06 04:33:32 +00:00
for ( walk = ns ; walk ; walk = walk - > mParent )
2012-09-19 15:15:01 +00:00
{
2018-03-06 05:48:44 +00:00
dStrcat ( ret , walk - > mName , size ) ;
2017-11-06 04:33:32 +00:00
if ( walk - > mParent )
2018-03-06 05:48:44 +00:00
dStrcat ( ret , " -> " , size ) ;
2012-09-19 15:15:01 +00:00
}
return ret ;
}
}
2021-09-04 03:27:39 +00:00
static void getFieldComponent ( SimObject * object , StringTableEntry field , const char * array , StringTableEntry subField , char val [ ] , S32 currentLocalRegister )
2021-03-30 23:33:19 +00:00
{
const char * prevVal = NULL ;
2021-09-04 03:27:39 +00:00
if ( object & & field )
prevVal = object - > getDataField ( field , array ) ;
else if ( currentLocalRegister ! = - 1 )
2021-08-17 02:02:24 +00:00
prevVal = gEvalState . getLocalStringVariable ( currentLocalRegister ) ;
else if ( gEvalState . currentVariable )
prevVal = gEvalState . getStringVariable ( ) ;
2021-03-30 23:33:19 +00:00
// Make sure we got a value.
if ( prevVal & & * prevVal )
{
static const StringTableEntry xyzw [ ] =
{
StringTable - > insert ( " x " ) ,
StringTable - > insert ( " y " ) ,
StringTable - > insert ( " z " ) ,
StringTable - > insert ( " w " )
} ;
static const StringTableEntry rgba [ ] =
{
StringTable - > insert ( " r " ) ,
StringTable - > insert ( " g " ) ,
StringTable - > insert ( " b " ) ,
StringTable - > insert ( " a " )
} ;
// Translate xyzw and rgba into the indexed component
// of the variable or field.
2021-09-03 02:21:00 +00:00
if ( subField = = xyzw [ 0 ] | | subField = = rgba [ 0 ] )
2021-03-30 23:33:19 +00:00
dStrcpy ( val , StringUnit : : getUnit ( prevVal , 0 , " \t \n " ) , 128 ) ;
2021-09-03 02:21:00 +00:00
else if ( subField = = xyzw [ 1 ] | | subField = = rgba [ 1 ] )
2021-03-30 23:33:19 +00:00
dStrcpy ( val , StringUnit : : getUnit ( prevVal , 1 , " \t \n " ) , 128 ) ;
2021-09-03 02:21:00 +00:00
else if ( subField = = xyzw [ 2 ] | | subField = = rgba [ 2 ] )
2021-03-30 23:33:19 +00:00
dStrcpy ( val , StringUnit : : getUnit ( prevVal , 2 , " \t \n " ) , 128 ) ;
else if ( subField = = xyzw [ 3 ] | | subField = = rgba [ 3 ] )
dStrcpy ( val , StringUnit : : getUnit ( prevVal , 3 , " \t \n " ) , 128 ) ;
else
val [ 0 ] = 0 ;
}
else
val [ 0 ] = 0 ;
}
2021-09-04 03:27:39 +00:00
static void setFieldComponent ( SimObject * object , StringTableEntry field , const char * array , StringTableEntry subField , S32 currentLocalRegister )
2021-03-30 23:33:19 +00:00
{
// Copy the current string value
char strValue [ 1024 ] ;
2021-04-27 02:52:58 +00:00
dStrncpy ( strValue , stack [ _STK ] . getString ( ) , 1024 ) ;
2021-03-30 23:33:19 +00:00
char val [ 1024 ] = " " ;
const char * prevVal = NULL ;
2021-09-04 03:27:39 +00:00
if ( object & & field )
prevVal = object - > getDataField ( field , array ) ;
2021-09-04 20:23:20 +00:00
else if ( currentLocalRegister ! = - 1 )
2021-08-17 02:02:24 +00:00
prevVal = gEvalState . getLocalStringVariable ( currentLocalRegister ) ;
2021-03-30 23:33:19 +00:00
// Set the value on a variable.
else if ( gEvalState . currentVariable )
prevVal = gEvalState . getStringVariable ( ) ;
// Ensure that the variable has a value
if ( ! prevVal )
return ;
static const StringTableEntry xyzw [ ] =
{
StringTable - > insert ( " x " ) ,
StringTable - > insert ( " y " ) ,
StringTable - > insert ( " z " ) ,
StringTable - > insert ( " w " )
} ;
static const StringTableEntry rgba [ ] =
{
StringTable - > insert ( " r " ) ,
StringTable - > insert ( " g " ) ,
StringTable - > insert ( " b " ) ,
StringTable - > insert ( " a " )
} ;
// Insert the value into the specified
// component of the string.
if ( subField = = xyzw [ 0 ] | | subField = = rgba [ 0 ] )
dStrcpy ( val , StringUnit : : setUnit ( prevVal , 0 , strValue , " \t \n " ) , 128 ) ;
else if ( subField = = xyzw [ 1 ] | | subField = = rgba [ 1 ] )
dStrcpy ( val , StringUnit : : setUnit ( prevVal , 1 , strValue , " \t \n " ) , 128 ) ;
else if ( subField = = xyzw [ 2 ] | | subField = = rgba [ 2 ] )
dStrcpy ( val , StringUnit : : setUnit ( prevVal , 2 , strValue , " \t \n " ) , 128 ) ;
else if ( subField = = xyzw [ 3 ] | | subField = = rgba [ 3 ] )
dStrcpy ( val , StringUnit : : setUnit ( prevVal , 3 , strValue , " \t \n " ) , 128 ) ;
if ( val [ 0 ] ! = 0 )
{
// Update the field or variable.
2021-09-04 03:27:39 +00:00
if ( object & & field )
object - > setDataField ( field , 0 , val ) ;
else if ( currentLocalRegister ! = - 1 )
2021-08-17 02:02:24 +00:00
gEvalState . setLocalStringVariable ( currentLocalRegister , val , dStrlen ( val ) ) ;
2021-03-30 23:33:19 +00:00
else if ( gEvalState . currentVariable )
gEvalState . setStringVariable ( val ) ;
}
}
2012-09-19 15:15:01 +00:00
//------------------------------------------------------------
F64 consoleStringToNumber ( const char * str , StringTableEntry file , U32 line )
{
F64 val = dAtof ( str ) ;
2017-11-06 04:33:32 +00:00
if ( val ! = 0 )
2012-09-19 15:15:01 +00:00
return val ;
2017-11-06 04:33:32 +00:00
else if ( ! dStricmp ( str , " true " ) )
2012-09-19 15:15:01 +00:00
return 1 ;
2017-11-06 04:33:32 +00:00
else if ( ! dStricmp ( str , " false " ) )
2012-09-19 15:15:01 +00:00
return 0 ;
2017-11-06 04:33:32 +00:00
else if ( file )
2012-09-19 15:15:01 +00:00
{
Con : : warnf ( ConsoleLogEntry : : General , " %s (%d): string always evaluates to 0. " , file , line ) ;
return 0 ;
}
return 0 ;
}
//------------------------------------------------------------
namespace Con
{
2018-03-29 00:52:46 +00:00
ReturnBuffer retBuffer ;
2012-09-19 15:15:01 +00:00
char * getReturnBuffer ( U32 bufferSize )
{
2018-03-29 00:52:46 +00:00
return retBuffer . getBuffer ( bufferSize ) ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
char * getReturnBuffer ( const char * stringToCopy )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
U32 len = dStrlen ( stringToCopy ) + 1 ;
2018-03-29 00:52:46 +00:00
char * ret = retBuffer . getBuffer ( len ) ;
2017-11-06 04:33:32 +00:00
dMemcpy ( ret , stringToCopy , len ) ;
2012-09-19 15:15:01 +00:00
return ret ;
}
2017-11-06 04:33:32 +00:00
char * getReturnBuffer ( const String & str )
2012-09-19 15:15:01 +00:00
{
const U32 size = str . size ( ) ;
2018-03-29 00:52:46 +00:00
char * ret = retBuffer . getBuffer ( size ) ;
2017-11-06 04:33:32 +00:00
dMemcpy ( ret , str . c_str ( ) , size ) ;
2012-09-19 15:15:01 +00:00
return ret ;
}
2017-11-06 04:33:32 +00:00
char * getReturnBuffer ( const StringBuilder & str )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
char * buffer = Con : : getReturnBuffer ( str . length ( ) + 1 ) ;
str . copy ( buffer ) ;
buffer [ str . length ( ) ] = ' \0 ' ;
2012-09-19 15:15:01 +00:00
return buffer ;
}
char * getArgBuffer ( U32 bufferSize )
{
return STR . getArgBuffer ( bufferSize ) ;
}
2015-02-07 22:41:54 +00:00
char * getFloatArg ( F64 arg )
2012-09-19 15:15:01 +00:00
{
2015-02-07 22:41:54 +00:00
char * ret = STR . getArgBuffer ( 32 ) ;
dSprintf ( ret , 32 , " %g " , arg ) ;
return ret ;
2012-09-19 15:15:01 +00:00
}
2015-02-07 22:41:54 +00:00
char * getIntArg ( S32 arg )
2012-09-19 15:15:01 +00:00
{
2015-02-07 22:41:54 +00:00
char * ret = STR . getArgBuffer ( 32 ) ;
dSprintf ( ret , 32 , " %d " , arg ) ;
2015-10-13 20:19:36 +00:00
return ret ;
}
char * getBoolArg ( bool arg )
{
char * ret = STR . getArgBuffer ( 32 ) ;
dSprintf ( ret , 32 , " %d " , arg ) ;
2015-02-07 22:41:54 +00:00
return ret ;
2012-09-19 15:15:01 +00:00
}
2015-02-07 22:41:54 +00:00
2017-11-06 04:33:32 +00:00
char * getStringArg ( const char * arg )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
U32 len = dStrlen ( arg ) + 1 ;
char * ret = STR . getArgBuffer ( len ) ;
dMemcpy ( ret , arg , len ) ;
2012-09-19 15:15:01 +00:00
return ret ;
}
2017-11-06 04:33:32 +00:00
char * getStringArg ( const String & arg )
2012-09-19 15:15:01 +00:00
{
const U32 size = arg . size ( ) ;
2017-11-06 04:33:32 +00:00
char * ret = STR . getArgBuffer ( size ) ;
dMemcpy ( ret , arg . c_str ( ) , size ) ;
2012-09-19 15:15:01 +00:00
return ret ;
}
}
//------------------------------------------------------------
2017-11-06 04:33:32 +00:00
void ExprEvalState : : setCurVarName ( StringTableEntry name )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( name [ 0 ] = = ' $ ' )
2012-09-19 15:15:01 +00:00
currentVariable = globalVars . lookup ( name ) ;
2017-11-06 04:33:32 +00:00
else if ( getStackDepth ( ) > 0 )
2012-09-19 15:15:01 +00:00
currentVariable = getCurrentFrame ( ) . lookup ( name ) ;
2017-11-06 04:33:32 +00:00
if ( ! currentVariable & & gWarnUndefinedScriptVariables )
2017-01-06 23:04:28 +00:00
Con : : warnf ( ConsoleLogEntry : : Script , " Variable referenced before assignment: %s " , name ) ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
void ExprEvalState : : setCurVarNameCreate ( StringTableEntry name )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( name [ 0 ] = = ' $ ' )
2012-09-19 15:15:01 +00:00
currentVariable = globalVars . add ( name ) ;
2017-11-06 04:33:32 +00:00
else if ( getStackDepth ( ) > 0 )
2012-09-19 15:15:01 +00:00
currentVariable = getCurrentFrame ( ) . add ( name ) ;
else
{
currentVariable = NULL ;
Con : : warnf ( ConsoleLogEntry : : Script , " Accessing local variable in global scope... failed: %s " , name ) ;
}
}
//------------------------------------------------------------
2017-11-06 04:33:32 +00:00
S32 ExprEvalState : : getIntVariable ( )
2012-09-19 15:15:01 +00:00
{
return currentVariable ? currentVariable - > getIntValue ( ) : 0 ;
}
2017-11-06 04:33:32 +00:00
F64 ExprEvalState : : getFloatVariable ( )
2012-09-19 15:15:01 +00:00
{
return currentVariable ? currentVariable - > getFloatValue ( ) : 0 ;
}
2017-11-06 04:33:32 +00:00
const char * ExprEvalState : : getStringVariable ( )
2012-09-19 15:15:01 +00:00
{
return currentVariable ? currentVariable - > getStringValue ( ) : " " ;
}
//------------------------------------------------------------
2017-11-06 04:33:32 +00:00
void ExprEvalState : : setIntVariable ( S32 val )
2012-09-19 15:15:01 +00:00
{
AssertFatal ( currentVariable ! = NULL , " Invalid evaluator state - trying to set null variable! " ) ;
currentVariable - > setIntValue ( val ) ;
}
2017-11-06 04:33:32 +00:00
void ExprEvalState : : setFloatVariable ( F64 val )
2012-09-19 15:15:01 +00:00
{
AssertFatal ( currentVariable ! = NULL , " Invalid evaluator state - trying to set null variable! " ) ;
currentVariable - > setFloatValue ( val ) ;
}
2017-11-06 04:33:32 +00:00
void ExprEvalState : : setStringVariable ( const char * val )
2012-09-19 15:15:01 +00:00
{
AssertFatal ( currentVariable ! = NULL , " Invalid evaluator state - trying to set null variable! " ) ;
currentVariable - > setStringValue ( val ) ;
}
2021-03-30 23:33:19 +00:00
//-----------------------------------------------------------------------------
2015-02-16 21:05:45 +00:00
2021-05-01 06:07:54 +00:00
enum class FloatOperation
{
Add ,
Sub ,
Mul ,
Div ,
LT ,
LE ,
GR ,
GE ,
EQ ,
NE
} ;
2021-07-10 01:05:55 +00:00
template < FloatOperation Op >
TORQUE_NOINLINE void doSlowMathOp ( )
{
ConsoleValue & a = stack [ _STK ] ;
ConsoleValue & b = stack [ _STK - 1 ] ;
// Arithmetic
if constexpr ( Op = = FloatOperation : : Add )
stack [ _STK - 1 ] . setFloat ( a . getFloat ( ) + b . getFloat ( ) ) ;
else if constexpr ( Op = = FloatOperation : : Sub )
stack [ _STK - 1 ] . setFloat ( a . getFloat ( ) - b . getFloat ( ) ) ;
else if constexpr ( Op = = FloatOperation : : Mul )
stack [ _STK - 1 ] . setFloat ( a . getFloat ( ) * b . getFloat ( ) ) ;
else if constexpr ( Op = = FloatOperation : : Div )
stack [ _STK - 1 ] . setFloat ( a . getFloat ( ) / b . getFloat ( ) ) ;
// Logical
if constexpr ( Op = = FloatOperation : : LT )
stack [ _STK - 1 ] . setInt ( a . getFloat ( ) < b . getFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : LE )
stack [ _STK - 1 ] . setInt ( a . getFloat ( ) < = b . getFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : GR )
stack [ _STK - 1 ] . setInt ( a . getFloat ( ) > b . getFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : GE )
stack [ _STK - 1 ] . setInt ( a . getFloat ( ) > = b . getFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : EQ )
stack [ _STK - 1 ] . setInt ( a . getFloat ( ) = = b . getFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : NE )
stack [ _STK - 1 ] . setInt ( a . getFloat ( ) ! = b . getFloat ( ) ) ;
_STK - - ;
}
2021-05-01 06:07:54 +00:00
template < FloatOperation Op >
TORQUE_FORCEINLINE void doFloatMathOperation ( )
{
ConsoleValue & a = stack [ _STK ] ;
ConsoleValue & b = stack [ _STK - 1 ] ;
S32 fastIf = ( a . getType ( ) = = ConsoleValueType : : cvFloat ) & ( b . getType ( ) = = ConsoleValueType : : cvFloat ) ;
if ( fastIf )
{
// Arithmetic
if constexpr ( Op = = FloatOperation : : Add )
stack [ _STK - 1 ] . setFastFloat ( a . getFastFloat ( ) + b . getFastFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : Sub )
stack [ _STK - 1 ] . setFastFloat ( a . getFastFloat ( ) - b . getFastFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : Mul )
stack [ _STK - 1 ] . setFastFloat ( a . getFastFloat ( ) * b . getFastFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : Div )
stack [ _STK - 1 ] . setFastFloat ( a . getFastFloat ( ) / b . getFastFloat ( ) ) ;
// Logical
if constexpr ( Op = = FloatOperation : : LT )
stack [ _STK - 1 ] . setFastInt ( a . getFastFloat ( ) < b . getFastFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : LE )
stack [ _STK - 1 ] . setFastInt ( a . getFastFloat ( ) < = b . getFastFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : GR )
stack [ _STK - 1 ] . setFastInt ( a . getFastFloat ( ) > b . getFastFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : GE )
stack [ _STK - 1 ] . setFastInt ( a . getFastFloat ( ) > = b . getFastFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : EQ )
stack [ _STK - 1 ] . setFastInt ( a . getFastFloat ( ) = = b . getFastFloat ( ) ) ;
if constexpr ( Op = = FloatOperation : : NE )
stack [ _STK - 1 ] . setFastInt ( a . getFastFloat ( ) ! = b . getFastFloat ( ) ) ;
_STK - - ;
}
else
{
doSlowMathOp < Op > ( ) ;
}
}
//-----------------------------------------------------------------------------
enum class IntegerOperation
{
BitAnd ,
BitOr ,
Xor ,
LShift ,
RShift ,
LogicalAnd ,
LogicalOr
} ;
2021-07-10 01:05:55 +00:00
template < IntegerOperation Op >
TORQUE_NOINLINE void doSlowIntegerOp ( )
{
ConsoleValue & a = stack [ _STK ] ;
ConsoleValue & b = stack [ _STK - 1 ] ;
// Bitwise Op
if constexpr ( Op = = IntegerOperation : : BitAnd )
stack [ _STK - 1 ] . setInt ( a . getInt ( ) & b . getInt ( ) ) ;
if constexpr ( Op = = IntegerOperation : : BitOr )
stack [ _STK - 1 ] . setInt ( a . getInt ( ) | b . getInt ( ) ) ;
if constexpr ( Op = = IntegerOperation : : Xor )
stack [ _STK - 1 ] . setInt ( a . getInt ( ) ^ b . getInt ( ) ) ;
if constexpr ( Op = = IntegerOperation : : LShift )
stack [ _STK - 1 ] . setInt ( a . getInt ( ) < < b . getInt ( ) ) ;
if constexpr ( Op = = IntegerOperation : : RShift )
stack [ _STK - 1 ] . setInt ( a . getInt ( ) > > b . getInt ( ) ) ;
// Logical Op
if constexpr ( Op = = IntegerOperation : : LogicalAnd )
2023-04-08 17:39:09 +00:00
stack [ _STK - 1 ] . setBool ( a . getInt ( ) & & b . getInt ( ) ) ;
2021-07-10 01:05:55 +00:00
if constexpr ( Op = = IntegerOperation : : LogicalOr )
2023-04-08 17:39:09 +00:00
stack [ _STK - 1 ] . setBool ( a . getInt ( ) | | b . getInt ( ) ) ;
2021-07-10 01:05:55 +00:00
_STK - - ;
}
2021-05-01 06:07:54 +00:00
template < IntegerOperation Op >
TORQUE_FORCEINLINE void doIntOperation ( )
{
ConsoleValue & a = stack [ _STK ] ;
ConsoleValue & b = stack [ _STK - 1 ] ;
if ( a . isNumberType ( ) & & b . isNumberType ( ) )
{
// Bitwise Op
if constexpr ( Op = = IntegerOperation : : BitAnd )
stack [ _STK - 1 ] . setFastInt ( a . getFastInt ( ) & b . getFastInt ( ) ) ;
if constexpr ( Op = = IntegerOperation : : BitOr )
stack [ _STK - 1 ] . setFastInt ( a . getFastInt ( ) | b . getFastInt ( ) ) ;
if constexpr ( Op = = IntegerOperation : : Xor )
stack [ _STK - 1 ] . setFastInt ( a . getFastInt ( ) ^ b . getFastInt ( ) ) ;
if constexpr ( Op = = IntegerOperation : : LShift )
stack [ _STK - 1 ] . setFastInt ( a . getFastInt ( ) < < b . getFastInt ( ) ) ;
if constexpr ( Op = = IntegerOperation : : RShift )
stack [ _STK - 1 ] . setFastInt ( a . getFastInt ( ) > > b . getFastInt ( ) ) ;
// Logical Op
if constexpr ( Op = = IntegerOperation : : LogicalAnd )
2023-04-08 17:39:09 +00:00
stack [ _STK - 1 ] . setBool ( a . getFastInt ( ) & & b . getFastInt ( ) ) ;
2021-05-01 06:07:54 +00:00
if constexpr ( Op = = IntegerOperation : : LogicalOr )
2023-04-08 17:39:09 +00:00
stack [ _STK - 1 ] . setBool ( a . getFastInt ( ) | | b . getFastInt ( ) ) ;
2021-05-01 06:07:54 +00:00
_STK - - ;
}
else
{
doSlowIntegerOp < Op > ( ) ;
}
}
//-----------------------------------------------------------------------------
2021-03-30 23:33:19 +00:00
U32 gExecCount = 0 ;
2021-04-01 02:10:55 +00:00
ConsoleValue CodeBlock : : exec ( U32 ip , const char * functionName , Namespace * thisNamespace , U32 argc , ConsoleValue * argv , bool noCalls , StringTableEntry packageName , S32 setFrame )
2012-10-04 16:58:43 +00:00
{
2021-03-30 23:33:19 +00:00
# ifdef TORQUE_DEBUG
2021-04-27 02:52:58 +00:00
U32 stackStart = _STK ;
2021-03-30 23:33:19 +00:00
gExecCount + + ;
# endif
2023-04-27 21:10:04 +00:00
const U32 TRACE_BUFFER_SIZE = 1024 ;
2021-03-30 23:33:19 +00:00
static char traceBuffer [ TRACE_BUFFER_SIZE ] ;
U32 i ;
U32 iterDepth = 0 ;
2021-04-01 02:10:55 +00:00
ConsoleValue returnValue ;
2021-03-30 23:33:19 +00:00
incRefCount ( ) ;
F64 * curFloatTable ;
char * curStringTable ;
S32 curStringTableLen = 0 ; //clint to ensure we dont overwrite it
2021-04-27 02:52:58 +00:00
2021-03-30 23:33:19 +00:00
StringTableEntry thisFunctionName = NULL ;
bool popFrame = false ;
if ( argv )
2012-10-11 20:29:39 +00:00
{
2021-03-30 23:33:19 +00:00
// assume this points into a function decl:
U32 fnArgc = code [ ip + 2 + 6 ] ;
U32 regCount = code [ ip + 2 + 7 ] ;
thisFunctionName = CodeToSTE ( code , ip ) ;
S32 wantedArgc = getMin ( argc - 1 , fnArgc ) ; // argv[0] is func name
if ( gEvalState . traceOn )
{
traceBuffer [ 0 ] = 0 ;
dStrcat ( traceBuffer , " Entering " , TRACE_BUFFER_SIZE ) ;
if ( packageName )
{
dStrcat ( traceBuffer , " [ " , TRACE_BUFFER_SIZE ) ;
dStrcat ( traceBuffer , packageName , TRACE_BUFFER_SIZE ) ;
dStrcat ( traceBuffer , " ] " , TRACE_BUFFER_SIZE ) ;
}
if ( thisNamespace & & thisNamespace - > mName )
{
2023-04-27 21:10:04 +00:00
dSprintf ( traceBuffer + ( U32 ) dStrlen ( traceBuffer ) , sizeof ( traceBuffer ) - ( U32 ) dStrlen ( traceBuffer ) ,
2021-03-30 23:33:19 +00:00
" %s::%s( " , thisNamespace - > mName , thisFunctionName ) ;
}
else
{
2023-04-27 21:10:04 +00:00
dSprintf ( traceBuffer + ( U32 ) dStrlen ( traceBuffer ) , sizeof ( traceBuffer ) - ( U32 ) dStrlen ( traceBuffer ) ,
2021-03-30 23:33:19 +00:00
" %s( " , thisFunctionName ) ;
}
for ( i = 0 ; i < wantedArgc ; i + + )
{
dStrcat ( traceBuffer , argv [ i + 1 ] . getString ( ) , TRACE_BUFFER_SIZE ) ;
if ( i ! = wantedArgc - 1 )
dStrcat ( traceBuffer , " , " , TRACE_BUFFER_SIZE ) ;
}
dStrcat ( traceBuffer , " ) " , TRACE_BUFFER_SIZE ) ;
Con : : printf ( " %s " , traceBuffer ) ;
}
gEvalState . pushFrame ( thisFunctionName , thisNamespace , regCount ) ;
popFrame = true ;
for ( i = 0 ; i < wantedArgc ; i + + )
2012-10-04 16:58:43 +00:00
{
2021-03-30 23:33:19 +00:00
S32 reg = code [ ip + ( 2 + 6 + 1 + 1 ) + i ] ;
ConsoleValue & value = argv [ i + 1 ] ;
2021-04-30 04:24:03 +00:00
gEvalState . moveConsoleValue ( reg , std : : move ( value ) ) ;
2021-03-30 23:33:19 +00:00
}
ip = ip + fnArgc + ( 2 + 6 + 1 + 1 ) ;
curFloatTable = functionFloats ;
curStringTable = functionStrings ;
curStringTableLen = functionStringsMaxLen ;
}
else
{
curFloatTable = globalFloats ;
curStringTable = globalStrings ;
curStringTableLen = globalStringsMaxLen ;
2021-04-03 05:53:40 +00:00
// If requested stack frame isn't available, request a new one
// (this prevents assert failures when creating local
// variables without a stack frame)
if ( gEvalState . getStackDepth ( ) < = setFrame )
setFrame = - 1 ;
2021-03-30 23:33:19 +00:00
// Do we want this code to execute using a new stack frame?
2021-11-17 04:56:52 +00:00
// compiling a file will force setFrame to 0, forcing us to get a new frame.
if ( setFrame < = 0 )
2021-03-30 23:33:19 +00:00
{
2021-09-21 01:00:33 +00:00
// argc is the local count for eval
gEvalState . pushFrame ( NULL , NULL , argc ) ;
2021-03-30 23:33:19 +00:00
popFrame = true ;
}
2021-04-03 05:53:40 +00:00
else
2021-03-30 23:33:19 +00:00
{
// We want to copy a reference to an existing stack frame
// on to the top of the stack. Any change that occurs to
// the locals during this new frame will also occur in the
// original frame.
2021-04-03 05:53:40 +00:00
S32 stackIndex = gEvalState . getTopOfStack ( ) - setFrame - 1 ;
2021-03-30 23:33:19 +00:00
gEvalState . pushFrameRef ( stackIndex ) ;
popFrame = true ;
}
}
// Grab the state of the telenet debugger here once
// so that the push and pop frames are always balanced.
const bool telDebuggerOn = TelDebugger & & TelDebugger - > isConnected ( ) ;
if ( telDebuggerOn & & setFrame < 0 )
TelDebugger - > pushStackFrame ( ) ;
StringTableEntry var , objParent ;
2021-10-07 04:27:39 +00:00
U32 failJump = 0 ;
2021-03-30 23:33:19 +00:00
StringTableEntry fnName ;
StringTableEntry fnNamespace , fnPackage ;
static const U32 objectCreationStackSize = 32 ;
U32 objectCreationStackIndex = 0 ;
struct {
SimObject * newObject ;
U32 failJump ;
2023-05-01 15:13:12 +00:00
} objectCreationStack [ objectCreationStackSize ] = { } ;
2021-03-30 23:33:19 +00:00
SimObject * currentNewObject = 0 ;
2021-09-04 03:27:39 +00:00
StringTableEntry prevField = NULL ;
2021-03-30 23:33:19 +00:00
StringTableEntry curField = NULL ;
2021-09-04 03:27:39 +00:00
SimObject * prevObject = NULL ;
2021-03-30 23:33:19 +00:00
SimObject * curObject = NULL ;
SimObject * saveObject = NULL ;
Namespace : : Entry * nsEntry ;
2021-09-17 01:21:04 +00:00
Namespace * ns = NULL ;
2021-03-30 23:33:19 +00:00
const char * curFNDocBlock = NULL ;
const char * curNSDocBlock = NULL ;
const S32 nsDocLength = 128 ;
char nsDocBlockClass [ nsDocLength ] ;
S32 callArgc ;
ConsoleValue * callArgv ;
static char curFieldArray [ 256 ] ;
static char prevFieldArray [ 256 ] ;
CodeBlock * saveCodeBlock = smCurrentCodeBlock ;
smCurrentCodeBlock = this ;
if ( this - > name )
{
Con : : gCurrentFile = this - > name ;
Con : : gCurrentRoot = this - > modPath ;
}
const char * val ;
S32 reg ;
2021-08-17 02:02:24 +00:00
S32 currentRegister = - 1 ;
2021-03-30 23:33:19 +00:00
// The frame temp is used by the variable accessor ops (OP_SAVEFIELD_* and
// OP_LOADFIELD_*) to store temporary values for the fields.
static S32 VAL_BUFFER_SIZE = 1024 ;
FrameTemp < char > valBuffer ( VAL_BUFFER_SIZE ) ;
for ( ; ; )
{
U32 instruction = code [ ip + + ] ;
breakContinue :
switch ( instruction )
{
case OP_FUNC_DECL :
if ( ! noCalls )
{
fnName = CodeToSTE ( code , ip ) ;
fnNamespace = CodeToSTE ( code , ip + 2 ) ;
fnPackage = CodeToSTE ( code , ip + 4 ) ;
bool hasBody = ( code [ ip + 6 ] & 0x01 ) ! = 0 ;
Namespace : : unlinkPackages ( ) ;
if ( fnNamespace = = NULL & & fnPackage = = NULL )
ns = Namespace : : global ( ) ;
else
ns = Namespace : : find ( fnNamespace , fnPackage ) ;
ns - > addFunction ( fnName , this , hasBody ? ip : 0 ) ; // if no body, set the IP to 0
if ( curNSDocBlock )
{
if ( fnNamespace = = StringTable - > lookup ( nsDocBlockClass ) )
{
char * usageStr = dStrdup ( curNSDocBlock ) ;
usageStr [ dStrlen ( usageStr ) ] = ' \0 ' ;
ns - > mUsage = usageStr ;
ns - > mCleanUpUsage = true ;
curNSDocBlock = NULL ;
}
}
Namespace : : relinkPackages ( ) ;
// If we had a docblock, it's definitely not valid anymore, so clear it out.
curFNDocBlock = NULL ;
//Con::printf("Adding function %s::%s (%d)", fnNamespace, fnName, ip);
}
ip = code [ ip + 7 ] ;
break ;
case OP_CREATE_OBJECT :
{
// Read some useful info.
objParent = CodeToSTE ( code , ip ) ;
bool isDataBlock = code [ ip + 2 ] ;
bool isInternal = code [ ip + 3 ] ;
bool isSingleton = code [ ip + 4 ] ;
U32 lineNumber = code [ ip + 5 ] ;
failJump = code [ ip + 6 ] ;
// If we don't allow calls, we certainly don't allow creating objects!
// Moved this to after failJump is set. Engine was crashing when
// noCalls = true and an object was being created at the beginning of
// a file. ADL.
if ( noCalls )
{
ip = failJump ;
break ;
}
// Push the old info to the stack
//Assert( objectCreationStackIndex < objectCreationStackSize );
objectCreationStack [ objectCreationStackIndex ] . newObject = currentNewObject ;
objectCreationStack [ objectCreationStackIndex + + ] . failJump = failJump ;
// Get the constructor information off the stack.
gCallStack . argvc ( NULL , callArgc , & callArgv ) ;
AssertFatal ( callArgc - 3 > = 0 , avar ( " Call Arg needs at least 3, only has %d " , callArgc ) ) ;
const char * objectName = callArgv [ 2 ] . getString ( ) ;
// Con::printf("Creating object...");
// objectName = argv[1]...
currentNewObject = NULL ;
// Are we creating a datablock? If so, deal with case where we override
// an old one.
if ( isDataBlock )
{
// Con::printf(" - is a datablock");
// Find the old one if any.
SimObject * db = Sim : : getDataBlockGroup ( ) - > findObject ( objectName ) ;
// Make sure we're not changing types on ourselves...
if ( db & & dStricmp ( db - > getClassName ( ) , callArgv [ 1 ] . getString ( ) ) )
{
Con : : errorf ( ConsoleLogEntry : : General , " Cannot re-declare data block %s with a different class. " , objectName ) ;
ip = failJump ;
gCallStack . popFrame ( ) ;
break ;
}
// If there was one, set the currentNewObject and move on.
if ( db )
currentNewObject = db ;
}
else if ( ! isInternal )
{
AbstractClassRep * rep = AbstractClassRep : : findClassRep ( objectName ) ;
if ( rep ! = NULL )
{
Con : : errorf ( ConsoleLogEntry : : General , " %s: Cannot name object [%s] the same name as a script class. " ,
getFileLine ( ip ) , objectName ) ;
ip = failJump ;
gCallStack . popFrame ( ) ;
break ;
}
SimObject * obj = Sim : : findObject ( ( const char * ) objectName ) ;
if ( obj )
{
if ( isSingleton )
{
// Make sure we're not trying to change types
if ( dStricmp ( obj - > getClassName ( ) , callArgv [ 1 ] . getString ( ) ) ! = 0 )
{
Con : : errorf ( ConsoleLogEntry : : General , " %s: Cannot re-declare object [%s] with a different class [%s] - was [%s]. " ,
getFileLine ( ip ) , objectName , callArgv [ 1 ] . getString ( ) , obj - > getClassName ( ) ) ;
ip = failJump ;
gCallStack . popFrame ( ) ;
break ;
}
// We're creating a singleton, so use the found object instead of creating a new object.
currentNewObject = obj ;
Con : : warnf ( " %s: Singleton Object was already created with name %s. Using existing object. " ,
getFileLine ( ip ) , objectName ) ;
}
}
}
gCallStack . popFrame ( ) ;
if ( ! currentNewObject )
{
// Well, looks like we have to create a new object.
ConsoleObject * object = ConsoleObject : : create ( callArgv [ 1 ] . getString ( ) ) ;
// Deal with failure!
if ( ! object )
{
Con : : errorf ( ConsoleLogEntry : : General , " %s: Unable to instantiate non-conobject class %s. " , getFileLine ( ip - 1 ) , callArgv [ 1 ] . getString ( ) ) ;
ip = failJump ;
break ;
}
// Do special datablock init if appropros
if ( isDataBlock )
{
SimDataBlock * dataBlock = dynamic_cast < SimDataBlock * > ( object ) ;
if ( dataBlock )
{
dataBlock - > assignId ( ) ;
}
else
{
// They tried to make a non-datablock with a datablock keyword!
Con : : errorf ( ConsoleLogEntry : : General , " %s: Unable to instantiate non-datablock class %s. " , getFileLine ( ip - 1 ) , callArgv [ 1 ] . getString ( ) ) ;
// Clean up...
delete object ;
2021-04-10 19:52:53 +00:00
currentNewObject = NULL ;
2021-03-30 23:33:19 +00:00
ip = failJump ;
break ;
}
}
// Finally, set currentNewObject to point to the new one.
currentNewObject = dynamic_cast < SimObject * > ( object ) ;
// Deal with the case of a non-SimObject.
if ( ! currentNewObject )
{
Con : : errorf ( ConsoleLogEntry : : General , " %s: Unable to instantiate non-SimObject class %s. " , getFileLine ( ip - 1 ) , callArgv [ 1 ] . getString ( ) ) ;
delete object ;
ip = failJump ;
break ;
}
// Set the declaration line
currentNewObject - > setDeclarationLine ( lineNumber ) ;
// Set the file that this object was created in
currentNewObject - > setFilename ( this - > name ) ;
// Does it have a parent object? (ie, the copy constructor : syntax, not inheriance)
if ( * objParent )
{
// Find it!
SimObject * parent ;
if ( Sim : : findObject ( objParent , parent ) )
{
// Con::printf(" - Parent object found: %s", parent->getClassName());
currentNewObject - > setCopySource ( parent ) ;
currentNewObject - > assignFieldsFrom ( parent ) ;
// copy any substitution statements
SimDataBlock * parent_db = dynamic_cast < SimDataBlock * > ( parent ) ;
if ( parent_db )
{
SimDataBlock * currentNewObject_db = dynamic_cast < SimDataBlock * > ( currentNewObject ) ;
if ( currentNewObject_db )
currentNewObject_db - > copySubstitutionsFrom ( parent_db ) ;
}
}
else
{
2021-09-13 23:46:21 +00:00
if ( Con : : gObjectCopyFailures = = - 1 )
Con : : errorf ( ConsoleLogEntry : : General , " %s: Unable to find parent object %s for %s. " , getFileLine ( ip - 1 ) , objParent , callArgv [ 1 ] . getString ( ) ) ;
else
+ + Con : : gObjectCopyFailures ;
2021-03-30 23:33:19 +00:00
delete object ;
currentNewObject = NULL ;
ip = failJump ;
break ;
}
}
// If a name was passed, assign it.
if ( objectName [ 0 ] )
{
if ( ! isInternal )
currentNewObject - > assignName ( objectName ) ;
else
currentNewObject - > setInternalName ( objectName ) ;
// Set the original name
currentNewObject - > setOriginalName ( objectName ) ;
}
// Do the constructor parameters.
if ( ! currentNewObject - > processArguments ( callArgc - 3 , callArgv + 3 ) )
{
delete currentNewObject ;
currentNewObject = NULL ;
ip = failJump ;
break ;
}
// If it's not a datablock, allow people to modify bits of it.
if ( ! isDataBlock )
{
currentNewObject - > setModStaticFields ( true ) ;
currentNewObject - > setModDynamicFields ( true ) ;
}
}
else
{
currentNewObject - > reloadReset ( ) ; // AFX (reload-reset)
// Does it have a parent object? (ie, the copy constructor : syntax, not inheriance)
if ( * objParent )
{
// Find it!
SimObject * parent ;
if ( Sim : : findObject ( objParent , parent ) )
{
// Con::printf(" - Parent object found: %s", parent->getClassName());
// temporarily block name change
SimObject : : preventNameChanging = true ;
currentNewObject - > setCopySource ( parent ) ;
currentNewObject - > assignFieldsFrom ( parent ) ;
// restore name changing
SimObject : : preventNameChanging = false ;
// copy any substitution statements
SimDataBlock * parent_db = dynamic_cast < SimDataBlock * > ( parent ) ;
if ( parent_db )
{
SimDataBlock * currentNewObject_db = dynamic_cast < SimDataBlock * > ( currentNewObject ) ;
if ( currentNewObject_db )
currentNewObject_db - > copySubstitutionsFrom ( parent_db ) ;
}
}
else
{
Con : : errorf ( ConsoleLogEntry : : General , " %d: Unable to find parent object %s for %s. " , lineNumber , objParent , callArgv [ 1 ] . getString ( ) ) ;
}
}
}
// Advance the IP past the create info...
ip + = 7 ;
break ;
}
case OP_ADD_OBJECT :
{
// See OP_SETCURVAR for why we do this.
curFNDocBlock = NULL ;
curNSDocBlock = NULL ;
// Do we place this object at the root?
bool placeAtRoot = code [ ip + + ] ;
// Con::printf("Adding object %s", currentNewObject->getName());
// Make sure it wasn't already added, then add it.
if ( currentNewObject = = NULL )
{
break ;
}
bool isMessage = dynamic_cast < Message * > ( currentNewObject ) ! = NULL ;
if ( currentNewObject - > isProperlyAdded ( ) = = false )
{
bool ret = false ;
if ( isMessage )
{
SimObjectId id = Message : : getNextMessageID ( ) ;
if ( id ! = 0xffffffff )
ret = currentNewObject - > registerObject ( id ) ;
else
Con : : errorf ( " %s: No more object IDs available for messages " , getFileLine ( ip ) ) ;
}
else
ret = currentNewObject - > registerObject ( ) ;
if ( ! ret )
{
// This error is usually caused by failing to call Parent::initPersistFields in the class' initPersistFields().
Con : : warnf ( ConsoleLogEntry : : General , " %s: Register object failed for object %s of class %s. " , getFileLine ( ip - 2 ) , currentNewObject - > getName ( ) , currentNewObject - > getClassName ( ) ) ;
delete currentNewObject ;
2021-09-08 01:03:57 +00:00
currentNewObject = NULL ;
2021-03-30 23:33:19 +00:00
ip = failJump ;
break ;
}
}
// Are we dealing with a datablock?
SimDataBlock * dataBlock = dynamic_cast < SimDataBlock * > ( currentNewObject ) ;
String errorStr ;
// If so, preload it.
if ( dataBlock & & ! dataBlock - > preload ( true , errorStr ) )
{
Con : : errorf ( ConsoleLogEntry : : General , " %s: preload failed for %s: %s. " , getFileLine ( ip - 2 ) ,
currentNewObject - > getName ( ) , errorStr . c_str ( ) ) ;
dataBlock - > deleteObject ( ) ;
2021-09-11 19:16:36 +00:00
currentNewObject = NULL ;
2021-03-30 23:33:19 +00:00
ip = failJump ;
break ;
}
// What group will we be added to, if any?
2021-04-27 02:52:58 +00:00
U32 groupAddId = ( U32 ) stack [ _STK ] . getInt ( ) ;
2021-03-30 23:33:19 +00:00
SimGroup * grp = NULL ;
SimSet * set = NULL ;
if ( ! placeAtRoot | | ! currentNewObject - > getGroup ( ) )
{
if ( ! isMessage )
{
if ( ! placeAtRoot )
{
// Otherwise just add to the requested group or set.
if ( ! Sim : : findObject ( groupAddId , grp ) )
Sim : : findObject ( groupAddId , set ) ;
}
if ( placeAtRoot )
{
// Deal with the instantGroup if we're being put at the root or we're adding to a component.
if ( Con : : gInstantGroup . isEmpty ( ) | | ! Sim : : findObject ( Con : : gInstantGroup , grp ) )
grp = Sim : : getRootGroup ( ) ;
}
}
// If we didn't get a group, then make sure we have a pointer to
// the rootgroup.
if ( ! grp )
grp = Sim : : getRootGroup ( ) ;
// add to the parent group
grp - > addObject ( currentNewObject ) ;
// If for some reason the add failed, add the object to the
// root group so it won't leak.
if ( currentNewObject - > getGroup ( ) = = NULL )
Sim : : getRootGroup ( ) - > addObject ( currentNewObject ) ;
// add to any set we might be in
if ( set )
set - > addObject ( currentNewObject ) ;
}
// store the new object's ID on the stack (overwriting the group/set
// id, if one was given, otherwise getting pushed)
S32 id = currentNewObject - > getId ( ) ;
if ( placeAtRoot )
2021-04-27 02:52:58 +00:00
stack [ _STK ] . setInt ( id ) ;
2021-03-30 23:33:19 +00:00
else
2021-04-27 02:52:58 +00:00
stack [ + + _STK ] . setInt ( id ) ;
2021-03-30 23:33:19 +00:00
break ;
}
case OP_END_OBJECT :
{
// If we're not to be placed at the root, make sure we clean up
// our group reference.
bool placeAtRoot = code [ ip + + ] ;
if ( ! placeAtRoot )
2021-04-16 23:20:15 +00:00
_STK - - ;
2021-03-30 23:33:19 +00:00
break ;
}
case OP_FINISH_OBJECT :
{
if ( currentNewObject )
currentNewObject - > onPostAdd ( ) ;
2021-04-10 19:52:53 +00:00
AssertFatal ( objectCreationStackIndex > = 0 , " Object Stack is empty. " ) ;
2021-03-30 23:33:19 +00:00
// Restore the object info from the stack [7/9/2007 Black]
currentNewObject = objectCreationStack [ - - objectCreationStackIndex ] . newObject ;
failJump = objectCreationStack [ objectCreationStackIndex ] . failJump ;
break ;
}
case OP_JMPIFFNOT :
2021-04-27 02:52:58 +00:00
if ( stack [ _STK - - ] . getFloat ( ) )
2021-03-30 23:33:19 +00:00
{
ip + + ;
break ;
}
ip = code [ ip ] ;
break ;
case OP_JMPIFNOT :
2021-04-27 02:52:58 +00:00
if ( stack [ _STK - - ] . getInt ( ) )
2021-03-30 23:33:19 +00:00
{
ip + + ;
break ;
}
ip = code [ ip ] ;
break ;
case OP_JMPIFF :
2021-04-27 02:52:58 +00:00
if ( ! stack [ _STK - - ] . getFloat ( ) )
2021-03-30 23:33:19 +00:00
{
ip + + ;
break ;
}
ip = code [ ip ] ;
break ;
case OP_JMPIF :
2021-04-27 02:52:58 +00:00
if ( ! stack [ _STK - - ] . getFloat ( ) )
2021-03-30 23:33:19 +00:00
{
ip + + ;
break ;
}
ip = code [ ip ] ;
break ;
case OP_JMPIFNOT_NP :
2021-04-27 02:52:58 +00:00
if ( stack [ _STK ] . getInt ( ) )
2021-03-30 23:33:19 +00:00
{
2021-04-16 23:20:15 +00:00
_STK - - ;
2021-03-30 23:33:19 +00:00
ip + + ;
break ;
}
ip = code [ ip ] ;
break ;
case OP_JMPIF_NP :
2021-04-27 02:52:58 +00:00
if ( ! stack [ _STK ] . getInt ( ) )
2021-03-30 23:33:19 +00:00
{
2021-04-16 23:20:15 +00:00
_STK - - ;
2021-03-30 23:33:19 +00:00
ip + + ;
break ;
}
ip = code [ ip ] ;
break ;
case OP_JMP :
ip = code [ ip ] ;
break ;
case OP_RETURN_VOID :
2021-04-27 02:52:58 +00:00
{
if ( iterDepth > 0 )
{
// Clear iterator state.
while ( iterDepth > 0 )
{
iterStack [ - - _ITER ] . mIsStringIter = false ;
- - iterDepth ;
2021-09-01 02:18:08 +00:00
_STK - - ; // this is a pop from foreach()
}
2021-04-27 02:52:58 +00:00
}
returnValue . setEmptyString ( ) ;
goto execFinished ;
}
2021-03-30 23:33:19 +00:00
case OP_RETURN :
2021-04-03 05:53:40 +00:00
{
2021-09-01 02:18:08 +00:00
returnValue = std : : move ( stack [ _STK ] ) ;
_STK - - ;
// Clear iterator state.
while ( iterDepth > 0 )
2021-03-30 23:33:19 +00:00
{
2021-09-01 02:18:08 +00:00
iterStack [ - - _ITER ] . mIsStringIter = false ;
- - iterDepth ;
2021-03-30 23:33:19 +00:00
2021-04-27 02:52:58 +00:00
_STK - - ;
2021-03-30 23:33:19 +00:00
}
2021-04-03 05:53:40 +00:00
goto execFinished ;
}
2021-03-30 23:33:19 +00:00
case OP_RETURN_FLT :
2021-09-01 02:18:08 +00:00
returnValue . setFloat ( stack [ _STK ] . getFloat ( ) ) ;
_STK - - ;
2021-03-30 23:33:19 +00:00
2021-09-01 02:18:08 +00:00
// Clear iterator state.
while ( iterDepth > 0 )
2021-03-30 23:33:19 +00:00
{
2021-09-01 02:18:08 +00:00
iterStack [ - - _ITER ] . mIsStringIter = false ;
- - iterDepth ;
2021-03-30 23:33:19 +00:00
2021-09-01 02:18:08 +00:00
_STK - - ;
2021-03-30 23:33:19 +00:00
}
goto execFinished ;
case OP_RETURN_UINT :
2021-09-01 02:18:08 +00:00
returnValue . setInt ( stack [ _STK ] . getInt ( ) ) ;
_STK - - ;
2021-03-30 23:33:19 +00:00
2021-09-01 02:18:08 +00:00
// Clear iterator state.
while ( iterDepth > 0 )
2021-03-30 23:33:19 +00:00
{
2021-09-01 02:18:08 +00:00
iterStack [ - - _ITER ] . mIsStringIter = false ;
- - iterDepth ;
2021-03-30 23:33:19 +00:00
2021-09-01 02:18:08 +00:00
_STK - - ;
}
2021-03-30 23:33:19 +00:00
goto execFinished ;
case OP_CMPEQ :
2021-05-01 06:07:54 +00:00
doFloatMathOperation < FloatOperation : : EQ > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_CMPGR :
2021-05-01 06:07:54 +00:00
doFloatMathOperation < FloatOperation : : GR > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_CMPGE :
2021-05-01 06:07:54 +00:00
doFloatMathOperation < FloatOperation : : GE > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_CMPLT :
2021-05-01 06:07:54 +00:00
doFloatMathOperation < FloatOperation : : LT > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_CMPLE :
2021-05-01 06:07:54 +00:00
doFloatMathOperation < FloatOperation : : LE > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_CMPNE :
2021-05-01 06:07:54 +00:00
doFloatMathOperation < FloatOperation : : NE > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_XOR :
2021-05-01 06:07:54 +00:00
doIntOperation < IntegerOperation : : Xor > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_BITAND :
2021-05-01 06:07:54 +00:00
doIntOperation < IntegerOperation : : BitAnd > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_BITOR :
2021-05-01 06:07:54 +00:00
doIntOperation < IntegerOperation : : BitOr > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_NOT :
2023-04-08 17:39:09 +00:00
stack [ _STK ] . setBool ( ! stack [ _STK ] . getInt ( ) ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_NOTF :
2021-04-27 02:52:58 +00:00
stack [ _STK ] . setInt ( ! stack [ _STK ] . getFloat ( ) ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_ONESCOMPLEMENT :
2021-04-27 02:52:58 +00:00
stack [ _STK ] . setInt ( ~ stack [ _STK ] . getInt ( ) ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_SHR :
2021-05-01 06:07:54 +00:00
doIntOperation < IntegerOperation : : RShift > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_SHL :
2021-05-01 06:07:54 +00:00
doIntOperation < IntegerOperation : : LShift > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_AND :
2021-05-01 06:07:54 +00:00
doIntOperation < IntegerOperation : : LogicalAnd > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_OR :
2021-05-01 06:07:54 +00:00
doIntOperation < IntegerOperation : : LogicalOr > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_ADD :
2021-05-01 06:07:54 +00:00
doFloatMathOperation < FloatOperation : : Add > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_SUB :
2021-05-01 06:07:54 +00:00
doFloatMathOperation < FloatOperation : : Sub > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_MUL :
2021-05-01 06:07:54 +00:00
doFloatMathOperation < FloatOperation : : Mul > ( ) ;
2021-03-30 23:33:19 +00:00
break ;
2021-04-27 02:52:58 +00:00
2021-03-30 23:33:19 +00:00
case OP_DIV :
2021-05-01 06:07:54 +00:00
doFloatMathOperation < FloatOperation : : Div > ( ) ;
break ;
case OP_MOD :
{
S64 divisor = stack [ _STK - 1 ] . getInt ( ) ;
if ( divisor ! = 0 )
stack [ _STK - 1 ] . setInt ( stack [ _STK ] . getInt ( ) % divisor ) ;
else
stack [ _STK - 1 ] . setInt ( 0 ) ;
2021-04-16 23:20:15 +00:00
_STK - - ;
2021-03-30 23:33:19 +00:00
break ;
2021-05-01 06:07:54 +00:00
}
2021-04-27 02:52:58 +00:00
2021-03-30 23:33:19 +00:00
case OP_NEG :
2021-04-27 02:52:58 +00:00
stack [ _STK ] . setFloat ( - stack [ _STK ] . getFloat ( ) ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_INC :
reg = code [ ip + + ] ;
2021-09-03 02:21:00 +00:00
currentRegister = reg ;
2021-03-30 23:33:19 +00:00
gEvalState . setLocalFloatVariable ( reg , gEvalState . getLocalFloatVariable ( reg ) + 1.0 ) ;
break ;
case OP_SETCURVAR :
var = CodeToSTE ( code , ip ) ;
ip + = 2 ;
// If a variable is set, then these must be NULL. It is necessary
// to set this here so that the vector parser can appropriately
// identify whether it's dealing with a vector.
2021-09-04 03:27:39 +00:00
prevField = NULL ;
prevObject = NULL ;
2021-03-30 23:33:19 +00:00
curObject = NULL ;
2021-08-17 02:02:24 +00:00
// Used for local variable caching of what is active...when we
// set a global, we aren't active
currentRegister = - 1 ;
2021-03-30 23:33:19 +00:00
gEvalState . setCurVarName ( var ) ;
// In order to let docblocks work properly with variables, we have
// clear the current docblock when we do an assign. This way it
// won't inappropriately carry forward to following function decls.
curFNDocBlock = NULL ;
curNSDocBlock = NULL ;
break ;
case OP_SETCURVAR_CREATE :
var = CodeToSTE ( code , ip ) ;
ip + = 2 ;
// See OP_SETCURVAR
2021-09-04 03:27:39 +00:00
prevField = NULL ;
prevObject = NULL ;
2021-03-30 23:33:19 +00:00
curObject = NULL ;
2021-08-17 02:02:24 +00:00
// Used for local variable caching of what is active...when we
// set a global, we aren't active
currentRegister = - 1 ;
2021-03-30 23:33:19 +00:00
gEvalState . setCurVarNameCreate ( var ) ;
// See OP_SETCURVAR for why we do this.
curFNDocBlock = NULL ;
curNSDocBlock = NULL ;
break ;
case OP_SETCURVAR_ARRAY :
2021-04-27 02:52:58 +00:00
var = StringTable - > insert ( stack [ _STK ] . getString ( ) ) ;
2021-03-30 23:33:19 +00:00
// See OP_SETCURVAR
2021-09-04 03:27:39 +00:00
prevField = NULL ;
prevObject = NULL ;
2021-03-30 23:33:19 +00:00
curObject = NULL ;
2021-08-17 02:02:24 +00:00
// Used for local variable caching of what is active...when we
// set a global, we aren't active
currentRegister = - 1 ;
2021-03-30 23:33:19 +00:00
gEvalState . setCurVarName ( var ) ;
// See OP_SETCURVAR for why we do this.
curFNDocBlock = NULL ;
curNSDocBlock = NULL ;
break ;
case OP_SETCURVAR_ARRAY_CREATE :
2021-04-27 02:52:58 +00:00
var = StringTable - > insert ( stack [ _STK ] . getString ( ) ) ;
2021-03-30 23:33:19 +00:00
// See OP_SETCURVAR
2021-09-04 03:27:39 +00:00
prevField = NULL ;
prevObject = NULL ;
2021-03-30 23:33:19 +00:00
curObject = NULL ;
2021-08-17 02:02:24 +00:00
// Used for local variable caching of what is active...when we
// set a global, we aren't active
currentRegister = - 1 ;
2021-03-30 23:33:19 +00:00
gEvalState . setCurVarNameCreate ( var ) ;
// See OP_SETCURVAR for why we do this.
curFNDocBlock = NULL ;
curNSDocBlock = NULL ;
break ;
case OP_LOADVAR_UINT :
2021-08-17 02:02:24 +00:00
currentRegister = - 1 ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setInt ( gEvalState . getIntVariable ( ) ) ;
2021-04-16 23:20:15 +00:00
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
case OP_LOADVAR_FLT :
2021-08-17 02:02:24 +00:00
currentRegister = - 1 ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setFloat ( gEvalState . getFloatVariable ( ) ) ;
2021-04-16 23:20:15 +00:00
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
case OP_LOADVAR_STR :
2021-08-17 02:02:24 +00:00
currentRegister = - 1 ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setString ( gEvalState . getStringVariable ( ) ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
case OP_SAVEVAR_UINT :
2021-04-27 02:52:58 +00:00
gEvalState . setIntVariable ( stack [ _STK ] . getInt ( ) ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_SAVEVAR_FLT :
2021-04-27 02:52:58 +00:00
gEvalState . setFloatVariable ( stack [ _STK ] . getFloat ( ) ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_SAVEVAR_STR :
2021-04-27 02:52:58 +00:00
gEvalState . setStringVariable ( stack [ _STK ] . getString ( ) ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_LOAD_LOCAL_VAR_UINT :
reg = code [ ip + + ] ;
2021-08-17 02:02:24 +00:00
currentRegister = reg ;
2021-09-04 03:27:39 +00:00
// See OP_SETCURVAR
prevField = NULL ;
prevObject = NULL ;
curObject = NULL ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setInt ( gEvalState . getLocalIntVariable ( reg ) ) ;
2021-04-16 23:20:15 +00:00
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
case OP_LOAD_LOCAL_VAR_FLT :
reg = code [ ip + + ] ;
2021-08-17 02:02:24 +00:00
currentRegister = reg ;
2021-09-04 03:27:39 +00:00
// See OP_SETCURVAR
prevField = NULL ;
prevObject = NULL ;
curObject = NULL ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setFloat ( gEvalState . getLocalFloatVariable ( reg ) ) ;
2021-04-16 23:20:15 +00:00
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
case OP_LOAD_LOCAL_VAR_STR :
reg = code [ ip + + ] ;
2021-08-17 02:02:24 +00:00
currentRegister = reg ;
2021-09-04 03:27:39 +00:00
// See OP_SETCURVAR
prevField = NULL ;
prevObject = NULL ;
curObject = NULL ;
2021-03-30 23:33:19 +00:00
val = gEvalState . getLocalStringVariable ( reg ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setString ( val ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
case OP_SAVE_LOCAL_VAR_UINT :
reg = code [ ip + + ] ;
2021-09-03 02:21:00 +00:00
currentRegister = reg ;
2021-09-04 03:27:39 +00:00
// See OP_SETCURVAR
prevField = NULL ;
prevObject = NULL ;
curObject = NULL ;
2021-04-27 02:52:58 +00:00
gEvalState . setLocalIntVariable ( reg , stack [ _STK ] . getInt ( ) ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_SAVE_LOCAL_VAR_FLT :
reg = code [ ip + + ] ;
2021-09-03 02:21:00 +00:00
currentRegister = reg ;
2021-09-04 03:27:39 +00:00
// See OP_SETCURVAR
prevField = NULL ;
prevObject = NULL ;
curObject = NULL ;
2021-04-27 02:52:58 +00:00
gEvalState . setLocalFloatVariable ( reg , stack [ _STK ] . getFloat ( ) ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_SAVE_LOCAL_VAR_STR :
reg = code [ ip + + ] ;
2021-04-27 02:52:58 +00:00
val = stack [ _STK ] . getString ( ) ;
2021-09-03 02:21:00 +00:00
currentRegister = reg ;
2021-09-04 03:27:39 +00:00
// See OP_SETCURVAR
prevField = NULL ;
prevObject = NULL ;
curObject = NULL ;
2021-04-27 02:52:58 +00:00
gEvalState . setLocalStringVariable ( reg , val , ( S32 ) dStrlen ( val ) ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_SETCUROBJECT :
2021-09-04 03:27:39 +00:00
// Save the previous object for parsing vector fields.
prevObject = curObject ;
2021-04-27 02:52:58 +00:00
val = stack [ _STK ] . getString ( ) ;
2021-03-30 23:33:19 +00:00
// Sim::findObject will sometimes find valid objects from
// multi-component strings. This makes sure that doesn't
// happen.
for ( const char * check = val ; * check ; check + + )
{
if ( * check = = ' ' )
{
val = " " ;
break ;
}
}
curObject = Sim : : findObject ( val ) ;
break ;
case OP_SETCUROBJECT_INTERNAL :
+ + ip ; // To skip the recurse flag if the object wasnt found
if ( curObject )
{
2022-01-21 22:01:44 +00:00
SimSet * set = dynamic_cast < SimSet * > ( curObject ) ;
if ( set )
2021-03-30 23:33:19 +00:00
{
2021-04-27 02:52:58 +00:00
StringTableEntry intName = StringTable - > insert ( stack [ _STK ] . getString ( ) ) ;
2021-03-30 23:33:19 +00:00
bool recurse = code [ ip - 1 ] ;
2022-01-21 22:01:44 +00:00
SimObject * obj = set - > findObjectByInternalName ( intName , recurse ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK ] . setInt ( obj ? obj - > getId ( ) : 0 ) ;
2021-03-30 23:33:19 +00:00
}
else
{
2022-01-21 22:01:44 +00:00
Con : : errorf ( ConsoleLogEntry : : Script , " %s: Attempt to use -> on non-set %s of class %s. " , getFileLine ( ip - 2 ) , curObject - > getName ( ) , curObject - > getClassName ( ) ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK ] . setInt ( 0 ) ;
2021-03-30 23:33:19 +00:00
}
}
2021-08-18 00:52:59 +00:00
else
{
Con : : errorf ( ConsoleLogEntry : : Script , " %s: Attempt to use ->, but the group object wasn't found. " , getFileLine ( ip - 2 ) ) ;
stack [ _STK ] . setInt ( 0 ) ;
}
2021-03-30 23:33:19 +00:00
break ;
case OP_SETCUROBJECT_NEW :
curObject = currentNewObject ;
break ;
case OP_SETCURFIELD :
2021-09-04 03:27:39 +00:00
// Save the previous field for parsing vector fields.
prevField = curField ;
2021-03-30 23:33:19 +00:00
dStrcpy ( prevFieldArray , curFieldArray , 256 ) ;
curField = CodeToSTE ( code , ip ) ;
curFieldArray [ 0 ] = 0 ;
ip + = 2 ;
break ;
case OP_SETCURFIELD_ARRAY :
2021-04-27 02:52:58 +00:00
dStrcpy ( curFieldArray , stack [ _STK ] . getString ( ) , 256 ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_SETCURFIELD_TYPE :
if ( curObject )
curObject - > setDataFieldType ( code [ ip ] , curField , curFieldArray ) ;
ip + + ;
break ;
case OP_LOADFIELD_UINT :
if ( curObject )
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setInt ( dAtol ( curObject - > getDataField ( curField , curFieldArray ) ) ) ;
2021-03-30 23:33:19 +00:00
else
{
// The field is not being retrieved from an object. Maybe it's
// a special accessor?
char buff [ FieldBufferSizeNumeric ] ;
memset ( buff , 0 , sizeof ( buff ) ) ;
2021-09-04 03:27:39 +00:00
getFieldComponent ( prevObject , prevField , prevFieldArray , curField , buff , currentRegister ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setInt ( dAtol ( buff ) ) ;
2021-03-30 23:33:19 +00:00
}
2021-04-16 23:20:15 +00:00
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
case OP_LOADFIELD_FLT :
if ( curObject )
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setFloat ( dAtod ( curObject - > getDataField ( curField , curFieldArray ) ) ) ;
2021-03-30 23:33:19 +00:00
else
{
// The field is not being retrieved from an object. Maybe it's
// a special accessor?
char buff [ FieldBufferSizeNumeric ] ;
memset ( buff , 0 , sizeof ( buff ) ) ;
2021-09-04 03:27:39 +00:00
getFieldComponent ( prevObject , prevField , prevFieldArray , curField , buff , currentRegister ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setFloat ( dAtod ( buff ) ) ;
2021-03-30 23:33:19 +00:00
}
2021-04-16 23:20:15 +00:00
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
case OP_LOADFIELD_STR :
if ( curObject )
{
val = curObject - > getDataField ( curField , curFieldArray ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setString ( val ) ;
2021-03-30 23:33:19 +00:00
}
else
{
// The field is not being retrieved from an object. Maybe it's
// a special accessor?
char buff [ FieldBufferSizeString ] ;
memset ( buff , 0 , sizeof ( buff ) ) ;
2021-09-04 03:27:39 +00:00
getFieldComponent ( prevObject , prevField , prevFieldArray , curField , buff , currentRegister ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setString ( buff ) ;
2021-03-30 23:33:19 +00:00
}
2021-04-27 02:52:58 +00:00
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
case OP_SAVEFIELD_UINT :
if ( curObject )
2021-04-27 02:52:58 +00:00
curObject - > setDataField ( curField , curFieldArray , stack [ _STK ] . getString ( ) ) ;
2021-03-30 23:33:19 +00:00
else
2021-09-04 03:27:39 +00:00
{
// The field is not being set on an object. Maybe it's a special accessor?
setFieldComponent ( prevObject , prevField , prevFieldArray , curField , currentRegister ) ;
prevObject = NULL ;
}
2021-03-30 23:33:19 +00:00
break ;
case OP_SAVEFIELD_FLT :
if ( curObject )
2021-04-27 02:52:58 +00:00
curObject - > setDataField ( curField , curFieldArray , stack [ _STK ] . getString ( ) ) ;
2021-03-30 23:33:19 +00:00
else
2021-09-04 03:27:39 +00:00
{
// The field is not being set on an object. Maybe it's a special accessor?
setFieldComponent ( prevObject , prevField , prevFieldArray , curField , currentRegister ) ;
prevObject = NULL ;
}
2021-03-30 23:33:19 +00:00
break ;
case OP_SAVEFIELD_STR :
if ( curObject )
2021-04-27 02:52:58 +00:00
curObject - > setDataField ( curField , curFieldArray , stack [ _STK ] . getString ( ) ) ;
2021-03-30 23:33:19 +00:00
else
2021-09-04 03:27:39 +00:00
{
// The field is not being set on an object. Maybe it's a special accessor?
setFieldComponent ( prevObject , prevField , prevFieldArray , curField , currentRegister ) ;
prevObject = NULL ;
}
2021-03-30 23:33:19 +00:00
break ;
2021-04-27 02:52:58 +00:00
case OP_POP_STK :
2021-04-16 23:20:15 +00:00
_STK - - ;
2021-03-30 23:33:19 +00:00
break ;
case OP_LOADIMMED_UINT :
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setInt ( code [ ip + + ] ) ;
2021-04-16 23:20:15 +00:00
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
case OP_LOADIMMED_FLT :
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setFloat ( curFloatTable [ code [ ip + + ] ] ) ;
2021-04-16 23:20:15 +00:00
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
2021-04-27 02:52:58 +00:00
2021-03-30 23:33:19 +00:00
case OP_TAG_TO_STR :
code [ ip - 1 ] = OP_LOADIMMED_STR ;
// it's possible the string has already been converted
if ( U8 ( curStringTable [ code [ ip ] ] ) ! = StringTagPrefixByte )
{
U32 id = GameAddTaggedString ( curStringTable + code [ ip ] ) ;
dSprintf ( curStringTable + code [ ip ] + 1 , 7 , " %d " , id ) ;
* ( curStringTable + code [ ip ] ) = StringTagPrefixByte ;
}
2021-04-27 02:52:58 +00:00
TORQUE_CASE_FALLTHROUGH ;
2021-03-30 23:33:19 +00:00
case OP_LOADIMMED_STR :
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setString ( curStringTable + code [ ip + + ] ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
case OP_DOCBLOCK_STR :
{
// If the first word of the doc is '\class' or '@class', then this
// is a namespace doc block, otherwise it is a function doc block.
const char * docblock = curStringTable + code [ ip + + ] ;
const char * sansClass = dStrstr ( docblock , " @class " ) ;
if ( ! sansClass )
sansClass = dStrstr ( docblock , " \\ class " ) ;
if ( sansClass )
{
// Don't save the class declaration. Scan past the 'class'
// keyword and up to the first whitespace.
sansClass + = 7 ;
S32 index = 0 ;
while ( ( * sansClass ! = ' ' ) & & ( * sansClass ! = ' \n ' ) & & * sansClass & & ( index < ( nsDocLength - 1 ) ) )
{
nsDocBlockClass [ index + + ] = * sansClass ;
sansClass + + ;
}
nsDocBlockClass [ index ] = ' \0 ' ;
curNSDocBlock = sansClass + 1 ;
}
else
curFNDocBlock = docblock ;
}
break ;
case OP_LOADIMMED_IDENT :
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setString ( CodeToSTE ( code , ip ) ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
ip + = 2 ;
break ;
case OP_CALLFUNC :
{
// This routingId is set when we query the object as to whether
// it handles this method. It is set to an enum from the table
// above indicating whether it handles it on a component it owns
// or just on the object.
fnName = CodeToSTE ( code , ip ) ;
fnNamespace = CodeToSTE ( code , ip + 2 ) ;
U32 callType = code [ ip + 4 ] ;
//if this is called from inside a function, append the ip and codeptr
if ( ! gEvalState . stack . empty ( ) )
{
2021-08-14 05:37:01 +00:00
gEvalState . getCurrentFrame ( ) . code = this ;
gEvalState . getCurrentFrame ( ) . ip = ip - 1 ;
2021-03-30 23:33:19 +00:00
}
ip + = 5 ;
gCallStack . argvc ( fnName , callArgc , & callArgv ) ;
if ( callType = = FuncCallExprNode : : FunctionCall )
{
// Note: This works even if the function was in a package. Reason being is when
// activatePackage() is called, it swaps the namespaceEntry into the global namespace
// (and reverts it when deactivatePackage is called). Method or Static related ones work
// as expected, as the namespace is resolved on the fly.
nsEntry = Namespace : : global ( ) - > lookup ( fnName ) ;
if ( ! nsEntry )
{
Con : : warnf ( ConsoleLogEntry : : General ,
" %s: Unable to find function %s " ,
getFileLine ( ip - 4 ) , fnName ) ;
2021-04-27 02:52:58 +00:00
2021-03-30 23:33:19 +00:00
gCallStack . popFrame ( ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setEmptyString ( ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
}
}
else if ( callType = = FuncCallExprNode : : StaticCall )
{
// Try to look it up.
ns = Namespace : : find ( fnNamespace ) ;
nsEntry = ns - > lookup ( fnName ) ;
if ( ! nsEntry )
{
Con : : warnf ( ConsoleLogEntry : : General ,
" %s: Unable to find function %s%s%s " ,
getFileLine ( ip - 4 ) , fnNamespace ? fnNamespace : " " ,
fnNamespace ? " :: " : " " , fnName ) ;
2021-04-27 02:52:58 +00:00
2021-03-30 23:33:19 +00:00
gCallStack . popFrame ( ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setEmptyString ( ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
}
}
else if ( callType = = FuncCallExprNode : : MethodCall )
{
saveObject = gEvalState . thisObject ;
// Optimization: If we're an integer, we can lookup the value by SimObjectId
const ConsoleValue & simObjectLookupValue = callArgv [ 1 ] ;
if ( simObjectLookupValue . getType ( ) = = ConsoleValueType : : cvInteger )
2021-05-01 06:55:24 +00:00
gEvalState . thisObject = Sim : : findObject ( static_cast < SimObjectId > ( simObjectLookupValue . getFastInt ( ) ) ) ;
2021-03-30 23:33:19 +00:00
else
2021-04-17 18:31:27 +00:00
{
SimObject * foundObject = Sim : : findObject ( simObjectLookupValue . getString ( ) ) ;
// Optimization: If we're not an integer, let's make it so that the fast path exists
// on the first argument of the method call (speeds up future usage of %this, for example)
if ( foundObject ! = NULL )
callArgv [ 1 ] . setInt ( static_cast < S64 > ( foundObject - > getId ( ) ) ) ;
gEvalState . thisObject = foundObject ;
}
2021-03-30 23:33:19 +00:00
if ( gEvalState . thisObject = = NULL )
{
Con : : warnf (
ConsoleLogEntry : : General ,
" %s: Unable to find object: '%s' attempting to call function '%s' " ,
getFileLine ( ip - 6 ) ,
simObjectLookupValue . getString ( ) ,
fnName
) ;
2021-04-27 02:52:58 +00:00
2021-03-30 23:33:19 +00:00
gCallStack . popFrame ( ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setEmptyString ( ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
}
ns = gEvalState . thisObject - > getNamespace ( ) ;
if ( ns )
nsEntry = ns - > lookup ( fnName ) ;
else
nsEntry = NULL ;
}
else // it's a ParentCall
{
if ( thisNamespace )
{
ns = thisNamespace - > mParent ;
if ( ns )
nsEntry = ns - > lookup ( fnName ) ;
else
nsEntry = NULL ;
}
else
{
ns = NULL ;
nsEntry = NULL ;
}
}
if ( ! nsEntry | | noCalls )
{
if ( ! noCalls )
{
Con : : warnf ( ConsoleLogEntry : : General , " %s: Unknown command %s. " , getFileLine ( ip - 4 ) , fnName ) ;
if ( callType = = FuncCallExprNode : : MethodCall )
{
Con : : warnf ( ConsoleLogEntry : : General , " Object %s(%d) %s " ,
gEvalState . thisObject - > getName ( ) ? gEvalState . thisObject - > getName ( ) : " " ,
gEvalState . thisObject - > getId ( ) , Con : : getNamespaceList ( ns ) ) ;
}
}
gCallStack . popFrame ( ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setEmptyString ( ) ;
_STK + + ;
2017-11-06 04:33:32 +00:00
break ;
2021-03-30 23:33:19 +00:00
}
if ( nsEntry - > mType = = Namespace : : Entry : : ConsoleFunctionType )
{
if ( nsEntry - > mFunctionOffset )
{
2021-04-03 05:53:40 +00:00
ConsoleValue returnFromFn = nsEntry - > mCode - > exec ( nsEntry - > mFunctionOffset , fnName , nsEntry - > mNamespace , callArgc , callArgv , false , nsEntry - > mPackage ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] = std : : move ( returnFromFn ) ;
2021-03-30 23:33:19 +00:00
}
else // no body
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setEmptyString ( ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
gCallStack . popFrame ( ) ;
}
else
{
if ( ( nsEntry - > mMinArgs & & S32 ( callArgc ) < nsEntry - > mMinArgs ) | | ( nsEntry - > mMaxArgs & & S32 ( callArgc ) > nsEntry - > mMaxArgs ) )
{
const char * nsName = ns ? ns - > mName : " " ;
Con : : warnf ( ConsoleLogEntry : : Script , " %s: %s::%s - wrong number of arguments. " , getFileLine ( ip - 4 ) , nsName , fnName ) ;
Con : : warnf ( ConsoleLogEntry : : Script , " %s: usage: %s " , getFileLine ( ip - 4 ) , nsEntry - > mUsage ) ;
gCallStack . popFrame ( ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setEmptyString ( ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
}
else
{
switch ( nsEntry - > mType )
{
case Namespace : : Entry : : StringCallbackType :
{
2021-04-27 02:52:58 +00:00
const char * result = nsEntry - > cb . mStringCallbackFunc ( gEvalState . thisObject , callArgc , callArgv ) ;
2021-03-30 23:33:19 +00:00
gCallStack . popFrame ( ) ;
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setString ( result ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
}
case Namespace : : Entry : : IntCallbackType :
{
2021-04-16 23:20:15 +00:00
S64 result = nsEntry - > cb . mIntCallbackFunc ( gEvalState . thisObject , callArgc , callArgv ) ;
2021-03-30 23:33:19 +00:00
gCallStack . popFrame ( ) ;
2021-04-27 02:52:58 +00:00
if ( code [ ip ] = = OP_POP_STK )
2021-03-30 23:33:19 +00:00
{
ip + + ;
break ;
}
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setInt ( result ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
}
case Namespace : : Entry : : FloatCallbackType :
{
F64 result = nsEntry - > cb . mFloatCallbackFunc ( gEvalState . thisObject , callArgc , callArgv ) ;
gCallStack . popFrame ( ) ;
2021-04-27 02:52:58 +00:00
if ( code [ ip ] = = OP_POP_STK )
2021-03-30 23:33:19 +00:00
{
ip + + ;
break ;
}
2021-04-27 02:52:58 +00:00
2021-09-05 02:00:32 +00:00
stack [ _STK + 1 ] . setFloat ( result ) ;
2021-04-27 02:52:58 +00:00
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
}
case Namespace : : Entry : : VoidCallbackType :
{
nsEntry - > cb . mVoidCallbackFunc ( gEvalState . thisObject , callArgc , callArgv ) ;
gCallStack . popFrame ( ) ;
2021-04-27 02:52:58 +00:00
if ( code [ ip ] = = OP_POP_STK )
{
ip + + ;
break ;
}
2021-12-09 02:00:50 +00:00
if ( Con : : getBoolVariable ( " $Con::warnVoidAssignment " , true ) )
{
Con : : warnf ( ConsoleLogEntry : : General , " %s: Call to %s in %s uses result of void function call. " , getFileLine ( ip - 4 ) , fnName , functionName ) ;
}
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setEmptyString ( ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
}
case Namespace : : Entry : : BoolCallbackType :
{
bool result = nsEntry - > cb . mBoolCallbackFunc ( gEvalState . thisObject , callArgc , callArgv ) ;
gCallStack . popFrame ( ) ;
2021-04-27 02:52:58 +00:00
if ( code [ ip ] = = OP_POP_STK )
2021-03-30 23:33:19 +00:00
{
ip + + ;
break ;
}
2021-04-27 02:52:58 +00:00
stack [ _STK + 1 ] . setBool ( result ) ;
_STK + + ;
2021-03-30 23:33:19 +00:00
break ;
}
}
}
}
if ( callType = = FuncCallExprNode : : MethodCall )
gEvalState . thisObject = saveObject ;
break ;
}
2021-04-27 02:52:58 +00:00
2021-03-30 23:33:19 +00:00
case OP_ADVANCE_STR_APPENDCHAR :
2021-04-27 02:52:58 +00:00
{
char buff [ 2 ] ;
buff [ 0 ] = ( char ) code [ ip + + ] ;
buff [ 1 ] = ' \0 ' ;
2021-04-30 05:20:01 +00:00
S32 len ;
const char * concat = tsconcat ( stack [ _STK ] . getString ( ) , buff , len ) ;
2021-03-30 23:33:19 +00:00
2021-04-30 05:20:01 +00:00
stack [ _STK ] . setStringRef ( concat , len ) ;
2021-03-30 23:33:19 +00:00
break ;
2021-04-27 02:52:58 +00:00
}
2021-03-30 23:33:19 +00:00
2021-04-27 02:52:58 +00:00
case OP_REWIND_STR :
TORQUE_CASE_FALLTHROUGH ;
2021-03-30 23:33:19 +00:00
case OP_TERMINATE_REWIND_STR :
2021-04-30 05:20:01 +00:00
{
S32 len ;
const char * concat = tsconcat ( stack [ _STK - 1 ] . getString ( ) , stack [ _STK ] . getString ( ) , len ) ;
stack [ _STK - 1 ] . setStringRef ( concat , len ) ;
2021-04-27 02:52:58 +00:00
_STK - - ;
2021-03-30 23:33:19 +00:00
break ;
2021-04-30 05:20:01 +00:00
}
2021-03-30 23:33:19 +00:00
case OP_COMPARE_STR :
2021-04-27 02:52:58 +00:00
stack [ _STK - 1 ] . setBool ( ! dStricmp ( stack [ _STK ] . getString ( ) , stack [ _STK - 1 ] . getString ( ) ) ) ;
_STK - - ;
2021-03-30 23:33:19 +00:00
break ;
case OP_PUSH :
2021-04-27 02:52:58 +00:00
gCallStack . push ( std : : move ( stack [ _STK - - ] ) ) ;
2021-03-30 23:33:19 +00:00
break ;
case OP_PUSH_FRAME :
gCallStack . pushFrame ( code [ ip + + ] ) ;
break ;
case OP_ASSERT :
{
2021-04-27 02:52:58 +00:00
if ( ! stack [ _STK - - ] . getBool ( ) )
2021-03-30 23:33:19 +00:00
{
const char * message = curStringTable + code [ ip ] ;
U32 breakLine , inst ;
findBreakLine ( ip - 1 , breakLine , inst ) ;
if ( PlatformAssert : : processAssert ( PlatformAssert : : Fatal ,
name ? name : " eval " ,
breakLine ,
message ) )
{
if ( TelDebugger & & TelDebugger - > isConnected ( ) & & breakLine > 0 )
{
TelDebugger - > breakProcess ( ) ;
}
else
Platform : : debugBreak ( ) ;
}
}
ip + + ;
break ;
}
case OP_BREAK :
{
//append the ip and codeptr before managing the breakpoint!
AssertFatal ( ! gEvalState . stack . empty ( ) , " Empty eval stack on break! " ) ;
2021-08-14 05:37:01 +00:00
gEvalState . getCurrentFrame ( ) . code = this ;
gEvalState . getCurrentFrame ( ) . ip = ip - 1 ;
2021-03-30 23:33:19 +00:00
U32 breakLine ;
findBreakLine ( ip - 1 , breakLine , instruction ) ;
if ( ! breakLine )
goto breakContinue ;
TelDebugger - > executionStopped ( this , breakLine ) ;
goto breakContinue ;
}
case OP_ITER_BEGIN_STR :
{
iterStack [ _ITER ] . mIsStringIter = true ;
2021-04-27 02:52:58 +00:00
TORQUE_CASE_FALLTHROUGH ;
2021-03-30 23:33:19 +00:00
}
case OP_ITER_BEGIN :
{
2021-04-04 04:50:37 +00:00
bool isGlobal = code [ ip ] ;
2021-09-05 02:00:32 +00:00
U32 failIp = code [ ip + ( isGlobal ? 3 : 2 ) ] ;
2021-03-30 23:33:19 +00:00
IterStackRecord & iter = iterStack [ _ITER ] ;
2021-04-04 04:50:37 +00:00
iter . mIsGlobalVariable = isGlobal ;
2021-03-30 23:33:19 +00:00
2021-04-04 04:50:37 +00:00
if ( isGlobal )
{
StringTableEntry varName = CodeToSTE ( code , ip + 1 ) ;
iter . mVar . mVariable = gEvalState . globalVars . add ( varName ) ;
}
else
{
iter . mVar . mRegister = code [ ip + 1 ] ;
}
2021-03-30 23:33:19 +00:00
if ( iter . mIsStringIter )
{
2021-04-27 02:52:58 +00:00
iter . mData . mStr . mString = stack [ _STK ] . getString ( ) ;
2021-03-30 23:33:19 +00:00
iter . mData . mStr . mIndex = 0 ;
}
else
{
// Look up the object.
SimSet * set ;
2021-04-27 02:52:58 +00:00
if ( ! Sim : : findObject ( stack [ _STK ] . getString ( ) , set ) )
2021-03-30 23:33:19 +00:00
{
2021-04-27 02:52:58 +00:00
Con : : errorf ( ConsoleLogEntry : : General , " No SimSet object '%s' " , stack [ _STK ] . getString ( ) ) ;
2021-03-30 23:33:19 +00:00
Con : : errorf ( ConsoleLogEntry : : General , " Did you mean to use 'foreach$' instead of 'foreach'? " ) ;
ip = failIp ;
continue ;
}
// Set up.
iter . mData . mObj . mSet = set ;
iter . mData . mObj . mIndex = 0 ;
}
_ITER + + ;
iterDepth + + ;
2021-04-04 04:50:37 +00:00
ip + = isGlobal ? 4 : 3 ;
2021-03-30 23:33:19 +00:00
break ;
}
case OP_ITER :
{
U32 breakIp = code [ ip ] ;
IterStackRecord & iter = iterStack [ _ITER - 1 ] ;
if ( iter . mIsStringIter )
{
const char * str = iter . mData . mStr . mString ;
U32 startIndex = iter . mData . mStr . mIndex ;
U32 endIndex = startIndex ;
// Break if at end.
if ( ! str [ startIndex ] )
{
ip = breakIp ;
continue ;
}
// Find right end of current component.
if ( ! dIsspace ( str [ endIndex ] ) )
do + + endIndex ;
while ( str [ endIndex ] & & ! dIsspace ( str [ endIndex ] ) ) ;
// Extract component.
if ( endIndex ! = startIndex )
{
char savedChar = str [ endIndex ] ;
const_cast < char * > ( str ) [ endIndex ] = ' \0 ' ; // We are on the string stack so this is okay.
2021-04-04 04:50:37 +00:00
if ( iter . mIsGlobalVariable )
iter . mVar . mVariable - > setStringValue ( & str [ startIndex ] ) ;
else
gEvalState . setLocalStringVariable ( iter . mVar . mRegister , & str [ startIndex ] , endIndex - startIndex ) ;
2021-03-30 23:33:19 +00:00
const_cast < char * > ( str ) [ endIndex ] = savedChar ;
}
else
2021-04-04 04:50:37 +00:00
{
if ( iter . mIsGlobalVariable )
iter . mVar . mVariable - > setStringValue ( " " ) ;
else
gEvalState . setLocalStringVariable ( iter . mVar . mRegister , " " , 0 ) ;
}
2021-03-30 23:33:19 +00:00
// Skip separator.
if ( str [ endIndex ] ! = ' \0 ' )
+ + endIndex ;
iter . mData . mStr . mIndex = endIndex ;
}
else
{
U32 index = iter . mData . mObj . mIndex ;
SimSet * set = iter . mData . mObj . mSet ;
if ( index > = set - > size ( ) )
{
ip = breakIp ;
continue ;
}
2021-04-04 04:50:37 +00:00
SimObjectId id = set - > at ( index ) - > getId ( ) ;
if ( iter . mIsGlobalVariable )
iter . mVar . mVariable - > setIntValue ( id ) ;
else
gEvalState . setLocalIntVariable ( iter . mVar . mRegister , id ) ;
2021-03-30 23:33:19 +00:00
iter . mData . mObj . mIndex = index + 1 ;
}
+ + ip ;
break ;
}
case OP_ITER_END :
{
- - _ITER ;
- - iterDepth ;
2021-04-27 02:52:58 +00:00
_STK - - ;
2021-03-30 23:33:19 +00:00
iterStack [ _ITER ] . mIsStringIter = false ;
break ;
}
case OP_INVALID :
2021-04-27 02:52:58 +00:00
TORQUE_CASE_FALLTHROUGH ;
2021-03-30 23:33:19 +00:00
default :
// error!
2021-04-27 02:52:58 +00:00
AssertISV ( false , " Invalid OPCode Processed! " ) ;
2021-03-30 23:33:19 +00:00
goto execFinished ;
2017-01-06 23:04:28 +00:00
}
2012-10-04 16:58:43 +00:00
}
2021-03-30 23:33:19 +00:00
execFinished :
2012-10-04 16:58:43 +00:00
2021-03-30 23:33:19 +00:00
if ( telDebuggerOn & & setFrame < 0 )
TelDebugger - > popStackFrame ( ) ;
2012-09-19 15:15:01 +00:00
2021-03-30 23:33:19 +00:00
if ( popFrame )
{
gEvalState . popFrame ( ) ;
}
2012-09-19 15:15:01 +00:00
2021-03-30 23:33:19 +00:00
if ( argv )
{
if ( gEvalState . traceOn )
{
traceBuffer [ 0 ] = 0 ;
dStrcat ( traceBuffer , " Leaving " , TRACE_BUFFER_SIZE ) ;
if ( packageName )
{
dStrcat ( traceBuffer , " [ " , TRACE_BUFFER_SIZE ) ;
dStrcat ( traceBuffer , packageName , TRACE_BUFFER_SIZE ) ;
dStrcat ( traceBuffer , " ] " , TRACE_BUFFER_SIZE ) ;
}
if ( thisNamespace & & thisNamespace - > mName )
{
2023-04-27 21:10:04 +00:00
dSprintf ( traceBuffer + ( U32 ) dStrlen ( traceBuffer ) , sizeof ( traceBuffer ) - ( U32 ) dStrlen ( traceBuffer ) ,
2021-03-30 23:33:19 +00:00
" %s::%s() - return %s " , thisNamespace - > mName , thisFunctionName , returnValue . getString ( ) ) ;
}
else
{
2023-04-27 21:10:04 +00:00
dSprintf ( traceBuffer + ( U32 ) dStrlen ( traceBuffer ) , sizeof ( traceBuffer ) - ( U32 ) dStrlen ( traceBuffer ) ,
2021-03-30 23:33:19 +00:00
" %s() - return %s " , thisFunctionName , returnValue . getString ( ) ) ;
}
Con : : printf ( " %s " , traceBuffer ) ;
}
}
else
{
delete [ ] const_cast < char * > ( globalStrings ) ;
delete [ ] globalFloats ;
globalStrings = NULL ;
globalFloats = NULL ;
}
smCurrentCodeBlock = saveCodeBlock ;
if ( saveCodeBlock & & saveCodeBlock - > name )
{
Con : : gCurrentFile = saveCodeBlock - > name ;
Con : : gCurrentRoot = saveCodeBlock - > modPath ;
}
decRefCount ( ) ;
# ifdef TORQUE_DEBUG
2021-04-27 02:52:58 +00:00
AssertFatal ( ! ( _STK > stackStart ) , " String stack not popped enough in script exec " ) ;
AssertFatal ( ! ( _STK < stackStart ) , " String stack popped too much in script exec " ) ;
2021-03-30 23:33:19 +00:00
# endif
2021-04-01 02:10:55 +00:00
2023-05-01 15:13:12 +00:00
return returnValue ;
2012-09-19 15:15:01 +00:00
}
//------------------------------------------------------------