2012-09-19 15:15:01 +00:00
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// 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"
# ifndef TORQUE_TGB_ONLY
# include "materials/materialDefinition.h"
# include "materials/materialManager.h"
# endif
2014-09-07 21:49:45 +00:00
// Uncomment to optimize function calls at the expense of potential invalid package lookups
//#define COMPILER_OPTIMIZE_FUNCTION_CALLS
2012-09-19 15:15:01 +00:00
using namespace Compiler ;
enum EvalConstants {
MaxStackSize = 1024 ,
MethodOnComponent = - 2
} ;
namespace Con
{
// Current script file name and root, these are registered as
// console variables.
extern StringTableEntry gCurrentFile ;
extern StringTableEntry gCurrentRoot ;
extern S32 gObjectCopyFailures ;
}
/// 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 ;
/// The iterator variable.
Dictionary : : Entry * mVariable ;
/// 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 ;
} ;
IterStackRecord iterStack [ MaxStackSize ] ;
F64 floatStack [ MaxStackSize ] ;
S64 intStack [ MaxStackSize ] ;
2012-09-23 08:59:48 +00:00
2012-09-19 15:15:01 +00:00
StringStack STR ;
2012-09-23 08:59:48 +00:00
ConsoleValueStack CSTK ;
2012-09-19 15:15:01 +00:00
U32 _FLT = 0 ; ///< Stack pointer for floatStack.
U32 _UINT = 0 ; ///< Stack pointer for intStack.
U32 _ITER = 0 ; ///< Stack pointer for iterStack.
namespace Con
{
const char * getNamespaceList ( Namespace * ns )
{
U32 size = 1 ;
Namespace * walk ;
for ( walk = ns ; walk ; walk = walk - > mParent )
size + = dStrlen ( walk - > mName ) + 4 ;
char * ret = Con : : getReturnBuffer ( size ) ;
ret [ 0 ] = 0 ;
for ( walk = ns ; walk ; walk = walk - > mParent )
{
dStrcat ( ret , walk - > mName ) ;
if ( walk - > mParent )
dStrcat ( ret , " -> " ) ;
}
return ret ;
}
}
//------------------------------------------------------------
F64 consoleStringToNumber ( const char * str , StringTableEntry file , U32 line )
{
F64 val = dAtof ( str ) ;
if ( val ! = 0 )
return val ;
else if ( ! dStricmp ( str , " true " ) )
return 1 ;
else if ( ! dStricmp ( str , " false " ) )
return 0 ;
else if ( file )
{
Con : : warnf ( ConsoleLogEntry : : General , " %s (%d): string always evaluates to 0. " , file , line ) ;
return 0 ;
}
return 0 ;
}
//------------------------------------------------------------
namespace Con
{
char * getReturnBuffer ( U32 bufferSize )
{
return STR . getReturnBuffer ( bufferSize ) ;
}
char * getReturnBuffer ( const char * stringToCopy )
{
U32 len = dStrlen ( stringToCopy ) + 1 ;
char * ret = STR . getReturnBuffer ( len ) ;
dMemcpy ( ret , stringToCopy , len ) ;
return ret ;
}
char * getReturnBuffer ( const String & str )
{
const U32 size = str . size ( ) ;
char * ret = STR . getReturnBuffer ( size ) ;
dMemcpy ( ret , str . c_str ( ) , size ) ;
return ret ;
}
char * getReturnBuffer ( const StringBuilder & str )
{
char * buffer = Con : : getReturnBuffer ( str . length ( ) + 1 ) ;
str . copy ( buffer ) ;
buffer [ str . length ( ) ] = ' \0 ' ;
return buffer ;
}
char * getArgBuffer ( U32 bufferSize )
{
return STR . getArgBuffer ( bufferSize ) ;
}
2012-10-11 20:29:39 +00:00
ConsoleValueRef getFloatArg ( F64 arg )
2012-09-19 15:15:01 +00:00
{
2012-10-11 20:29:39 +00:00
ConsoleValueRef ref = arg ;
return ref ;
2012-09-19 15:15:01 +00:00
}
2012-10-11 20:29:39 +00:00
ConsoleValueRef getIntArg ( S32 arg )
2012-09-19 15:15:01 +00:00
{
2012-10-11 20:29:39 +00:00
ConsoleValueRef ref = arg ;
return ref ;
2012-09-19 15:15:01 +00:00
}
char * getStringArg ( const char * arg )
{
U32 len = dStrlen ( arg ) + 1 ;
char * ret = STR . getArgBuffer ( len ) ;
dMemcpy ( ret , arg , len ) ;
return ret ;
}
char * getStringArg ( const String & arg )
{
const U32 size = arg . size ( ) ;
char * ret = STR . getArgBuffer ( size ) ;
dMemcpy ( ret , arg . c_str ( ) , size ) ;
return ret ;
}
}
//------------------------------------------------------------
inline void ExprEvalState : : setCurVarName ( StringTableEntry name )
{
if ( name [ 0 ] = = ' $ ' )
currentVariable = globalVars . lookup ( name ) ;
else if ( getStackDepth ( ) > 0 )
currentVariable = getCurrentFrame ( ) . lookup ( name ) ;
if ( ! currentVariable & & gWarnUndefinedScriptVariables )
Con : : warnf ( ConsoleLogEntry : : Script , " Variable referenced before assignment: %s " , name ) ;
}
inline void ExprEvalState : : setCurVarNameCreate ( StringTableEntry name )
{
if ( name [ 0 ] = = ' $ ' )
currentVariable = globalVars . add ( name ) ;
else if ( getStackDepth ( ) > 0 )
currentVariable = getCurrentFrame ( ) . add ( name ) ;
else
{
currentVariable = NULL ;
Con : : warnf ( ConsoleLogEntry : : Script , " Accessing local variable in global scope... failed: %s " , name ) ;
}
}
//------------------------------------------------------------
inline S32 ExprEvalState : : getIntVariable ( )
{
return currentVariable ? currentVariable - > getIntValue ( ) : 0 ;
}
inline F64 ExprEvalState : : getFloatVariable ( )
{
return currentVariable ? currentVariable - > getFloatValue ( ) : 0 ;
}
inline const char * ExprEvalState : : getStringVariable ( )
{
return currentVariable ? currentVariable - > getStringValue ( ) : " " ;
}
//------------------------------------------------------------
inline void ExprEvalState : : setIntVariable ( S32 val )
{
AssertFatal ( currentVariable ! = NULL , " Invalid evaluator state - trying to set null variable! " ) ;
currentVariable - > setIntValue ( val ) ;
}
inline void ExprEvalState : : setFloatVariable ( F64 val )
{
AssertFatal ( currentVariable ! = NULL , " Invalid evaluator state - trying to set null variable! " ) ;
currentVariable - > setFloatValue ( val ) ;
}
inline void ExprEvalState : : setStringVariable ( const char * val )
{
AssertFatal ( currentVariable ! = NULL , " Invalid evaluator state - trying to set null variable! " ) ;
currentVariable - > setStringValue ( val ) ;
}
2012-10-04 16:58:43 +00:00
inline void ExprEvalState : : setCopyVariable ( )
{
2012-10-11 20:29:39 +00:00
if ( copyVariable )
{
2012-10-04 16:58:43 +00:00
switch ( copyVariable - > value . type )
{
case ConsoleValue : : TypeInternalInt :
currentVariable - > setIntValue ( copyVariable - > getIntValue ( ) ) ;
break ;
case ConsoleValue : : TypeInternalFloat :
currentVariable - > setFloatValue ( copyVariable - > getFloatValue ( ) ) ;
break ;
default :
currentVariable - > setStringValue ( copyVariable - > getStringValue ( ) ) ;
break ;
}
}
}
2012-09-19 15:15:01 +00:00
//------------------------------------------------------------
// Gets a component of an object's field value or a variable and returns it
// in val.
static void getFieldComponent ( SimObject * object , StringTableEntry field , const char * array , StringTableEntry subField , char val [ ] )
{
const char * prevVal = NULL ;
// Grab value from object.
if ( object & & field )
prevVal = object - > getDataField ( field , array ) ;
// Otherwise, grab from the string stack. The value coming in will always
// be a string because that is how multicomponent variables are handled.
else
prevVal = STR . getStringValue ( ) ;
// 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.
if ( subField = = xyzw [ 0 ] | | subField = = rgba [ 0 ] )
dStrcpy ( val , StringUnit : : getUnit ( prevVal , 0 , " \t \n " ) ) ;
else if ( subField = = xyzw [ 1 ] | | subField = = rgba [ 1 ] )
dStrcpy ( val , StringUnit : : getUnit ( prevVal , 1 , " \t \n " ) ) ;
else if ( subField = = xyzw [ 2 ] | | subField = = rgba [ 2 ] )
dStrcpy ( val , StringUnit : : getUnit ( prevVal , 2 , " \t \n " ) ) ;
else if ( subField = = xyzw [ 3 ] | | subField = = rgba [ 3 ] )
dStrcpy ( val , StringUnit : : getUnit ( prevVal , 3 , " \t \n " ) ) ;
else
val [ 0 ] = 0 ;
}
else
val [ 0 ] = 0 ;
}
// Sets a component of an object's field value based on the sub field. 'x' will
// set the first field, 'y' the second, and 'z' the third.
static void setFieldComponent ( SimObject * object , StringTableEntry field , const char * array , StringTableEntry subField )
{
// Copy the current string value
char strValue [ 1024 ] ;
dStrncpy ( strValue , STR . getStringValue ( ) , 1024 ) ;
char val [ 1024 ] = " " ;
const char * prevVal = NULL ;
// Set the value on an object field.
if ( object & & field )
prevVal = object - > getDataField ( field , array ) ;
// 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 " ) ) ;
else if ( subField = = xyzw [ 1 ] | | subField = = rgba [ 1 ] )
dStrcpy ( val , StringUnit : : setUnit ( prevVal , 1 , strValue , " \t \n " ) ) ;
else if ( subField = = xyzw [ 2 ] | | subField = = rgba [ 2 ] )
dStrcpy ( val , StringUnit : : setUnit ( prevVal , 2 , strValue , " \t \n " ) ) ;
else if ( subField = = xyzw [ 3 ] | | subField = = rgba [ 3 ] )
dStrcpy ( val , StringUnit : : setUnit ( prevVal , 3 , strValue , " \t \n " ) ) ;
if ( val [ 0 ] ! = 0 )
{
// Update the field or variable.
if ( object & & field )
object - > setDataField ( field , 0 , val ) ;
else if ( gEvalState . currentVariable )
gEvalState . setStringVariable ( val ) ;
}
}
2012-09-23 08:59:48 +00:00
ConsoleValueRef CodeBlock : : exec ( U32 ip , const char * functionName , Namespace * thisNamespace , U32 argc , ConsoleValueRef * argv , bool noCalls , StringTableEntry packageName , S32 setFrame )
2012-09-19 15:15:01 +00:00
{
# ifdef TORQUE_DEBUG
U32 stackStart = STR . mStartStackSize ;
2012-09-23 08:59:48 +00:00
U32 consoleStackStart = CSTK . mStackPos ;
2012-09-19 15:15:01 +00:00
# endif
static char traceBuffer [ 1024 ] ;
2012-09-23 08:59:48 +00:00
S32 i ;
2012-09-19 15:15:01 +00:00
U32 iterDepth = 0 ;
incRefCount ( ) ;
F64 * curFloatTable ;
char * curStringTable ;
S32 curStringTableLen = 0 ; //clint to ensure we dont overwrite it
STR . clearFunctionOffset ( ) ;
StringTableEntry thisFunctionName = NULL ;
bool popFrame = false ;
if ( argv )
{
// assume this points into a function decl:
2014-09-07 16:38:35 +00:00
U32 fnArgc = code [ ip + 2 + 6 ] ;
thisFunctionName = CodeToSTE ( code , ip ) ;
2012-09-23 08:59:48 +00:00
S32 wantedArgc = getMin ( argc - 1 , fnArgc ) ; // argv[0] is func name
2012-09-19 15:15:01 +00:00
if ( gEvalState . traceOn )
{
traceBuffer [ 0 ] = 0 ;
dStrcat ( traceBuffer , " Entering " ) ;
if ( packageName )
{
dStrcat ( traceBuffer , " [ " ) ;
dStrcat ( traceBuffer , packageName ) ;
dStrcat ( traceBuffer , " ] " ) ;
}
if ( thisNamespace & & thisNamespace - > mName )
{
dSprintf ( traceBuffer + dStrlen ( traceBuffer ) , sizeof ( traceBuffer ) - dStrlen ( traceBuffer ) ,
" %s::%s( " , thisNamespace - > mName , thisFunctionName ) ;
}
else
{
dSprintf ( traceBuffer + dStrlen ( traceBuffer ) , sizeof ( traceBuffer ) - dStrlen ( traceBuffer ) ,
" %s( " , thisFunctionName ) ;
}
2014-11-20 20:38:17 +00:00
for ( i = 0 ; i < wantedArgc ; i + + )
2012-09-19 15:15:01 +00:00
{
2014-11-20 20:38:17 +00:00
dStrcat ( traceBuffer , argv [ i + 1 ] ) ;
if ( i ! = wantedArgc - 1 )
dStrcat ( traceBuffer , " , " ) ;
2012-09-19 15:15:01 +00:00
}
dStrcat ( traceBuffer , " ) " ) ;
Con : : printf ( " %s " , traceBuffer ) ;
}
gEvalState . pushFrame ( thisFunctionName , thisNamespace ) ;
popFrame = true ;
2012-09-23 08:59:48 +00:00
for ( i = 0 ; i < wantedArgc ; i + + )
2012-09-19 15:15:01 +00:00
{
2014-09-07 16:38:35 +00:00
StringTableEntry var = CodeToSTE ( code , ip + ( 2 + 6 + 1 ) + ( i * 2 ) ) ;
2012-09-19 15:15:01 +00:00
gEvalState . setCurVarNameCreate ( var ) ;
2012-09-23 08:59:48 +00:00
2012-10-11 20:29:39 +00:00
ConsoleValueRef ref = argv [ i + 1 ] ;
2012-09-23 08:59:48 +00:00
2012-10-11 20:29:39 +00:00
if ( argv [ i + 1 ] . isString ( ) )
gEvalState . setStringVariable ( argv [ i + 1 ] ) ;
else if ( argv [ i + 1 ] . isInt ( ) )
gEvalState . setIntVariable ( argv [ i + 1 ] ) ;
else if ( argv [ i + 1 ] . isFloat ( ) )
gEvalState . setFloatVariable ( argv [ i + 1 ] ) ;
else
gEvalState . setStringVariable ( argv [ i + 1 ] ) ;
2012-09-19 15:15:01 +00:00
}
2014-09-07 16:38:35 +00:00
ip = ip + ( fnArgc * 2 ) + ( 2 + 6 + 1 ) ;
2012-09-19 15:15:01 +00:00
curFloatTable = functionFloats ;
curStringTable = functionStrings ;
curStringTableLen = functionStringsMaxLen ;
}
else
{
curFloatTable = globalFloats ;
curStringTable = globalStrings ;
curStringTableLen = globalStringsMaxLen ;
// 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 ;
// Do we want this code to execute using a new stack frame?
if ( setFrame < 0 )
{
gEvalState . pushFrame ( NULL , NULL ) ;
popFrame = true ;
}
else
{
// 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.
S32 stackIndex = gEvalState . getStackDepth ( ) - setFrame - 1 ;
gEvalState . pushFrameRef ( stackIndex ) ;
popFrame = true ;
}
}
2012-10-11 20:29:39 +00:00
// Reset the console stack frame which at this point will contain
2012-09-23 08:59:48 +00:00
// either nothing or argv[] which we just copied
CSTK . resetFrame ( ) ;
2012-09-19 15:15:01 +00:00
// 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 ;
StringTableEntry fnName ;
StringTableEntry fnNamespace , fnPackage ;
// Add local object creation stack [7/9/2007 Black]
static const U32 objectCreationStackSize = 32 ;
U32 objectCreationStackIndex = 0 ;
struct {
SimObject * newObject ;
U32 failJump ;
} objectCreationStack [ objectCreationStackSize ] ;
SimObject * currentNewObject = 0 ;
U32 failJump = 0 ;
StringTableEntry prevField = NULL ;
StringTableEntry curField = NULL ;
SimObject * prevObject = NULL ;
SimObject * curObject = NULL ;
SimObject * saveObject = NULL ;
Namespace : : Entry * nsEntry ;
Namespace * ns ;
const char * curFNDocBlock = NULL ;
const char * curNSDocBlock = NULL ;
const S32 nsDocLength = 128 ;
char nsDocBlockClass [ nsDocLength ] ;
U32 callArgc ;
2012-09-23 08:59:48 +00:00
ConsoleValueRef * callArgv ;
2012-09-19 15:15:01 +00:00
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 ;
2012-09-23 08:59:48 +00:00
const char * retValue ;
2012-10-11 20:29:39 +00:00
// note: anything returned is pushed to CSTK and will be invalidated on the next exec()
2012-09-23 08:59:48 +00:00
ConsoleValueRef returnValue ;
2012-09-19 15:15:01 +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 + + ] ;
nsEntry = NULL ;
breakContinue :
switch ( instruction )
{
case OP_FUNC_DECL :
if ( ! noCalls )
{
2014-09-07 16:38:35 +00:00
fnName = CodeToSTE ( code , ip ) ;
fnNamespace = CodeToSTE ( code , ip + 2 ) ;
fnPackage = CodeToSTE ( code , ip + 4 ) ;
bool hasBody = ( code [ ip + 6 ] & 0x01 ) ! = 0 ;
U32 lineNumber = code [ ip + 6 ] > > 1 ;
2012-09-19 15:15:01 +00:00
Namespace : : unlinkPackages ( ) ;
ns = Namespace : : find ( fnNamespace , fnPackage ) ;
ns - > addFunction ( fnName , this , hasBody ? ip : 0 , curFNDocBlock ? dStrdup ( curFNDocBlock ) : NULL , lineNumber ) ; // 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);
}
2014-09-07 16:38:35 +00:00
ip = code [ ip + 7 ] ;
2012-09-19 15:15:01 +00:00
break ;
case OP_CREATE_OBJECT :
{
// Read some useful info.
2014-09-07 16:38:35 +00:00
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 ] ;
2012-09-19 15:15:01 +00:00
// 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.
2012-09-23 08:59:48 +00:00
CSTK . getArgcArgv ( NULL , & callArgc , & callArgv ) ;
const char * objectName = callArgv [ 2 ] ;
2012-09-19 15:15:01 +00:00
// 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 ] ) )
{
Con : : errorf ( ConsoleLogEntry : : General , " %s: Cannot re-declare data block %s with a different class. " , getFileLine ( ip ) , objectName ) ;
ip = failJump ;
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
break ;
}
// If there was one, set the currentNewObject and move on.
if ( db )
currentNewObject = db ;
}
else if ( ! isInternal )
{
// IF we aren't looking at a local/internal object, then check if
// this object already exists in the global space
2013-08-04 13:50:56 +00:00
AbstractClassRep * rep = AbstractClassRep : : findClassRep ( objectName ) ;
if ( rep ! = NULL ) {
2013-08-05 11:20:44 +00:00
Con : : errorf ( ConsoleLogEntry : : General , " %s: Cannot name object [%s] the same name as a script class. " ,
2013-08-04 13:50:56 +00:00
getFileLine ( ip ) , objectName ) ;
ip = failJump ;
STR . popFrame ( ) ;
break ;
}
2012-09-23 08:59:48 +00:00
SimObject * obj = Sim : : findObject ( ( const char * ) objectName ) ;
2012-09-19 15:15:01 +00:00
if ( obj /*&& !obj->isLocalName()*/ )
{
if ( isSingleton )
{
// Make sure we're not trying to change types
2012-09-23 08:59:48 +00:00
if ( dStricmp ( obj - > getClassName ( ) , ( const char * ) callArgv [ 1 ] ) ! = 0 )
2012-09-19 15:15:01 +00:00
{
Con : : errorf ( ConsoleLogEntry : : General , " %s: Cannot re-declare object [%s] with a different class [%s] - was [%s]. " ,
2012-09-23 08:59:48 +00:00
getFileLine ( ip ) , objectName , ( const char * ) callArgv [ 1 ] , obj - > getClassName ( ) ) ;
2012-09-19 15:15:01 +00:00
ip = failJump ;
STR . popFrame ( ) ;
2012-09-23 08:59:48 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
break ;
}
// We're creating a singleton, so use the found object
// instead of creating a new object.
currentNewObject = obj ;
}
else
{
const char * redefineBehavior = Con : : getVariable ( " $Con::redefineBehavior " ) ;
if ( dStricmp ( redefineBehavior , " replaceExisting " ) = = 0 )
{
// Save our constructor args as the argv vector is stored on the
// string stack and may get stomped if deleteObject triggers
// script execution.
2012-09-23 08:59:48 +00:00
ConsoleValueRef savedArgv [ StringStack : : MaxArgs ] ;
for ( int i = 0 ; i < callArgc ; i + + ) {
savedArgv [ i ] = callArgv [ i ] ;
}
//dMemcpy( savedArgv, callArgv, sizeof( savedArgv[ 0 ] ) * callArgc );
2012-09-19 15:15:01 +00:00
2012-10-11 20:29:39 +00:00
// Prevent stack value corruption
CSTK . pushFrame ( ) ;
STR . pushFrame ( ) ;
// --
2012-09-23 08:59:48 +00:00
2012-09-19 15:15:01 +00:00
obj - > deleteObject ( ) ;
obj = NULL ;
2012-10-11 20:29:39 +00:00
// Prevent stack value corruption
CSTK . popFrame ( ) ;
STR . popFrame ( ) ;
// --
2012-09-23 08:59:48 +00:00
//dMemcpy( callArgv, savedArgv, sizeof( callArgv[ 0 ] ) * callArgc );
for ( int i = 0 ; i < callArgc ; i + + ) {
callArgv [ i ] = savedArgv [ i ] ;
}
2012-09-19 15:15:01 +00:00
}
else if ( dStricmp ( redefineBehavior , " renameNew " ) = = 0 )
{
for ( U32 i = 1 ; ; + + i )
{
String newName = String : : ToString ( " %s%i " , objectName , i ) ;
if ( ! Sim : : findObject ( newName ) )
{
objectName = StringTable - > insert ( newName ) ;
break ;
}
}
}
else if ( dStricmp ( redefineBehavior , " unnameNew " ) = = 0 )
{
objectName = StringTable - > insert ( " " ) ;
}
else if ( dStricmp ( redefineBehavior , " postfixNew " ) = = 0 )
{
const char * postfix = Con : : getVariable ( " $Con::redefineBehaviorPostfix " ) ;
String newName = String : : ToString ( " %s%s " , objectName , postfix ) ;
if ( Sim : : findObject ( newName ) )
{
Con : : errorf ( ConsoleLogEntry : : General , " %s: Cannot re-declare object with postfix [%s]. " ,
getFileLine ( ip ) , newName . c_str ( ) ) ;
ip = failJump ;
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
break ;
}
else
objectName = StringTable - > insert ( newName ) ;
}
else
{
Con : : errorf ( ConsoleLogEntry : : General , " %s: Cannot re-declare object [%s]. " ,
getFileLine ( ip ) , objectName ) ;
ip = failJump ;
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
break ;
}
}
}
}
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
if ( ! currentNewObject )
{
// Well, looks like we have to create a new object.
2012-09-23 08:59:48 +00:00
ConsoleObject * object = ConsoleObject : : create ( ( const char * ) callArgv [ 1 ] ) ;
2012-09-19 15:15:01 +00:00
// Deal with failure!
if ( ! object )
{
2012-09-23 08:59:48 +00:00
Con : : errorf ( ConsoleLogEntry : : General , " %s: Unable to instantiate non-conobject class %s. " , getFileLine ( ip ) , ( const char * ) callArgv [ 1 ] ) ;
2012-09-19 15:15:01 +00:00
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!
2012-09-23 08:59:48 +00:00
Con : : errorf ( ConsoleLogEntry : : General , " %s: Unable to instantiate non-datablock class %s. " , getFileLine ( ip ) , ( const char * ) callArgv [ 1 ] ) ;
2012-09-19 15:15:01 +00:00
// Clean up...
delete object ;
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 )
{
2012-09-23 08:59:48 +00:00
Con : : errorf ( ConsoleLogEntry : : General , " %s: Unable to instantiate non-SimObject class %s. " , getFileLine ( ip ) , ( const char * ) callArgv [ 1 ] ) ;
2012-09-19 15:15:01 +00:00
delete object ;
ip = failJump ;
break ;
}
// Set the declaration line
currentNewObject - > setDeclarationLine ( lineNumber ) ;
// Set the file that this object was created in
currentNewObject - > setFilename ( 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 ) ;
}
else
{
if ( Con : : gObjectCopyFailures = = - 1 )
2012-09-23 08:59:48 +00:00
Con : : errorf ( ConsoleLogEntry : : General , " %s: Unable to find parent object %s for %s. " , getFileLine ( ip ) , objParent , ( const char * ) callArgv [ 1 ] ) ;
2012-09-19 15:15:01 +00:00
else
+ + Con : : gObjectCopyFailures ;
// Fail to create the object.
delete object ;
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 ) ;
}
2012-10-11 20:29:39 +00:00
// Prevent stack value corruption
CSTK . pushFrame ( ) ;
STR . pushFrame ( ) ;
// --
2012-09-23 08:59:48 +00:00
2012-09-19 15:15:01 +00:00
// Do the constructor parameters.
if ( ! currentNewObject - > processArguments ( callArgc - 3 , callArgv + 3 ) )
{
delete currentNewObject ;
currentNewObject = NULL ;
ip = failJump ;
2012-09-23 08:59:48 +00:00
// Prevent stack value corruption
CSTK . popFrame ( ) ;
STR . popFrame ( ) ;
// --
2012-09-19 15:15:01 +00:00
break ;
}
2012-09-23 08:59:48 +00:00
// Prevent stack value corruption
CSTK . popFrame ( ) ;
STR . popFrame ( ) ;
// --
2012-09-19 15:15:01 +00:00
// If it's not a datablock, allow people to modify bits of it.
if ( ! isDataBlock )
{
currentNewObject - > setModStaticFields ( true ) ;
currentNewObject - > setModDynamicFields ( true ) ;
}
}
// Advance the IP past the create info...
2014-09-07 16:38:35 +00:00
ip + = 7 ;
2012-09-19 15:15:01 +00:00
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());
2012-09-23 08:59:48 +00:00
// Prevent stack value corruption
CSTK . pushFrame ( ) ;
STR . pushFrame ( ) ;
// --
2012-09-19 15:15:01 +00:00
// Make sure it wasn't already added, then add it.
if ( currentNewObject - > isProperlyAdded ( ) = = false )
{
bool ret = false ;
Message * msg = dynamic_cast < Message * > ( currentNewObject ) ;
if ( msg )
{
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 ) , currentNewObject - > getName ( ) , currentNewObject - > getClassName ( ) ) ;
delete currentNewObject ;
ip = failJump ;
2012-09-23 08:59:48 +00:00
// Prevent stack value corruption
CSTK . popFrame ( ) ;
STR . popFrame ( ) ;
// --
2012-09-19 15:15:01 +00:00
break ;
}
}
// Are we dealing with a datablock?
SimDataBlock * dataBlock = dynamic_cast < SimDataBlock * > ( currentNewObject ) ;
static String errorStr ;
2012-09-23 08:59:48 +00:00
2012-09-19 15:15:01 +00:00
// If so, preload it.
if ( dataBlock & & ! dataBlock - > preload ( true , errorStr ) )
{
Con : : errorf ( ConsoleLogEntry : : General , " %s: preload failed for %s: %s. " , getFileLine ( ip ) ,
currentNewObject - > getName ( ) , errorStr . c_str ( ) ) ;
dataBlock - > deleteObject ( ) ;
ip = failJump ;
2012-09-23 08:59:48 +00:00
// Prevent stack value corruption
CSTK . popFrame ( ) ;
STR . popFrame ( ) ;
// --
2012-09-19 15:15:01 +00:00
break ;
}
// What group will we be added to, if any?
U32 groupAddId = intStack [ _UINT ] ;
SimGroup * grp = NULL ;
SimSet * set = NULL ;
bool isMessage = dynamic_cast < Message * > ( currentNewObject ) ! = 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 ( ) )
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)
if ( placeAtRoot )
intStack [ _UINT ] = currentNewObject - > getId ( ) ;
else
intStack [ + + _UINT ] = currentNewObject - > getId ( ) ;
2012-10-11 20:29:39 +00:00
// Prevent stack value corruption
CSTK . popFrame ( ) ;
STR . popFrame ( ) ;
// --
2012-09-19 15:15:01 +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 )
_UINT - - ;
break ;
}
case OP_FINISH_OBJECT :
{
//Assert( objectCreationStackIndex >= 0 );
// Restore the object info from the stack [7/9/2007 Black]
currentNewObject = objectCreationStack [ - - objectCreationStackIndex ] . newObject ;
failJump = objectCreationStack [ objectCreationStackIndex ] . failJump ;
break ;
}
case OP_JMPIFFNOT :
if ( floatStack [ _FLT - - ] )
{
ip + + ;
break ;
}
ip = code [ ip ] ;
break ;
case OP_JMPIFNOT :
if ( intStack [ _UINT - - ] )
{
ip + + ;
break ;
}
ip = code [ ip ] ;
break ;
case OP_JMPIFF :
if ( ! floatStack [ _FLT - - ] )
{
ip + + ;
break ;
}
ip = code [ ip ] ;
break ;
case OP_JMPIF :
if ( ! intStack [ _UINT - - ] )
{
ip + + ;
break ;
}
ip = code [ ip ] ;
break ;
case OP_JMPIFNOT_NP :
if ( intStack [ _UINT ] )
{
_UINT - - ;
ip + + ;
break ;
}
ip = code [ ip ] ;
break ;
case OP_JMPIF_NP :
if ( ! intStack [ _UINT ] )
{
_UINT - - ;
ip + + ;
break ;
}
ip = code [ ip ] ;
break ;
case OP_JMP :
ip = code [ ip ] ;
break ;
// This fixes a bug when not explicitly returning a value.
case OP_RETURN_VOID :
STR . setStringValue ( " " ) ;
// We're falling thru here on purpose.
case OP_RETURN :
2012-10-11 20:29:39 +00:00
retValue = STR . getStringValue ( ) ;
2012-09-23 08:59:48 +00:00
if ( iterDepth > 0 )
{
// Clear iterator state.
while ( iterDepth > 0 )
{
iterStack [ - - _ITER ] . mIsStringIter = false ;
- - iterDepth ;
}
STR . rewind ( ) ;
STR . setStringValue ( retValue ) ; // Not nice but works.
2012-10-11 20:29:39 +00:00
retValue = STR . getStringValue ( ) ;
2012-09-23 08:59:48 +00:00
}
2012-10-11 20:29:39 +00:00
// Previously the return value was on the stack and would be returned using STR.getStringValue().
// Now though we need to wrap it in a ConsoleValueRef
returnValue . value = CSTK . pushStackString ( retValue ) ;
2012-09-23 08:59:48 +00:00
goto execFinished ;
case OP_RETURN_FLT :
2012-09-19 15:15:01 +00:00
if ( iterDepth > 0 )
{
// Clear iterator state.
while ( iterDepth > 0 )
{
iterStack [ - - _ITER ] . mIsStringIter = false ;
- - iterDepth ;
}
}
2012-09-23 08:59:48 +00:00
returnValue . value = CSTK . pushFLT ( floatStack [ _FLT ] ) ;
_FLT - - ;
goto execFinished ;
case OP_RETURN_UINT :
if ( iterDepth > 0 )
{
// Clear iterator state.
while ( iterDepth > 0 )
{
iterStack [ - - _ITER ] . mIsStringIter = false ;
- - iterDepth ;
}
}
2012-10-11 20:29:39 +00:00
returnValue . value = CSTK . pushUINT ( intStack [ _UINT ] ) ;
_UINT - - ;
2012-09-19 15:15:01 +00:00
goto execFinished ;
case OP_CMPEQ :
intStack [ _UINT + 1 ] = bool ( floatStack [ _FLT ] = = floatStack [ _FLT - 1 ] ) ;
_UINT + + ;
_FLT - = 2 ;
break ;
case OP_CMPGR :
intStack [ _UINT + 1 ] = bool ( floatStack [ _FLT ] > floatStack [ _FLT - 1 ] ) ;
_UINT + + ;
_FLT - = 2 ;
break ;
case OP_CMPGE :
intStack [ _UINT + 1 ] = bool ( floatStack [ _FLT ] > = floatStack [ _FLT - 1 ] ) ;
_UINT + + ;
_FLT - = 2 ;
break ;
case OP_CMPLT :
intStack [ _UINT + 1 ] = bool ( floatStack [ _FLT ] < floatStack [ _FLT - 1 ] ) ;
_UINT + + ;
_FLT - = 2 ;
break ;
case OP_CMPLE :
intStack [ _UINT + 1 ] = bool ( floatStack [ _FLT ] < = floatStack [ _FLT - 1 ] ) ;
_UINT + + ;
_FLT - = 2 ;
break ;
case OP_CMPNE :
intStack [ _UINT + 1 ] = bool ( floatStack [ _FLT ] ! = floatStack [ _FLT - 1 ] ) ;
_UINT + + ;
_FLT - = 2 ;
break ;
case OP_XOR :
intStack [ _UINT - 1 ] = intStack [ _UINT ] ^ intStack [ _UINT - 1 ] ;
_UINT - - ;
break ;
case OP_MOD :
if ( intStack [ _UINT - 1 ] ! = 0 )
intStack [ _UINT - 1 ] = intStack [ _UINT ] % intStack [ _UINT - 1 ] ;
else
intStack [ _UINT - 1 ] = 0 ;
_UINT - - ;
break ;
case OP_BITAND :
intStack [ _UINT - 1 ] = intStack [ _UINT ] & intStack [ _UINT - 1 ] ;
_UINT - - ;
break ;
case OP_BITOR :
intStack [ _UINT - 1 ] = intStack [ _UINT ] | intStack [ _UINT - 1 ] ;
_UINT - - ;
break ;
case OP_NOT :
intStack [ _UINT ] = ! intStack [ _UINT ] ;
break ;
case OP_NOTF :
intStack [ _UINT + 1 ] = ! floatStack [ _FLT ] ;
_FLT - - ;
_UINT + + ;
break ;
case OP_ONESCOMPLEMENT :
intStack [ _UINT ] = ~ intStack [ _UINT ] ;
break ;
case OP_SHR :
intStack [ _UINT - 1 ] = intStack [ _UINT ] > > intStack [ _UINT - 1 ] ;
_UINT - - ;
break ;
case OP_SHL :
intStack [ _UINT - 1 ] = intStack [ _UINT ] < < intStack [ _UINT - 1 ] ;
_UINT - - ;
break ;
case OP_AND :
intStack [ _UINT - 1 ] = intStack [ _UINT ] & & intStack [ _UINT - 1 ] ;
_UINT - - ;
break ;
case OP_OR :
intStack [ _UINT - 1 ] = intStack [ _UINT ] | | intStack [ _UINT - 1 ] ;
_UINT - - ;
break ;
case OP_ADD :
floatStack [ _FLT - 1 ] = floatStack [ _FLT ] + floatStack [ _FLT - 1 ] ;
_FLT - - ;
break ;
case OP_SUB :
floatStack [ _FLT - 1 ] = floatStack [ _FLT ] - floatStack [ _FLT - 1 ] ;
_FLT - - ;
break ;
case OP_MUL :
floatStack [ _FLT - 1 ] = floatStack [ _FLT ] * floatStack [ _FLT - 1 ] ;
_FLT - - ;
break ;
case OP_DIV :
floatStack [ _FLT - 1 ] = floatStack [ _FLT ] / floatStack [ _FLT - 1 ] ;
_FLT - - ;
break ;
case OP_NEG :
floatStack [ _FLT ] = - floatStack [ _FLT ] ;
break ;
case OP_SETCURVAR :
2014-09-07 16:38:35 +00:00
var = CodeToSTE ( code , ip ) ;
ip + = 2 ;
2012-09-19 15:15:01 +00:00
// 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.
prevField = NULL ;
prevObject = NULL ;
curObject = NULL ;
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 :
2014-09-07 16:38:35 +00:00
var = CodeToSTE ( code , ip ) ;
ip + = 2 ;
2012-09-19 15:15:01 +00:00
2012-10-11 20:29:39 +00:00
// See OP_SETCURVAR
2012-09-19 15:15:01 +00:00
prevField = NULL ;
prevObject = NULL ;
curObject = NULL ;
gEvalState . setCurVarNameCreate ( var ) ;
// See OP_SETCURVAR for why we do this.
curFNDocBlock = NULL ;
curNSDocBlock = NULL ;
break ;
case OP_SETCURVAR_ARRAY :
var = STR . getSTValue ( ) ;
// See OP_SETCURVAR
prevField = NULL ;
prevObject = NULL ;
curObject = NULL ;
gEvalState . setCurVarName ( var ) ;
// See OP_SETCURVAR for why we do this.
curFNDocBlock = NULL ;
curNSDocBlock = NULL ;
break ;
case OP_SETCURVAR_ARRAY_CREATE :
var = STR . getSTValue ( ) ;
// See OP_SETCURVAR
prevField = NULL ;
prevObject = NULL ;
curObject = NULL ;
gEvalState . setCurVarNameCreate ( var ) ;
// See OP_SETCURVAR for why we do this.
curFNDocBlock = NULL ;
curNSDocBlock = NULL ;
break ;
case OP_LOADVAR_UINT :
intStack [ _UINT + 1 ] = gEvalState . getIntVariable ( ) ;
_UINT + + ;
break ;
case OP_LOADVAR_FLT :
floatStack [ _FLT + 1 ] = gEvalState . getFloatVariable ( ) ;
_FLT + + ;
break ;
case OP_LOADVAR_STR :
val = gEvalState . getStringVariable ( ) ;
STR . setStringValue ( val ) ;
break ;
2012-10-04 16:58:43 +00:00
case OP_LOADVAR_VAR :
// Sets current source of OP_SAVEVAR_VAR
gEvalState . copyVariable = gEvalState . currentVariable ;
break ;
2012-09-19 15:15:01 +00:00
case OP_SAVEVAR_UINT :
gEvalState . setIntVariable ( intStack [ _UINT ] ) ;
break ;
case OP_SAVEVAR_FLT :
gEvalState . setFloatVariable ( floatStack [ _FLT ] ) ;
break ;
case OP_SAVEVAR_STR :
gEvalState . setStringVariable ( STR . getStringValue ( ) ) ;
break ;
2012-10-04 16:58:43 +00:00
case OP_SAVEVAR_VAR :
2012-10-11 20:29:39 +00:00
// this basically handles %var1 = %var2
2012-10-04 16:58:43 +00:00
gEvalState . setCopyVariable ( ) ;
break ;
2012-09-19 15:15:01 +00:00
case OP_SETCUROBJECT :
// Save the previous object for parsing vector fields.
prevObject = curObject ;
val = STR . getStringValue ( ) ;
// 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 wasn't found
if ( curObject )
{
SimSet * set = dynamic_cast < SimSet * > ( curObject ) ;
if ( set )
{
StringTableEntry intName = StringTable - > insert ( STR . getStringValue ( ) ) ;
bool recurse = code [ ip - 1 ] ;
SimObject * obj = set - > findObjectByInternalName ( intName , recurse ) ;
intStack [ _UINT + 1 ] = obj ? obj - > getId ( ) : 0 ;
_UINT + + ;
}
else
{
Con : : errorf ( ConsoleLogEntry : : Script , " %s: Attempt to use -> on non-set %s of class %s. " , getFileLine ( ip - 2 ) , curObject - > getName ( ) , curObject - > getClassName ( ) ) ;
intStack [ _UINT ] = 0 ;
}
}
break ;
case OP_SETCUROBJECT_NEW :
curObject = currentNewObject ;
break ;
case OP_SETCURFIELD :
// Save the previous field for parsing vector fields.
prevField = curField ;
dStrcpy ( prevFieldArray , curFieldArray ) ;
2014-09-07 16:38:35 +00:00
curField = CodeToSTE ( code , ip ) ;
2012-09-19 15:15:01 +00:00
curFieldArray [ 0 ] = 0 ;
2014-09-07 16:38:35 +00:00
ip + = 2 ;
2012-09-19 15:15:01 +00:00
break ;
case OP_SETCURFIELD_ARRAY :
dStrcpy ( curFieldArray , STR . getStringValue ( ) ) ;
break ;
case OP_SETCURFIELD_TYPE :
if ( curObject )
curObject - > setDataFieldType ( code [ ip ] , curField , curFieldArray ) ;
ip + + ;
break ;
case OP_LOADFIELD_UINT :
if ( curObject )
intStack [ _UINT + 1 ] = U32 ( dAtoi ( curObject - > getDataField ( curField , curFieldArray ) ) ) ;
else
{
// The field is not being retrieved from an object. Maybe it's
// a special accessor?
getFieldComponent ( prevObject , prevField , prevFieldArray , curField , valBuffer ) ;
intStack [ _UINT + 1 ] = dAtoi ( valBuffer ) ;
}
_UINT + + ;
break ;
case OP_LOADFIELD_FLT :
if ( curObject )
floatStack [ _FLT + 1 ] = dAtof ( curObject - > getDataField ( curField , curFieldArray ) ) ;
else
{
// The field is not being retrieved from an object. Maybe it's
// a special accessor?
getFieldComponent ( prevObject , prevField , prevFieldArray , curField , valBuffer ) ;
floatStack [ _FLT + 1 ] = dAtof ( valBuffer ) ;
}
_FLT + + ;
break ;
case OP_LOADFIELD_STR :
if ( curObject )
{
val = curObject - > getDataField ( curField , curFieldArray ) ;
STR . setStringValue ( val ) ;
}
else
{
// The field is not being retrieved from an object. Maybe it's
// a special accessor?
getFieldComponent ( prevObject , prevField , prevFieldArray , curField , valBuffer ) ;
STR . setStringValue ( valBuffer ) ;
}
break ;
case OP_SAVEFIELD_UINT :
STR . setIntValue ( intStack [ _UINT ] ) ;
if ( curObject )
curObject - > setDataField ( curField , curFieldArray , STR . getStringValue ( ) ) ;
else
{
// The field is not being set on an object. Maybe it's
// a special accessor?
setFieldComponent ( prevObject , prevField , prevFieldArray , curField ) ;
prevObject = NULL ;
}
break ;
case OP_SAVEFIELD_FLT :
STR . setFloatValue ( floatStack [ _FLT ] ) ;
if ( curObject )
curObject - > setDataField ( curField , curFieldArray , STR . getStringValue ( ) ) ;
else
{
// The field is not being set on an object. Maybe it's
// a special accessor?
setFieldComponent ( prevObject , prevField , prevFieldArray , curField ) ;
prevObject = NULL ;
}
break ;
case OP_SAVEFIELD_STR :
if ( curObject )
curObject - > setDataField ( curField , curFieldArray , STR . getStringValue ( ) ) ;
else
{
// The field is not being set on an object. Maybe it's
// a special accessor?
setFieldComponent ( prevObject , prevField , prevFieldArray , curField ) ;
prevObject = NULL ;
}
break ;
case OP_STR_TO_UINT :
intStack [ _UINT + 1 ] = STR . getIntValue ( ) ;
_UINT + + ;
break ;
case OP_STR_TO_FLT :
floatStack [ _FLT + 1 ] = STR . getFloatValue ( ) ;
_FLT + + ;
break ;
case OP_STR_TO_NONE :
// This exists simply to deal with certain typecast situations.
break ;
case OP_FLT_TO_UINT :
intStack [ _UINT + 1 ] = ( S64 ) floatStack [ _FLT ] ;
_FLT - - ;
_UINT + + ;
break ;
case OP_FLT_TO_STR :
STR . setFloatValue ( floatStack [ _FLT ] ) ;
_FLT - - ;
break ;
case OP_FLT_TO_NONE :
_FLT - - ;
break ;
case OP_UINT_TO_FLT :
floatStack [ _FLT + 1 ] = ( F32 ) intStack [ _UINT ] ;
_UINT - - ;
_FLT + + ;
break ;
case OP_UINT_TO_STR :
STR . setIntValue ( intStack [ _UINT ] ) ;
_UINT - - ;
break ;
case OP_UINT_TO_NONE :
_UINT - - ;
break ;
2012-10-04 16:58:43 +00:00
case OP_COPYVAR_TO_NONE :
gEvalState . copyVariable = NULL ;
break ;
2012-09-19 15:15:01 +00:00
case OP_LOADIMMED_UINT :
intStack [ _UINT + 1 ] = code [ ip + + ] ;
_UINT + + ;
break ;
case OP_LOADIMMED_FLT :
floatStack [ _FLT + 1 ] = curFloatTable [ code [ ip ] ] ;
ip + + ;
_FLT + + ;
break ;
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 ;
}
case OP_LOADIMMED_STR :
STR . setStringValue ( curStringTable + code [ ip + + ] ) ;
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 :
2014-09-07 16:38:35 +00:00
STR . setStringValue ( CodeToSTE ( code , ip ) ) ;
ip + = 2 ;
2012-09-19 15:15:01 +00:00
break ;
case OP_CALLFUNC_RESOLVE :
// This deals with a function that is potentially living in a namespace.
2014-09-07 16:38:35 +00:00
fnNamespace = CodeToSTE ( code , ip + 2 ) ;
fnName = CodeToSTE ( code , ip ) ;
2012-09-19 15:15:01 +00:00
// Try to look it up.
ns = Namespace : : find ( fnNamespace ) ;
nsEntry = ns - > lookup ( fnName ) ;
if ( ! nsEntry )
{
2014-09-07 16:38:35 +00:00
ip + = 5 ;
2012-09-19 15:15:01 +00:00
Con : : warnf ( ConsoleLogEntry : : General ,
" %s: Unable to find function %s%s%s " ,
2014-09-07 16:38:35 +00:00
getFileLine ( ip - 7 ) , fnNamespace ? fnNamespace : " " ,
2012-09-19 15:15:01 +00:00
fnNamespace ? " :: " : " " , fnName ) ;
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
break ;
}
2014-09-07 16:38:35 +00:00
2014-09-07 21:49:45 +00:00
# ifdef COMPILER_OPTIMIZE_FUNCTION_CALLS
2012-09-19 15:15:01 +00:00
// Now fall through to OP_CALLFUNC...
2014-09-07 16:38:35 +00:00
// Now, rewrite our code a bit (ie, avoid future lookups) and fall
// through to OP_CALLFUNC
2014-09-15 01:50:32 +00:00
# ifdef TORQUE_CPU_X64
2014-09-07 16:38:35 +00:00
* ( ( U64 * ) ( code + ip + 2 ) ) = ( ( U64 ) nsEntry ) ;
# else
code [ ip + 2 ] = ( ( U32 ) nsEntry ) ;
# endif
code [ ip - 1 ] = OP_CALLFUNC ;
2014-09-07 21:49:45 +00:00
# endif
2012-09-19 15:15:01 +00:00
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.
S32 routingId = 0 ;
2014-09-07 16:38:35 +00:00
fnName = CodeToSTE ( code , ip ) ;
2012-09-19 15:15:01 +00:00
//if this is called from inside a function, append the ip and codeptr
if ( gEvalState . getStackDepth ( ) > 0 )
{
gEvalState . getCurrentFrame ( ) . code = this ;
gEvalState . getCurrentFrame ( ) . ip = ip - 1 ;
}
2014-09-07 16:38:35 +00:00
U32 callType = code [ ip + 4 ] ;
2012-09-19 15:15:01 +00:00
2014-09-07 16:38:35 +00:00
ip + = 5 ;
2012-09-23 08:59:48 +00:00
CSTK . getArgcArgv ( fnName , & callArgc , & callArgv ) ;
2012-09-19 15:15:01 +00:00
const char * componentReturnValue = " " ;
if ( callType = = FuncCallExprNode : : FunctionCall )
{
if ( ! nsEntry )
{
2014-09-07 21:49:45 +00:00
# ifdef COMPILER_OPTIMIZE_FUNCTION_CALLS
2014-09-15 01:50:32 +00:00
# ifdef TORQUE_CPU_X64
2014-09-07 16:38:35 +00:00
nsEntry = ( ( Namespace : : Entry * ) * ( ( U64 * ) ( code + ip - 3 ) ) ) ;
# else
nsEntry = ( ( Namespace : : Entry * ) * ( code + ip - 3 ) ) ;
2014-09-07 21:49:45 +00:00
# endif
# else
2012-09-19 15:15:01 +00:00
nsEntry = Namespace : : global ( ) - > lookup ( fnName ) ;
2014-09-07 16:38:35 +00:00
# endif
ns = NULL ;
2012-09-19 15:15:01 +00:00
}
ns = NULL ;
}
else if ( callType = = FuncCallExprNode : : MethodCall )
{
saveObject = gEvalState . thisObject ;
2012-09-23 08:59:48 +00:00
gEvalState . thisObject = Sim : : findObject ( ( const char * ) callArgv [ 1 ] ) ;
2012-09-19 15:15:01 +00:00
if ( ! gEvalState . thisObject )
{
// Go back to the previous saved object.
gEvalState . thisObject = saveObject ;
2012-09-23 08:59:48 +00:00
Con : : warnf ( ConsoleLogEntry : : General , " %s: Unable to find object: '%s' attempting to call function '%s' " , getFileLine ( ip - 4 ) , ( const char * ) callArgv [ 1 ] , fnName ) ;
2012-09-19 15:15:01 +00:00
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2014-06-23 17:58:06 +00:00
STR . setStringValue ( " " ) ;
2012-09-19 15:15:01 +00:00
break ;
}
bool handlesMethod = gEvalState . thisObject - > handlesConsoleMethod ( fnName , & routingId ) ;
if ( handlesMethod & & routingId = = MethodOnComponent )
{
ICallMethod * pComponent = dynamic_cast < ICallMethod * > ( gEvalState . thisObject ) ;
if ( pComponent )
componentReturnValue = pComponent - > callMethodArgList ( callArgc , callArgv , false ) ;
}
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 ;
}
}
Namespace : : Entry : : CallbackUnion * nsCb = NULL ;
const char * nsUsage = NULL ;
if ( nsEntry )
{
nsCb = & nsEntry - > cb ;
nsUsage = nsEntry - > mUsage ;
routingId = 0 ;
}
if ( ! nsEntry | | noCalls )
{
if ( ! noCalls & & ! ( routingId = = MethodOnComponent ) )
{
2014-09-07 16:38:35 +00:00
Con : : warnf ( ConsoleLogEntry : : General , " %s: Unknown command %s. " , getFileLine ( ip - 6 ) , fnName ) ;
2012-09-19 15:15:01 +00:00
if ( callType = = FuncCallExprNode : : MethodCall )
{
Con : : warnf ( ConsoleLogEntry : : General , " Object %s(%d) %s " ,
gEvalState . thisObject - > getName ( ) ? gEvalState . thisObject - > getName ( ) : " " ,
gEvalState . thisObject - > getId ( ) , Con : : getNamespaceList ( ns ) ) ;
}
}
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
if ( routingId = = MethodOnComponent )
STR . setStringValue ( componentReturnValue ) ;
else
STR . setStringValue ( " " ) ;
break ;
}
if ( nsEntry - > mType = = Namespace : : Entry : : ConsoleFunctionType )
{
2012-09-23 08:59:48 +00:00
ConsoleValueRef ret ;
2012-09-19 15:15:01 +00:00
if ( nsEntry - > mFunctionOffset )
ret = nsEntry - > mCode - > exec ( nsEntry - > mFunctionOffset , fnName , nsEntry - > mNamespace , callArgc , callArgv , false , nsEntry - > mPackage ) ;
2014-11-20 20:20:54 +00:00
2012-10-11 20:29:39 +00:00
STR . popFrame ( ) ;
// Functions are assumed to return strings, so look ahead to see if we can skip the conversion
if ( code [ ip ] = = OP_STR_TO_UINT )
2012-09-23 08:59:48 +00:00
{
ip + + ;
intStack [ + + _UINT ] = ( U32 ) ( ( S32 ) ret ) ;
}
else if ( code [ ip ] = = OP_STR_TO_FLT )
{
ip + + ;
floatStack [ + + _FLT ] = ( F32 ) ret ;
}
else if ( code [ ip ] = = OP_STR_TO_NONE )
2014-11-20 20:17:59 +00:00
{
STR . setStringValue ( ret . getStringValue ( ) ) ;
2012-09-23 08:59:48 +00:00
ip + + ;
2014-11-20 20:17:59 +00:00
}
2012-09-23 08:59:48 +00:00
else
STR . setStringValue ( ( const char * ) ret ) ;
2014-11-20 20:38:17 +00:00
2012-10-11 20:29:39 +00:00
// This will clear everything including returnValue
CSTK . popFrame ( ) ;
STR . clearFunctionOffset ( ) ;
2012-09-19 15:15:01 +00:00
}
else
{
const char * nsName = ns ? ns - > mName : " " ;
# ifndef TORQUE_DEBUG
// [tom, 12/13/2006] This stops tools functions from working in the console,
// which is useful behavior when debugging so I'm ifdefing this out for debug builds.
if ( nsEntry - > mToolOnly & & ! Con : : isCurrentScriptToolScript ( ) )
{
2014-09-07 16:38:35 +00:00
Con : : errorf ( ConsoleLogEntry : : Script , " %s: %s::%s - attempting to call tools only function from outside of tools. " , getFileLine ( ip - 6 ) , nsName , fnName ) ;
2012-09-19 15:15:01 +00:00
}
else
# endif
if ( ( nsEntry - > mMinArgs & & S32 ( callArgc ) < nsEntry - > mMinArgs ) | | ( nsEntry - > mMaxArgs & & S32 ( callArgc ) > nsEntry - > mMaxArgs ) )
{
Con : : warnf ( ConsoleLogEntry : : Script , " %s: %s::%s - wrong number of arguments (got %i, expected min %i and max %i). " ,
2014-09-07 16:38:35 +00:00
getFileLine ( ip - 6 ) , nsName , fnName ,
2012-09-19 15:15:01 +00:00
callArgc , nsEntry - > mMinArgs , nsEntry - > mMaxArgs ) ;
2014-09-07 16:38:35 +00:00
Con : : warnf ( ConsoleLogEntry : : Script , " %s: usage: %s " , getFileLine ( ip - 6 ) , nsEntry - > mUsage ) ;
2012-09-19 15:15:01 +00:00
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
}
else
{
switch ( nsEntry - > mType )
{
case Namespace : : Entry : : StringCallbackType :
{
const char * ret = nsEntry - > cb . mStringCallbackFunc ( gEvalState . thisObject , callArgc , callArgv ) ;
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
if ( ret ! = STR . getStringValue ( ) )
STR . setStringValue ( ret ) ;
2012-09-23 08:59:48 +00:00
//else
// STR.setLen(dStrlen(ret));
2012-09-19 15:15:01 +00:00
break ;
}
case Namespace : : Entry : : IntCallbackType :
{
S32 result = nsEntry - > cb . mIntCallbackFunc ( gEvalState . thisObject , callArgc , callArgv ) ;
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
if ( code [ ip ] = = OP_STR_TO_UINT )
{
ip + + ;
intStack [ + + _UINT ] = result ;
break ;
}
else if ( code [ ip ] = = OP_STR_TO_FLT )
{
ip + + ;
floatStack [ + + _FLT ] = result ;
break ;
}
else if ( code [ ip ] = = OP_STR_TO_NONE )
ip + + ;
else
STR . setIntValue ( result ) ;
break ;
}
case Namespace : : Entry : : FloatCallbackType :
{
F64 result = nsEntry - > cb . mFloatCallbackFunc ( gEvalState . thisObject , callArgc , callArgv ) ;
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
if ( code [ ip ] = = OP_STR_TO_UINT )
{
ip + + ;
intStack [ + + _UINT ] = ( S64 ) result ;
break ;
}
else if ( code [ ip ] = = OP_STR_TO_FLT )
{
ip + + ;
floatStack [ + + _FLT ] = result ;
break ;
}
else if ( code [ ip ] = = OP_STR_TO_NONE )
ip + + ;
else
STR . setFloatValue ( result ) ;
break ;
}
case Namespace : : Entry : : VoidCallbackType :
nsEntry - > cb . mVoidCallbackFunc ( gEvalState . thisObject , callArgc , callArgv ) ;
if ( code [ ip ] ! = OP_STR_TO_NONE & & Con : : getBoolVariable ( " $Con::warnVoidAssignment " , true ) )
2014-09-07 16:38:35 +00:00
Con : : warnf ( ConsoleLogEntry : : General , " %s: Call to %s in %s uses result of void function call. " , getFileLine ( ip - 6 ) , fnName , functionName ) ;
2012-09-19 15:15:01 +00:00
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
STR . setStringValue ( " " ) ;
break ;
case Namespace : : Entry : : BoolCallbackType :
{
bool result = nsEntry - > cb . mBoolCallbackFunc ( gEvalState . thisObject , callArgc , callArgv ) ;
STR . popFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . popFrame ( ) ;
2012-09-19 15:15:01 +00:00
if ( code [ ip ] = = OP_STR_TO_UINT )
{
ip + + ;
intStack [ + + _UINT ] = result ;
break ;
}
else if ( code [ ip ] = = OP_STR_TO_FLT )
{
ip + + ;
floatStack [ + + _FLT ] = result ;
break ;
}
else if ( code [ ip ] = = OP_STR_TO_NONE )
ip + + ;
else
STR . setIntValue ( result ) ;
break ;
}
}
}
}
if ( callType = = FuncCallExprNode : : MethodCall )
gEvalState . thisObject = saveObject ;
break ;
}
case OP_ADVANCE_STR :
STR . advance ( ) ;
break ;
case OP_ADVANCE_STR_APPENDCHAR :
STR . advanceChar ( code [ ip + + ] ) ;
break ;
case OP_ADVANCE_STR_COMMA :
STR . advanceChar ( ' _ ' ) ;
break ;
case OP_ADVANCE_STR_NUL :
STR . advanceChar ( 0 ) ;
break ;
case OP_REWIND_STR :
STR . rewind ( ) ;
break ;
case OP_TERMINATE_REWIND_STR :
STR . rewindTerminate ( ) ;
break ;
case OP_COMPARE_STR :
intStack [ + + _UINT ] = STR . compare ( ) ;
break ;
case OP_PUSH :
2012-10-11 20:29:39 +00:00
STR . push ( ) ;
2012-09-23 08:59:48 +00:00
CSTK . pushString ( STR . getPreviousStringValue ( ) ) ;
break ;
case OP_PUSH_UINT :
CSTK . pushUINT ( intStack [ _UINT ] ) ;
2012-10-11 20:29:39 +00:00
_UINT - - ;
2012-09-23 08:59:48 +00:00
break ;
case OP_PUSH_FLT :
CSTK . pushFLT ( floatStack [ _FLT ] ) ;
2012-10-11 20:29:39 +00:00
_FLT - - ;
2012-09-19 15:15:01 +00:00
break ;
2012-10-04 16:58:43 +00:00
case OP_PUSH_VAR :
if ( gEvalState . currentVariable )
2012-10-11 20:29:39 +00:00
CSTK . pushValue ( gEvalState . currentVariable - > value ) ;
else
CSTK . pushString ( " " ) ;
2012-10-04 16:58:43 +00:00
break ;
2012-09-19 15:15:01 +00:00
case OP_PUSH_FRAME :
STR . pushFrame ( ) ;
2012-10-11 20:29:39 +00:00
CSTK . pushFrame ( ) ;
2012-09-19 15:15:01 +00:00
break ;
case OP_ASSERT :
{
if ( ! intStack [ _UINT - - ] )
{
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 . getStackDepth ( ) > 0 , " Empty eval stack on break! " ) ;
gEvalState . getCurrentFrame ( ) . code = this ;
gEvalState . getCurrentFrame ( ) . ip = ip - 1 ;
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 ;
/* fallthrough */
}
case OP_ITER_BEGIN :
{
2014-09-07 16:38:35 +00:00
StringTableEntry varName = CodeToSTE ( code , ip ) ;
U32 failIp = code [ ip + 2 ] ;
2012-09-19 15:15:01 +00:00
IterStackRecord & iter = iterStack [ _ITER ] ;
iter . mVariable = gEvalState . getCurrentFrame ( ) . add ( varName ) ;
if ( iter . mIsStringIter )
{
iter . mData . mStr . mString = STR . getStringValue ( ) ;
iter . mData . mStr . mIndex = 0 ;
}
else
{
// Look up the object.
SimSet * set ;
if ( ! Sim : : findObject ( STR . getStringValue ( ) , set ) )
{
Con : : errorf ( ConsoleLogEntry : : General , " No SimSet object '%s' " , STR . getStringValue ( ) ) ;
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 + + ;
STR . push ( ) ;
2014-09-07 16:38:35 +00:00
ip + = 3 ;
2012-09-19 15:15:01 +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.
iter . mVariable - > setStringValue ( & str [ startIndex ] ) ;
const_cast < char * > ( str ) [ endIndex ] = savedChar ;
}
else
iter . mVariable - > setStringValue ( " " ) ;
// 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 ;
}
iter . mVariable - > setIntValue ( set - > at ( index ) - > getId ( ) ) ;
iter . mData . mObj . mIndex = index + 1 ;
}
+ + ip ;
break ;
}
case OP_ITER_END :
{
- - _ITER ;
- - iterDepth ;
STR . rewind ( ) ;
iterStack [ _ITER ] . mIsStringIter = false ;
break ;
}
case OP_INVALID :
default :
// error!
goto execFinished ;
}
}
execFinished :
if ( telDebuggerOn & & setFrame < 0 )
TelDebugger - > popStackFrame ( ) ;
2012-10-11 20:29:39 +00:00
if ( popFrame )
2012-09-19 15:15:01 +00:00
gEvalState . popFrame ( ) ;
if ( argv )
{
if ( gEvalState . traceOn )
{
traceBuffer [ 0 ] = 0 ;
dStrcat ( traceBuffer , " Leaving " ) ;
if ( packageName )
{
dStrcat ( traceBuffer , " [ " ) ;
dStrcat ( traceBuffer , packageName ) ;
dStrcat ( traceBuffer , " ] " ) ;
}
if ( thisNamespace & & thisNamespace - > mName )
{
dSprintf ( traceBuffer + dStrlen ( traceBuffer ) , sizeof ( traceBuffer ) - dStrlen ( traceBuffer ) ,
" %s::%s() - return %s " , thisNamespace - > mName , thisFunctionName , STR . getStringValue ( ) ) ;
}
else
{
dSprintf ( traceBuffer + dStrlen ( traceBuffer ) , sizeof ( traceBuffer ) - dStrlen ( traceBuffer ) ,
" %s() - return %s " , thisFunctionName , STR . getStringValue ( ) ) ;
}
Con : : printf ( " %s " , traceBuffer ) ;
}
}
else
{
delete [ ] globalStrings ;
globalStringsMaxLen = 0 ;
delete [ ] globalFloats ;
globalStrings = NULL ;
globalFloats = NULL ;
}
smCurrentCodeBlock = saveCodeBlock ;
if ( saveCodeBlock & & saveCodeBlock - > name )
{
Con : : gCurrentFile = saveCodeBlock - > name ;
Con : : gCurrentRoot = saveCodeBlock - > modPath ;
}
decRefCount ( ) ;
# ifdef TORQUE_DEBUG
AssertFatal ( ! ( STR . mStartStackSize > stackStart ) , " String stack not popped enough in script exec " ) ;
AssertFatal ( ! ( STR . mStartStackSize < stackStart ) , " String stack popped too much in script exec " ) ;
# endif
2012-09-23 08:59:48 +00:00
return returnValue ;
2012-09-19 15:15:01 +00:00
}
//------------------------------------------------------------