codeInterpreter.cpp
Engine/source/console/codeInterpreter.cpp
Namespaces:
namespace
This namespace contains the core of the console functionality.
Public Enumerations
enum
EvalConstants { MaxStackSize = 1024 FieldBufferSizeString = 2048 FieldBufferSizeNumeric = 128 MethodOnComponent = -2 }
Public Typedefs
OPCodeReturn(CodeInterpreter::*
OpFn )(U32 &)
Public Variables
char
curFieldArray [256]
floatStack [MaxStackSize]
gOpCodeArray [MAX_OP_CODELEN]
iterStack [MaxStackSize]
char
prevFieldArray [256]
char
sTraceBuffer [1024]
Public Functions
getFieldComponent(SimObject * object, StringTableEntry field, const char * array, StringTableEntry subField, char val)
setFieldComponent(SimObject * object, StringTableEntry field, const char * array, StringTableEntry subField)
Detailed Description
Public Enumerations
EvalConstants
Enumerator
- MaxStackSize = 1024
- FieldBufferSizeString = 2048
- FieldBufferSizeNumeric = 128
- MethodOnComponent = -2
Public Typedefs
typedef OPCodeReturn(CodeInterpreter::* OpFn )(U32 &)
Public Variables
U32 _FLT
Stack pointer for floatStack.
U32 _ITER
Stack pointer for iterStack.
U32 _UINT
Stack pointer for intStack.
ConsoleValueStack CSTK
char curFieldArray [256]
F64 floatStack [MaxStackSize]
ExprEvalState gEvalState
OpFn gOpCodeArray [MAX_OP_CODELEN]
S64 intStack [MaxStackSize]
IterStackRecord iterStack [MaxStackSize]
char prevFieldArray [256]
StringStack STR
char sTraceBuffer [1024]
Public Functions
getFieldComponent(SimObject * object, StringTableEntry field, const char * array, StringTableEntry subField, char val)
setFieldComponent(SimObject * object, StringTableEntry field, const char * array, StringTableEntry subField)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 26// Copyright (C) 2015 Faust Logic, Inc. 27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 28 29#include "console/codeInterpreter.h" 30#include "console/compiler.h" 31#include "console/simBase.h" 32#include "console/telnetDebugger.h" 33#include "sim/netStringTable.h" 34#include "console/ICallMethod.h" 35#include "console/stringStack.h" 36#include "util/messaging/message.h" 37#include "core/strings/findMatch.h" 38#include "core/strings/stringUnit.h" 39#include "console/console.h" 40#include "console/consoleInternal.h" 41#include "cinterface/cinterface.h" 42 43//#define TORQUE_VALIDATE_STACK 44 45using namespace Compiler; 46 47enum EvalConstants 48{ 49 MaxStackSize = 1024, 50 FieldBufferSizeString = 2048, 51 FieldBufferSizeNumeric = 128, 52 MethodOnComponent = -2 53}; 54 55namespace Con 56{ 57 // Current script file name and root, these are registered as 58 // console variables. 59 extern StringTableEntry gCurrentFile; 60 extern StringTableEntry gCurrentRoot; 61 extern S32 gObjectCopyFailures; 62} 63 64// Gets a component of an object's field value or a variable and returns it 65// in val. 66static void getFieldComponent(SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField, char val[]) 67{ 68 const char* prevVal = NULL; 69 70 // Grab value from object. 71 if (object && field) 72 prevVal = object->getDataField(field, array); 73 74 // Otherwise, grab from the string stack. The value coming in will always 75 // be a string because that is how multicomponent variables are handled. 76 else 77 prevVal = STR.getStringValue(); 78 79 // Make sure we got a value. 80 if (prevVal && *prevVal) 81 { 82 static const StringTableEntry xyzw[] = 83 { 84 StringTable->insert("x"), 85 StringTable->insert("y"), 86 StringTable->insert("z"), 87 StringTable->insert("w") 88 }; 89 90 static const StringTableEntry rgba[] = 91 { 92 StringTable->insert("r"), 93 StringTable->insert("g"), 94 StringTable->insert("b"), 95 StringTable->insert("a") 96 }; 97 98 // Translate xyzw and rgba into the indexed component 99 // of the variable or field. 100 if (subField == xyzw[0] || subField == rgba[0]) 101 dStrcpy(val, StringUnit::getUnit(prevVal, 0, " \t\n"), 128); 102 103 else if (subField == xyzw[1] || subField == rgba[1]) 104 dStrcpy(val, StringUnit::getUnit(prevVal, 1, " \t\n"), 128); 105 106 else if (subField == xyzw[2] || subField == rgba[2]) 107 dStrcpy(val, StringUnit::getUnit(prevVal, 2, " \t\n"), 128); 108 109 else if (subField == xyzw[3] || subField == rgba[3]) 110 dStrcpy(val, StringUnit::getUnit(prevVal, 3, " \t\n"), 128); 111 112 else 113 val[0] = 0; 114 } 115 else 116 val[0] = 0; 117} 118 119// Sets a component of an object's field value based on the sub field. 'x' will 120// set the first field, 'y' the second, and 'z' the third. 121static void setFieldComponent(SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField) 122{ 123 // Copy the current string value 124 char strValue[1024]; 125 dStrncpy(strValue, STR.getStringValue(), 1024); 126 127 char val[1024] = ""; 128 const char* prevVal = NULL; 129 130 // Set the value on an object field. 131 if (object && field) 132 prevVal = object->getDataField(field, array); 133 134 // Set the value on a variable. 135 else if (gEvalState.currentVariable) 136 prevVal = gEvalState.getStringVariable(); 137 138 // Ensure that the variable has a value 139 if (!prevVal) 140 return; 141 142 static const StringTableEntry xyzw[] = 143 { 144 StringTable->insert("x"), 145 StringTable->insert("y"), 146 StringTable->insert("z"), 147 StringTable->insert("w") 148 }; 149 150 static const StringTableEntry rgba[] = 151 { 152 StringTable->insert("r"), 153 StringTable->insert("g"), 154 StringTable->insert("b"), 155 StringTable->insert("a") 156 }; 157 158 // Insert the value into the specified 159 // component of the string. 160 if (subField == xyzw[0] || subField == rgba[0]) 161 dStrcpy(val, StringUnit::setUnit(prevVal, 0, strValue, " \t\n"), 128); 162 163 else if (subField == xyzw[1] || subField == rgba[1]) 164 dStrcpy(val, StringUnit::setUnit(prevVal, 1, strValue, " \t\n"), 128); 165 166 else if (subField == xyzw[2] || subField == rgba[2]) 167 dStrcpy(val, StringUnit::setUnit(prevVal, 2, strValue, " \t\n"), 128); 168 169 else if (subField == xyzw[3] || subField == rgba[3]) 170 dStrcpy(val, StringUnit::setUnit(prevVal, 3, strValue, " \t\n"), 128); 171 172 if (val[0] != 0) 173 { 174 // Update the field or variable. 175 if (object && field) 176 object->setDataField(field, 0, val); 177 else if (gEvalState.currentVariable) 178 gEvalState.setStringVariable(val); 179 } 180} 181extern ExprEvalState gEvalState; 182 183char sTraceBuffer[1024]; 184 185StringStack STR; 186ConsoleValueStack CSTK; 187 188U32 _FLT = 0; ///< Stack pointer for floatStack. 189U32 _UINT = 0; ///< Stack pointer for intStack. 190U32 _ITER = 0; ///< Stack pointer for iterStack. 191 192IterStackRecord iterStack[MaxStackSize]; 193 194F64 floatStack[MaxStackSize]; 195S64 intStack[MaxStackSize]; 196 197char curFieldArray[256]; 198char prevFieldArray[256]; 199 200typedef OPCodeReturn(CodeInterpreter::*OpFn)(U32&); 201 202static OpFn gOpCodeArray[MAX_OP_CODELEN]; 203 204CodeInterpreter::CodeInterpreter(CodeBlock *cb) : 205 mCodeBlock(cb), 206 mIterDepth(0), 207 mCurFloatTable(nullptr), 208 mCurStringTable(nullptr), 209 mThisFunctionName(nullptr), 210 mPopFrame(false), 211 mObjectCreationStackIndex(0), 212 mCurrentNewObject(nullptr), 213 mFailJump(0), 214 mPrevField(nullptr), 215 mCurField(nullptr), 216 mPrevObject(nullptr), 217 mCurObject(nullptr), 218 mSaveObject(nullptr), 219 mThisObject(nullptr), 220 mNSEntry(nullptr), 221 mCurFNDocBlock(nullptr), 222 mCurNSDocBlock(nullptr), 223 mCallArgc(0), 224 mCallArgv(nullptr), 225 mSaveCodeBlock(nullptr), 226 mCurrentInstruction(0) 227{ 228 dMemset(&mExec, 0, sizeof(mExec)); 229 dMemset(&mObjectCreationStack, 0, sizeof(mObjectCreationStack)); 230 dMemset(&mNSDocBlockClass, 0, sizeof(mNSDocBlockClass)); 231} 232 233CodeInterpreter::~CodeInterpreter() 234{ 235} 236 237void CodeInterpreter::init() 238{ 239 gOpCodeArray[OP_FUNC_DECL] = &CodeInterpreter::op_func_decl; 240 gOpCodeArray[OP_CREATE_OBJECT] = &CodeInterpreter::op_create_object; 241 gOpCodeArray[OP_ADD_OBJECT] = &CodeInterpreter::op_add_object; 242 gOpCodeArray[OP_END_OBJECT] = &CodeInterpreter::op_end_object; 243 gOpCodeArray[OP_FINISH_OBJECT] = &CodeInterpreter::op_finish_object; 244 gOpCodeArray[OP_JMPIFFNOT] = &CodeInterpreter::op_jmpiffnot; 245 gOpCodeArray[OP_JMPIFNOT] = &CodeInterpreter::op_jmpifnot; 246 gOpCodeArray[OP_JMPIFF] = &CodeInterpreter::op_jmpiff; 247 gOpCodeArray[OP_JMPIF] = &CodeInterpreter::op_jmpif; 248 gOpCodeArray[OP_JMPIFNOT_NP] = &CodeInterpreter::op_jmpifnot_np; 249 gOpCodeArray[OP_JMPIF_NP] = &CodeInterpreter::op_jmpif_np; 250 gOpCodeArray[OP_JMP] = &CodeInterpreter::op_jmp; 251 gOpCodeArray[OP_RETURN] = &CodeInterpreter::op_return; 252 gOpCodeArray[OP_RETURN_VOID] = &CodeInterpreter::op_return_void; 253 gOpCodeArray[OP_RETURN_FLT] = &CodeInterpreter::op_return_flt; 254 gOpCodeArray[OP_RETURN_UINT] = &CodeInterpreter::op_return_uint; 255 gOpCodeArray[OP_CMPEQ] = &CodeInterpreter::op_cmpeq; 256 gOpCodeArray[OP_CMPGR] = &CodeInterpreter::op_cmpgr; 257 gOpCodeArray[OP_CMPGE] = &CodeInterpreter::op_cmpge; 258 gOpCodeArray[OP_CMPLT] = &CodeInterpreter::op_cmplt; 259 gOpCodeArray[OP_CMPLE] = &CodeInterpreter::op_cmple; 260 gOpCodeArray[OP_CMPNE] = &CodeInterpreter::op_cmpne; 261 gOpCodeArray[OP_XOR] = &CodeInterpreter::op_xor; 262 gOpCodeArray[OP_MOD] = &CodeInterpreter::op_mod; 263 gOpCodeArray[OP_BITAND] = &CodeInterpreter::op_bitand; 264 gOpCodeArray[OP_BITOR] = &CodeInterpreter::op_bitor; 265 gOpCodeArray[OP_NOT] = &CodeInterpreter::op_not; 266 gOpCodeArray[OP_NOTF] = &CodeInterpreter::op_notf; 267 gOpCodeArray[OP_ONESCOMPLEMENT] = &CodeInterpreter::op_onescomplement; 268 gOpCodeArray[OP_SHR] = &CodeInterpreter::op_shr; 269 gOpCodeArray[OP_SHL] = &CodeInterpreter::op_shl; 270 gOpCodeArray[OP_AND] = &CodeInterpreter::op_and; 271 gOpCodeArray[OP_OR] = &CodeInterpreter::op_or; 272 gOpCodeArray[OP_ADD] = &CodeInterpreter::op_add; 273 gOpCodeArray[OP_SUB] = &CodeInterpreter::op_sub; 274 gOpCodeArray[OP_MUL] = &CodeInterpreter::op_mul; 275 gOpCodeArray[OP_DIV] = &CodeInterpreter::op_div; 276 gOpCodeArray[OP_NEG] = &CodeInterpreter::op_neg; 277 gOpCodeArray[OP_INC] = &CodeInterpreter::op_inc; 278 gOpCodeArray[OP_DEC] = &CodeInterpreter::op_dec; 279 gOpCodeArray[OP_SETCURVAR] = &CodeInterpreter::op_setcurvar; 280 gOpCodeArray[OP_SETCURVAR_CREATE] = &CodeInterpreter::op_setcurvar_create; 281 gOpCodeArray[OP_SETCURVAR_ARRAY] = &CodeInterpreter::op_setcurvar_array; 282 gOpCodeArray[OP_SETCURVAR_ARRAY_VARLOOKUP] = &CodeInterpreter::op_setcurvar_array_varlookup; 283 gOpCodeArray[OP_SETCURVAR_ARRAY_CREATE] = &CodeInterpreter::op_setcurvar_array_create; 284 gOpCodeArray[OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP] = &CodeInterpreter::op_setcurvar_array_create_varlookup; 285 gOpCodeArray[OP_LOADVAR_UINT] = &CodeInterpreter::op_loadvar_uint; 286 gOpCodeArray[OP_LOADVAR_FLT] = &CodeInterpreter::op_loadvar_flt; 287 gOpCodeArray[OP_LOADVAR_STR] = &CodeInterpreter::op_loadvar_str; 288 gOpCodeArray[OP_LOADVAR_VAR] = &CodeInterpreter::op_loadvar_var; 289 gOpCodeArray[OP_SAVEVAR_UINT] = &CodeInterpreter::op_savevar_uint; 290 gOpCodeArray[OP_SAVEVAR_FLT] = &CodeInterpreter::op_savevar_flt; 291 gOpCodeArray[OP_SAVEVAR_STR] = &CodeInterpreter::op_savevar_str; 292 gOpCodeArray[OP_SAVEVAR_VAR] = &CodeInterpreter::op_savevar_var; 293 gOpCodeArray[OP_SETCUROBJECT] = &CodeInterpreter::op_setcurobject; 294 gOpCodeArray[OP_SETCUROBJECT_INTERNAL] = &CodeInterpreter::op_setcurobject_internal; 295 gOpCodeArray[OP_SETCUROBJECT_NEW] = &CodeInterpreter::op_setcurobject_new; 296 gOpCodeArray[OP_SETCURFIELD] = &CodeInterpreter::op_setcurfield; 297 gOpCodeArray[OP_SETCURFIELD_ARRAY] = &CodeInterpreter::op_setcurfield_array; 298 gOpCodeArray[OP_SETCURFIELD_TYPE] = &CodeInterpreter::op_setcurfield_type; 299 gOpCodeArray[OP_SETCURFIELD_ARRAY_VAR] = &CodeInterpreter::op_setcurfield_array_var; 300 gOpCodeArray[OP_SETCURFIELD_THIS] = &CodeInterpreter::op_setcurfield_this; 301 gOpCodeArray[OP_LOADFIELD_UINT] = &CodeInterpreter::op_loadfield_uint; 302 gOpCodeArray[OP_LOADFIELD_FLT] = &CodeInterpreter::op_loadfield_flt; 303 gOpCodeArray[OP_LOADFIELD_STR] = &CodeInterpreter::op_loadfield_str; 304 gOpCodeArray[OP_SAVEFIELD_UINT] = &CodeInterpreter::op_savefield_uint; 305 gOpCodeArray[OP_SAVEFIELD_FLT] = &CodeInterpreter::op_savefield_flt; 306 gOpCodeArray[OP_SAVEFIELD_STR] = &CodeInterpreter::op_savefield_str; 307 gOpCodeArray[OP_STR_TO_UINT] = &CodeInterpreter::op_str_to_uint; 308 gOpCodeArray[OP_STR_TO_FLT] = &CodeInterpreter::op_str_to_flt; 309 gOpCodeArray[OP_STR_TO_NONE] = &CodeInterpreter::op_str_to_none; 310 gOpCodeArray[OP_FLT_TO_UINT] = &CodeInterpreter::op_flt_to_uint; 311 gOpCodeArray[OP_FLT_TO_STR] = &CodeInterpreter::op_flt_to_str; 312 gOpCodeArray[OP_FLT_TO_NONE] = &CodeInterpreter::op_flt_to_none; 313 gOpCodeArray[OP_UINT_TO_FLT] = &CodeInterpreter::op_uint_to_flt; 314 gOpCodeArray[OP_UINT_TO_STR] = &CodeInterpreter::op_uint_to_str; 315 gOpCodeArray[OP_UINT_TO_NONE] = &CodeInterpreter::op_uint_to_none; 316 gOpCodeArray[OP_COPYVAR_TO_NONE] = &CodeInterpreter::op_copyvar_to_none; 317 gOpCodeArray[OP_LOADIMMED_UINT] = &CodeInterpreter::op_loadimmed_uint; 318 gOpCodeArray[OP_LOADIMMED_FLT] = &CodeInterpreter::op_loadimmed_flt; 319 gOpCodeArray[OP_TAG_TO_STR] = &CodeInterpreter::op_tag_to_str; 320 gOpCodeArray[OP_LOADIMMED_STR] = &CodeInterpreter::op_loadimmed_str; 321 gOpCodeArray[OP_DOCBLOCK_STR] = &CodeInterpreter::op_docblock_str; 322 gOpCodeArray[OP_LOADIMMED_IDENT] = &CodeInterpreter::op_loadimmed_ident; 323 gOpCodeArray[OP_CALLFUNC_RESOLVE] = &CodeInterpreter::op_callfunc_resolve; 324 gOpCodeArray[OP_CALLFUNC] = &CodeInterpreter::op_callfunc; 325 gOpCodeArray[OP_CALLFUNC_POINTER] = &CodeInterpreter::op_callfunc_pointer; 326 gOpCodeArray[OP_CALLFUNC_THIS] = &CodeInterpreter::op_callfunc_this; 327 gOpCodeArray[OP_ADVANCE_STR] = &CodeInterpreter::op_advance_str; 328 gOpCodeArray[OP_ADVANCE_STR_APPENDCHAR] = &CodeInterpreter::op_advance_str_appendchar; 329 gOpCodeArray[OP_ADVANCE_STR_COMMA] = &CodeInterpreter::op_advance_str_comma; 330 gOpCodeArray[OP_ADVANCE_STR_NUL] = &CodeInterpreter::op_advance_str_nul; 331 gOpCodeArray[OP_REWIND_STR] = &CodeInterpreter::op_rewind_str; 332 gOpCodeArray[OP_TERMINATE_REWIND_STR] = &CodeInterpreter::op_terminate_rewind_str; 333 gOpCodeArray[OP_COMPARE_STR] = &CodeInterpreter::op_compare_str; 334 gOpCodeArray[OP_PUSH] = &CodeInterpreter::op_push; 335 gOpCodeArray[OP_PUSH_UINT] = &CodeInterpreter::op_push_uint; 336 gOpCodeArray[OP_PUSH_FLT] = &CodeInterpreter::op_push_flt; 337 gOpCodeArray[OP_PUSH_VAR] = &CodeInterpreter::op_push_var; 338 gOpCodeArray[OP_PUSH_THIS] = &CodeInterpreter::op_push_this; 339 gOpCodeArray[OP_PUSH_FRAME] = &CodeInterpreter::op_push_frame; 340 gOpCodeArray[OP_ASSERT] = &CodeInterpreter::op_assert; 341 gOpCodeArray[OP_BREAK] = &CodeInterpreter::op_break; 342 gOpCodeArray[OP_ITER_BEGIN_STR] = &CodeInterpreter::op_iter_begin_str; 343 gOpCodeArray[OP_ITER_BEGIN] = &CodeInterpreter::op_iter_begin; 344 gOpCodeArray[OP_ITER] = &CodeInterpreter::op_iter; 345 gOpCodeArray[OP_ITER_END] = &CodeInterpreter::op_iter_end; 346 gOpCodeArray[OP_INVALID] = &CodeInterpreter::op_invalid; 347} 348 349ConsoleValueRef CodeInterpreter::exec(U32 ip, 350 StringTableEntry functionName, 351 Namespace *thisNamespace, 352 U32 argc, 353 ConsoleValueRef *argv, 354 bool noCalls, 355 StringTableEntry packageName, 356 S32 setFrame) 357{ 358 mExec.functionName = functionName; 359 mExec.thisNamespace = thisNamespace; 360 mExec.argc = argc; 361 mExec.argv = argv; 362 mExec.noCalls = noCalls; 363 mExec.packageName = packageName; 364 mExec.setFrame = setFrame; 365 366 mCodeBlock->incRefCount(); 367 368 mPopFrame = false; 369 370#ifdef TORQUE_VALIDATE_STACK 371 U32 stackStart = STR.mStartStackSize; 372#endif 373 374 STR.clearFunctionOffset(); // ensures arg buffer offset is back to 0 375 376 // Lets load up our function arguments. 377 parseArgs(ip); 378 379 // Grab the state of the telenet debugger here once 380 // so that the push and pop frames are always balanced. 381 const bool telDebuggerOn = TelDebugger && TelDebugger->isConnected(); 382 if (telDebuggerOn && setFrame < 0) 383 TelDebugger->pushStackFrame(); 384 385 mSaveCodeBlock = CodeBlock::smCurrentCodeBlock; 386 CodeBlock::smCurrentCodeBlock = mCodeBlock; 387 if (mCodeBlock->name) 388 { 389 Con::gCurrentFile = mCodeBlock->name; 390 Con::gCurrentRoot = mCodeBlock->modPath; 391 } 392 393 U32 *code = mCodeBlock->code; 394 395 while (true) 396 { 397 mCurrentInstruction = code[ip++]; 398 mNSEntry = nullptr; 399 400#ifdef TORQUE_VALIDATE_STACK 401 // OP Code check. 402 AssertFatal(mCurrentInstruction < MAX_OP_CODELEN, "Invalid OP code in script interpreter"); 403#endif 404 405 breakContinueLabel: 406 OPCodeReturn ret = (this->*gOpCodeArray[mCurrentInstruction])(ip); 407 if (ret == OPCodeReturn::exitCode) 408 break; 409 else if (ret == OPCodeReturn::breakContinue) 410 goto breakContinueLabel; 411 } 412 413 if (telDebuggerOn && setFrame < 0) 414 TelDebugger->popStackFrame(); 415 416 if (mPopFrame) 417 gEvalState.popFrame(); 418 419 if (argv) 420 { 421 if (gEvalState.traceOn) 422 { 423 sTraceBuffer[0] = 0; 424 dStrcat(sTraceBuffer, "Leaving ", 1024); 425 426 if (packageName) 427 { 428 dStrcat(sTraceBuffer, "[", 1024); 429 dStrcat(sTraceBuffer, packageName, 1024); 430 dStrcat(sTraceBuffer, "]", 1024); 431 } 432 if (thisNamespace && thisNamespace->mName) 433 { 434 dSprintf(sTraceBuffer + dStrlen(sTraceBuffer), (U32)(sizeof(sTraceBuffer) - dStrlen(sTraceBuffer)), 435 "%s::%s() - return %s", thisNamespace->mName, mThisFunctionName, STR.getStringValue()); 436 } 437 else 438 { 439 dSprintf(sTraceBuffer + dStrlen(sTraceBuffer), (U32)(sizeof(sTraceBuffer) - dStrlen(sTraceBuffer)), 440 "%s() - return %s", mThisFunctionName, STR.getStringValue()); 441 } 442 Con::printf("%s", sTraceBuffer); 443 } 444 } 445 446 CodeBlock::smCurrentCodeBlock = mSaveCodeBlock; 447 if (mSaveCodeBlock && mSaveCodeBlock->name) 448 { 449 Con::gCurrentFile = mSaveCodeBlock->name; 450 Con::gCurrentRoot = mSaveCodeBlock->modPath; 451 } 452 453 mCodeBlock->decRefCount(); 454 455#ifdef TORQUE_VALIDATE_STACK 456 AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec"); 457 AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec"); 458#endif 459 460 return mReturnValue; 461} 462 463void CodeInterpreter::parseArgs(U32 &ip) 464{ 465 U32 *code = mCodeBlock->code; 466 467 if (mExec.argv) 468 { 469 U32 fnArgc = code[ip + 2 + 6]; 470 mThisFunctionName = Compiler::CodeToSTE(code, ip); 471 S32 wantedArgc = getMin(mExec.argc - 1, fnArgc); // argv[0] is func name 472 if (gEvalState.traceOn) 473 { 474 sTraceBuffer[0] = 0; 475 dStrcat(sTraceBuffer, "Entering ", 1024); 476 477 if (mExec.packageName) 478 { 479 dStrcat(sTraceBuffer, "[", 1024); 480 dStrcat(sTraceBuffer, mExec.packageName, 1024); 481 dStrcat(sTraceBuffer, "]", 1024); 482 } 483 if (mExec.thisNamespace && mExec.thisNamespace->mName) 484 { 485 dSprintf(sTraceBuffer + dStrlen(sTraceBuffer), (U32)(sizeof(sTraceBuffer) - dStrlen(sTraceBuffer)), 486 "%s::%s(", mExec.thisNamespace->mName, mThisFunctionName); 487 } 488 else 489 { 490 dSprintf(sTraceBuffer + dStrlen(sTraceBuffer), (U32)(sizeof(sTraceBuffer) - dStrlen(sTraceBuffer)), 491 "%s(", mThisFunctionName); 492 } 493 for (S32 i = 0; i < wantedArgc; i++) 494 { 495 dStrcat(sTraceBuffer, mExec.argv[i + 1], 1024); 496 if (i != wantedArgc - 1) 497 dStrcat(sTraceBuffer, ", ", 1024); 498 } 499 dStrcat(sTraceBuffer, ")", 1024); 500 Con::printf("%s", sTraceBuffer); 501 } 502 503 gEvalState.pushFrame(mThisFunctionName, mExec.thisNamespace); 504 mPopFrame = true; 505 506 StringTableEntry thisPointer = StringTable->insert("%this"); 507 508 for (S32 i = 0; i < wantedArgc; i++) 509 { 510 StringTableEntry var = Compiler::CodeToSTE(code, ip + (2 + 6 + 1) + (i * 2)); 511 gEvalState.setCurVarNameCreate(var); 512 513 ConsoleValueRef ref = mExec.argv[i + 1]; 514 515 switch (ref.getType()) 516 { 517 case ConsoleValue::TypeInternalInt: 518 gEvalState.setIntVariable(ref); 519 break; 520 case ConsoleValue::TypeInternalFloat: 521 gEvalState.setFloatVariable(ref); 522 break; 523 case ConsoleValue::TypeInternalStringStackPtr: 524 gEvalState.setStringStackPtrVariable(ref.getStringStackPtrValue()); 525 break; 526 case ConsoleValue::TypeInternalStackString: 527 case ConsoleValue::TypeInternalString: 528 default: 529 gEvalState.setStringVariable(ref); 530 break; 531 } 532 533 if (var == thisPointer) 534 { 535 // %this gets optimized as it is flagged as a constant. 536 // Since it is guarenteed to be constant, we can then perform optimizations. 537 gEvalState.currentVariable->mIsConstant = true; 538 539 // Store a reference to the this pointer object. 540 mThisObject = Sim::findObject(gEvalState.getStringVariable()); 541 } 542 } 543 544 ip = ip + (fnArgc * 2) + (2 + 6 + 1); 545 mCurFloatTable = mCodeBlock->functionFloats; 546 mCurStringTable = mCodeBlock->functionStrings; 547 } 548 else 549 { 550 mCurFloatTable = mCodeBlock->globalFloats; 551 mCurStringTable = mCodeBlock->globalStrings; 552 553 // If requested stack frame isn't available, request a new one 554 // (this prevents assert failures when creating local 555 // variables without a stack frame) 556 if (gEvalState.getStackDepth() <= mExec.setFrame) 557 mExec.setFrame = -1; 558 559 // Do we want this code to execute using a new stack frame? 560 if (mExec.setFrame < 0) 561 { 562 gEvalState.pushFrame(NULL, NULL); 563 mPopFrame = true; 564 } 565 else 566 { 567 // We want to copy a reference to an existing stack frame 568 // on to the top of the stack. Any change that occurs to 569 // the locals during this new frame will also occur in the 570 // original frame. 571 S32 stackIndex = gEvalState.getStackDepth() - mExec.setFrame - 1; 572 gEvalState.pushFrameRef(stackIndex); 573 mPopFrame = true; 574 } 575 } 576} 577 578OPCodeReturn CodeInterpreter::op_func_decl(U32 &ip) 579{ 580 U32 *code = mCodeBlock->code; 581 582 if (!mExec.noCalls) 583 { 584 StringTableEntry fnName = CodeToSTE(code, ip); 585 StringTableEntry fnNamespace = CodeToSTE(code, ip + 2); 586 StringTableEntry fnPackage = CodeToSTE(code, ip + 4); 587 bool hasBody = (code[ip + 6] & 0x01) != 0; 588 U32 lineNumber = code[ip + 6] >> 1; 589 590 Namespace::unlinkPackages(); 591 Namespace *ns = Namespace::find(fnNamespace, fnPackage); 592 ns->addFunction(fnName, mCodeBlock, hasBody ? ip : 0, mCurFNDocBlock ? dStrdup(mCurFNDocBlock) : NULL, lineNumber);// if no body, set the IP to 0 593 if (mCurNSDocBlock) 594 { 595 // If we have a docblock before we declare the function in the script file, 596 // this will attempt to set the doc block to the function. 597 // See OP_DOCBLOCK_STR 598 if (fnNamespace == StringTable->lookup(mNSDocBlockClass)) 599 { 600 char *usageStr = dStrdup(mCurNSDocBlock); 601 usageStr[dStrlen(usageStr)] = '\0'; 602 ns->mUsage = usageStr; 603 ns->mCleanUpUsage = true; 604 mCurNSDocBlock = NULL; 605 } 606 } 607 Namespace::relinkPackages(); 608 609 // If we had a docblock, it's definitely not valid anymore, so clear it out. 610 mCurFNDocBlock = NULL; 611 612 //Con::printf("Adding function %s::%s (%d)", fnNamespace, fnName, ip); 613 } 614 ip = code[ip + 7]; 615 return OPCodeReturn::success; 616} 617 618OPCodeReturn CodeInterpreter::op_create_object(U32 &ip) 619{ 620 U32 *code = mCodeBlock->code; 621 622 // Read some useful info. 623 StringTableEntry objParent = CodeToSTE(code, ip); 624 bool isDataBlock = code[ip + 2]; 625 bool isInternal = code[ip + 3]; 626 bool isSingleton = code[ip + 4]; 627 U32 lineNumber = code[ip + 5]; 628 mFailJump = code[ip + 6]; 629 630 // If we don't allow calls, we certainly don't allow creating objects! 631 // Moved this to after failJump is set. Engine was crashing when 632 // noCalls = true and an object was being created at the beginning of 633 // a file. ADL. 634 if (mExec.noCalls) 635 { 636 ip = mFailJump; 637 return OPCodeReturn::success; 638 } 639 640 // Push the old info to the stack 641 //Assert( objectCreationStackIndex < objectCreationStackSize ); 642 mObjectCreationStack[mObjectCreationStackIndex].newObject = mCurrentNewObject; 643 mObjectCreationStack[mObjectCreationStackIndex++].failJump = mFailJump; 644 645 // Get the constructor information off the stack. 646 CSTK.getArgcArgv(NULL, &mCallArgc, &mCallArgv); 647 const char *objectName = mCallArgv[2]; 648 649 // Con::printf("Creating object..."); 650 651 // objectName = argv[1]... 652 mCurrentNewObject = NULL; 653 654 // Are we creating a datablock? If so, deal with case where we override 655 // an old one. 656 if (isDataBlock) 657 { 658 // Con::printf(" - is a datablock"); 659 660 // Find the old one if any. 661 SimObject *db = Sim::getDataBlockGroup()->findObject(objectName); 662 663 // Make sure we're not changing types on ourselves... 664 if (db && dStricmp(db->getClassName(), mCallArgv[1])) 665 { 666 Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare data block %s with a different class.", mCodeBlock->getFileLine(ip), objectName); 667 ip = mFailJump; 668 STR.popFrame(); 669 CSTK.popFrame(); 670 return OPCodeReturn::success; 671 } 672 673 // If there was one, set the currentNewObject and move on. 674 if (db) 675 mCurrentNewObject = db; 676 } 677 else if (!isInternal) 678 { 679 // IF we aren't looking at a local/internal object, then check if 680 // this object already exists in the global space 681 682 AbstractClassRep* rep = AbstractClassRep::findClassRep(objectName); 683 if (rep != NULL) { 684 Con::errorf(ConsoleLogEntry::General, "%s: Cannot name object [%s] the same name as a script class.", 685 mCodeBlock->getFileLine(ip), objectName); 686 ip = mFailJump; 687 STR.popFrame(); 688 CSTK.popFrame(); 689 return OPCodeReturn::success; 690 } 691 692 SimObject *obj = Sim::findObject((const char*)objectName); 693 if (obj /*&& !obj->isLocalName()*/) 694 { 695 if (isSingleton) 696 { 697 // Make sure we're not trying to change types 698 if (dStricmp(obj->getClassName(), (const char*)mCallArgv[1]) != 0) 699 { 700 Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare object [%s] with a different class [%s] - was [%s].", 701 mCodeBlock->getFileLine(ip), objectName, (const char*)mCallArgv[1], obj->getClassName()); 702 ip = mFailJump; 703 STR.popFrame(); 704 CSTK.popFrame(); 705 return OPCodeReturn::success; 706 } 707 708 // We're creating a singleton, so use the found object 709 // instead of creating a new object. 710 mCurrentNewObject = obj; 711 } 712 else 713 { 714 const char* redefineBehavior = Con::getVariable("$Con::redefineBehavior"); 715 716 if (dStricmp(redefineBehavior, "replaceExisting") == 0) 717 { 718 // Save our constructor args as the argv vector is stored on the 719 // string stack and may get stomped if deleteObject triggers 720 // script execution. 721 722 ConsoleValueRef savedArgv[StringStack::MaxArgs]; 723 for (int i = 0; i< mCallArgc; i++) { 724 savedArgv[i] = mCallArgv[i]; 725 } 726 //dMemcpy( savedArgv, callArgv, sizeof( savedArgv[ 0 ] ) * callArgc ); 727 728 // Prevent stack value corruption 729 CSTK.pushFrame(); 730 STR.pushFrame(); 731 // -- 732 733 obj->deleteObject(); 734 obj = NULL; 735 736 // Prevent stack value corruption 737 CSTK.popFrame(); 738 STR.popFrame(); 739 // -- 740 741 //dMemcpy( callArgv, savedArgv, sizeof( callArgv[ 0 ] ) * callArgc ); 742 for (int i = 0; i<mCallArgc; i++) { 743 mCallArgv[i] = savedArgv[i]; 744 } 745 } 746 else if (dStricmp(redefineBehavior, "renameNew") == 0) 747 { 748 for (U32 i = 1;; ++i) 749 { 750 String newName = String::ToString("%s%i", objectName, i); 751 if (!Sim::findObject(newName)) 752 { 753 objectName = StringTable->insert(newName); 754 break; 755 } 756 } 757 } 758 else if (dStricmp(redefineBehavior, "unnameNew") == 0) 759 { 760 objectName = StringTable->insert(""); 761 } 762 else if (dStricmp(redefineBehavior, "postfixNew") == 0) 763 { 764 const char* postfix = Con::getVariable("$Con::redefineBehaviorPostfix"); 765 String newName = String::ToString("%s%s", objectName, postfix); 766 767 if (Sim::findObject(newName)) 768 { 769 Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare object with postfix [%s].", 770 mCodeBlock->getFileLine(ip), newName.c_str()); 771 ip = mFailJump; 772 STR.popFrame(); 773 CSTK.popFrame(); 774 return OPCodeReturn::success; 775 } 776 else 777 objectName = StringTable->insert(newName); 778 } 779 else 780 { 781 Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare object [%s].", 782 mCodeBlock->getFileLine(ip), objectName); 783 ip = mFailJump; 784 STR.popFrame(); 785 CSTK.popFrame(); 786 return OPCodeReturn::success; 787 } 788 } 789 } 790 } 791 792 STR.popFrame(); 793 CSTK.popFrame(); 794 795 if (!mCurrentNewObject) 796 { 797 // Well, looks like we have to create a new object. 798 ConsoleObject *object = ConsoleObject::create((const char*)mCallArgv[1]); 799 800 // Deal with failure! 801 if (!object) 802 { 803 Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-conobject class %s.", mCodeBlock->getFileLine(ip), (const char*)mCallArgv[1]); 804 ip = mFailJump; 805 return OPCodeReturn::success; 806 } 807 808 // Do special datablock init if appropros 809 if (isDataBlock) 810 { 811 SimDataBlock *dataBlock = dynamic_cast<SimDataBlock *>(object); 812 if (dataBlock) 813 { 814 dataBlock->assignId(); 815 } 816 else 817 { 818 // They tried to make a non-datablock with a datablock keyword! 819 Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-datablock class %s.", mCodeBlock->getFileLine(ip), (const char*)mCallArgv[1]); 820 // Clean up... 821 delete object; 822 mCurrentNewObject = NULL; 823 ip = mFailJump; 824 return OPCodeReturn::success; 825 } 826 } 827 828 // Finally, set currentNewObject to point to the new one. 829 mCurrentNewObject = dynamic_cast<SimObject *>(object); 830 831 // Deal with the case of a non-SimObject. 832 if (!mCurrentNewObject) 833 { 834 Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-SimObject class %s.", mCodeBlock->getFileLine(ip), (const char*)mCallArgv[1]); 835 delete object; 836 mCurrentNewObject = NULL; 837 ip = mFailJump; 838 return OPCodeReturn::success; 839 } 840 841 // Set the declaration line 842 mCurrentNewObject->setDeclarationLine(lineNumber); 843 844 // Set the file that this object was created in 845 mCurrentNewObject->setFilename(mCodeBlock->name); 846 847 // Does it have a parent object? (ie, the copy constructor : syntax, not inheriance) 848 if (*objParent) 849 { 850 // Find it! 851 SimObject *parent; 852 if (Sim::findObject(objParent, parent)) 853 { 854 // Con::printf(" - Parent object found: %s", parent->getClassName()); 855 856 mCurrentNewObject->setCopySource(parent); 857 mCurrentNewObject->assignFieldsFrom(parent); 858 859 // copy any substitution statements 860 SimDataBlock* parent_db = dynamic_cast<SimDataBlock*>(parent); 861 if (parent_db) 862 { 863 SimDataBlock* currentNewObject_db = dynamic_cast<SimDataBlock*>(mCurrentNewObject); 864 if (currentNewObject_db) 865 currentNewObject_db->copySubstitutionsFrom(parent_db); 866 } 867 } 868 else 869 { 870 if (Con::gObjectCopyFailures == -1) 871 Con::errorf(ConsoleLogEntry::General, "%s: Unable to find parent object %s for %s.", mCodeBlock->getFileLine(ip), objParent, (const char*)mCallArgv[1]); 872 else 873 ++Con::gObjectCopyFailures; 874 875 // Fail to create the object. 876 delete object; 877 mCurrentNewObject = NULL; 878 ip = mFailJump; 879 return OPCodeReturn::success; 880 } 881 } 882 883 // If a name was passed, assign it. 884 if (objectName[0]) 885 { 886 if (!isInternal) 887 mCurrentNewObject->assignName(objectName); 888 else 889 mCurrentNewObject->setInternalName(objectName); 890 891 // Set the original name 892 mCurrentNewObject->setOriginalName(objectName); 893 } 894 895 // Prevent stack value corruption 896 CSTK.pushFrame(); 897 STR.pushFrame(); 898 // -- 899 900 // Do the constructor parameters. 901 if (!mCurrentNewObject->processArguments(mCallArgc - 3, mCallArgv + 3)) 902 { 903 delete mCurrentNewObject; 904 mCurrentNewObject = NULL; 905 ip = mFailJump; 906 907 // Prevent stack value corruption 908 CSTK.popFrame(); 909 STR.popFrame(); 910 // -- 911 return OPCodeReturn::success; 912 } 913 914 // Prevent stack value corruption 915 CSTK.popFrame(); 916 STR.popFrame(); 917 // -- 918 919 // If it's not a datablock, allow people to modify bits of it. 920 if (!isDataBlock) 921 { 922 mCurrentNewObject->setModStaticFields(true); 923 mCurrentNewObject->setModDynamicFields(true); 924 } 925 } 926 else 927 { 928 mCurrentNewObject->reloadReset(); // AFX (reload-reset) 929 // Does it have a parent object? (ie, the copy constructor : syntax, not inheriance) 930 if (*objParent) 931 { 932 // Find it! 933 SimObject *parent; 934 if (Sim::findObject(objParent, parent)) 935 { 936 // Con::printf(" - Parent object found: %s", parent->getClassName()); 937 938 // temporarily block name change 939 SimObject::preventNameChanging = true; 940 mCurrentNewObject->setCopySource(parent); 941 mCurrentNewObject->assignFieldsFrom(parent); 942 // restore name changing 943 SimObject::preventNameChanging = false; 944 945 // copy any substitution statements 946 SimDataBlock* parent_db = dynamic_cast<SimDataBlock*>(parent); 947 if (parent_db) 948 { 949 SimDataBlock* currentNewObject_db = dynamic_cast<SimDataBlock*>(mCurrentNewObject); 950 if (currentNewObject_db) 951 currentNewObject_db->copySubstitutionsFrom(parent_db); 952 } 953 } 954 else 955 Con::errorf(ConsoleLogEntry::General, "%d: Unable to find parent object %s for %s.", lineNumber, objParent, (const char*)mCallArgv[1]); 956 } 957 } 958 959 // Advance the IP past the create info... 960 ip += 7; 961 return OPCodeReturn::success; 962} 963 964OPCodeReturn CodeInterpreter::op_add_object(U32 &ip) 965{ 966 // See OP_SETCURVAR for why we do this. 967 mCurFNDocBlock = NULL; 968 mCurNSDocBlock = NULL; 969 970 // Do we place this object at the root? 971 bool placeAtRoot = mCodeBlock->code[ip++]; 972 973 // Con::printf("Adding object %s", currentNewObject->getName()); 974 975 // Prevent stack value corruption 976 CSTK.pushFrame(); 977 STR.pushFrame(); 978 // -- 979 980 // Make sure it wasn't already added, then add it. 981 if (mCurrentNewObject->isProperlyAdded() == false) 982 { 983 bool ret = false; 984 985 Message *msg = dynamic_cast<Message *>(mCurrentNewObject); 986 if (msg) 987 { 988 SimObjectId id = Message::getNextMessageID(); 989 if (id != 0xffffffff) 990 ret = mCurrentNewObject->registerObject(id); 991 else 992 Con::errorf("%s: No more object IDs available for messages", mCodeBlock->getFileLine(ip)); 993 } 994 else 995 ret = mCurrentNewObject->registerObject(); 996 997 if (!ret) 998 { 999 // This error is usually caused by failing to call Parent::initPersistFields in the class' initPersistFields(). 1000 Con::warnf(ConsoleLogEntry::General, "%s: Register object failed for object %s of class %s.", mCodeBlock->getFileLine(ip), mCurrentNewObject->getName(), mCurrentNewObject->getClassName()); 1001 delete mCurrentNewObject; 1002 mCurrentNewObject = NULL; 1003 ip = mFailJump; 1004 // Prevent stack value corruption 1005 CSTK.popFrame(); 1006 STR.popFrame(); 1007 // -- 1008 return OPCodeReturn::success; 1009 } 1010 } 1011 1012 // Are we dealing with a datablock? 1013 SimDataBlock *dataBlock = dynamic_cast<SimDataBlock *>(mCurrentNewObject); 1014 static String errorStr; 1015 1016 // If so, preload it. 1017 if (dataBlock && !dataBlock->preload(true, errorStr)) 1018 { 1019 Con::errorf(ConsoleLogEntry::General, "%s: preload failed for %s: %s.", mCodeBlock->getFileLine(ip), 1020 mCurrentNewObject->getName(), errorStr.c_str()); 1021 dataBlock->deleteObject(); 1022 mCurrentNewObject = NULL; 1023 ip = mFailJump; 1024 1025 // Prevent stack value corruption 1026 CSTK.popFrame(); 1027 STR.popFrame(); 1028 // -- 1029 return OPCodeReturn::success; 1030 } 1031 1032 // What group will we be added to, if any? 1033 U32 groupAddId = intStack[_UINT]; 1034 SimGroup *grp = NULL; 1035 SimSet *set = NULL; 1036 bool isMessage = dynamic_cast<Message *>(mCurrentNewObject) != NULL; 1037 1038 if (!placeAtRoot || !mCurrentNewObject->getGroup()) 1039 { 1040 if (!isMessage) 1041 { 1042 if (!placeAtRoot) 1043 { 1044 // Otherwise just add to the requested group or set. 1045 if (!Sim::findObject(groupAddId, grp)) 1046 Sim::findObject(groupAddId, set); 1047 } 1048 1049 if (placeAtRoot) 1050 { 1051 // Deal with the instantGroup if we're being put at the root or we're adding to a component. 1052 if (Con::gInstantGroup.isEmpty() 1053 || !Sim::findObject(Con::gInstantGroup, grp)) 1054 grp = Sim::getRootGroup(); 1055 } 1056 } 1057 1058 // If we didn't get a group, then make sure we have a pointer to 1059 // the rootgroup. 1060 if (!grp) 1061 grp = Sim::getRootGroup(); 1062 1063 // add to the parent group 1064 grp->addObject(mCurrentNewObject); 1065 1066 // If for some reason the add failed, add the object to the 1067 // root group so it won't leak. 1068 if (!mCurrentNewObject->getGroup()) 1069 Sim::getRootGroup()->addObject(mCurrentNewObject); 1070 1071 // add to any set we might be in 1072 if (set) 1073 set->addObject(mCurrentNewObject); 1074 } 1075 1076 // store the new object's ID on the stack (overwriting the group/set 1077 // id, if one was given, otherwise getting pushed) 1078 if (placeAtRoot) 1079 intStack[_UINT] = mCurrentNewObject->getId(); 1080 else 1081 intStack[++_UINT] = mCurrentNewObject->getId(); 1082 1083 // Prevent stack value corruption 1084 CSTK.popFrame(); 1085 STR.popFrame(); 1086 // -- 1087 return OPCodeReturn::success; 1088} 1089 1090OPCodeReturn CodeInterpreter::op_end_object(U32 &ip) 1091{ 1092 // If we're not to be placed at the root, make sure we clean up 1093 // our group reference. 1094 bool placeAtRoot = mCodeBlock->code[ip++]; 1095 if (!placeAtRoot) 1096 _UINT--; 1097 return OPCodeReturn::success; 1098} 1099 1100OPCodeReturn CodeInterpreter::op_finish_object(U32 &ip) 1101{ 1102 if (mCurrentNewObject) 1103 mCurrentNewObject->onPostAdd(); 1104 1105 //Assert( objectCreationStackIndex >= 0 ); 1106 // Restore the object info from the stack [7/9/2007 Black] 1107 mCurrentNewObject = mObjectCreationStack[--mObjectCreationStackIndex].newObject; 1108 mFailJump = mObjectCreationStack[mObjectCreationStackIndex].failJump; 1109 return OPCodeReturn::success; 1110} 1111 1112OPCodeReturn CodeInterpreter::op_jmpiffnot(U32 &ip) 1113{ 1114 if (floatStack[_FLT--]) 1115 { 1116 ip++; 1117 return OPCodeReturn::success; 1118 } 1119 ip = mCodeBlock->code[ip]; 1120 return OPCodeReturn::success; 1121} 1122 1123 1124OPCodeReturn CodeInterpreter::op_jmpifnot(U32 &ip) 1125{ 1126 if (intStack[_UINT--]) 1127 { 1128 ip++; 1129 return OPCodeReturn::success; 1130 } 1131 ip = mCodeBlock->code[ip]; 1132 return OPCodeReturn::success; 1133} 1134 1135OPCodeReturn CodeInterpreter::op_jmpiff(U32 &ip) 1136{ 1137 if (!floatStack[_FLT--]) 1138 { 1139 ip++; 1140 return OPCodeReturn::success; 1141 } 1142 ip = mCodeBlock->code[ip]; 1143 return OPCodeReturn::success; 1144} 1145 1146OPCodeReturn CodeInterpreter::op_jmpif(U32 &ip) 1147{ 1148 if (!intStack[_UINT--]) 1149 { 1150 ip++; 1151 return OPCodeReturn::success; 1152 } 1153 ip = mCodeBlock->code[ip]; 1154 return OPCodeReturn::success; 1155} 1156 1157OPCodeReturn CodeInterpreter::op_jmpifnot_np(U32 &ip) 1158{ 1159 if (intStack[_UINT]) 1160 { 1161 _UINT--; 1162 ip++; 1163 return OPCodeReturn::success; 1164 } 1165 ip = mCodeBlock->code[ip]; 1166 return OPCodeReturn::success; 1167} 1168 1169OPCodeReturn CodeInterpreter::op_jmpif_np(U32 &ip) 1170{ 1171 if (!intStack[_UINT]) 1172 { 1173 _UINT--; 1174 ip++; 1175 return OPCodeReturn::success; 1176 } 1177 ip = mCodeBlock->code[ip]; 1178 return OPCodeReturn::success; 1179} 1180 1181OPCodeReturn CodeInterpreter::op_jmp(U32 &ip) 1182{ 1183 ip = mCodeBlock->code[ip]; 1184 return OPCodeReturn::success; 1185} 1186 1187OPCodeReturn CodeInterpreter::op_return_void(U32 &ip) 1188{ 1189 STR.setStringValue(""); 1190 // We're falling thru here on purpose. 1191 1192 OPCodeReturn ret = op_return(ip); 1193 1194 return ret; 1195} 1196 1197OPCodeReturn CodeInterpreter::op_return(U32 &ip) 1198{ 1199 StringStackPtr retValue = STR.getStringValuePtr(); 1200 1201 if (mIterDepth > 0) 1202 { 1203 // Clear iterator state. 1204 while (mIterDepth > 0) 1205 { 1206 iterStack[--_ITER].mIsStringIter = false; 1207 --mIterDepth; 1208 } 1209 1210 STR.rewind(); 1211 STR.setStringValue(StringStackPtrRef(retValue).getPtr(&STR)); // Not nice but works. 1212 retValue = STR.getStringValuePtr(); 1213 } 1214 1215 // Previously the return value was on the stack and would be returned using STR.getStringValue(). 1216 // Now though we need to wrap it in a ConsoleValueRef 1217 mReturnValue.value = CSTK.pushStringStackPtr(retValue); 1218 1219 return OPCodeReturn::exitCode; 1220} 1221 1222OPCodeReturn CodeInterpreter::op_return_flt(U32 &ip) 1223{ 1224 if (mIterDepth > 0) 1225 { 1226 // Clear iterator state. 1227 while (mIterDepth > 0) 1228 { 1229 iterStack[--_ITER].mIsStringIter = false; 1230 --mIterDepth; 1231 } 1232 1233 } 1234 1235 mReturnValue.value = CSTK.pushFLT(floatStack[_FLT]); 1236 _FLT--; 1237 1238 return OPCodeReturn::exitCode; 1239} 1240 1241OPCodeReturn CodeInterpreter::op_return_uint(U32 &ip) 1242{ 1243 if (mIterDepth > 0) 1244 { 1245 // Clear iterator state. 1246 while (mIterDepth > 0) 1247 { 1248 iterStack[--_ITER].mIsStringIter = false; 1249 --mIterDepth; 1250 } 1251 } 1252 1253 mReturnValue.value = CSTK.pushUINT(intStack[_UINT]); 1254 _UINT--; 1255 1256 return OPCodeReturn::exitCode; 1257} 1258 1259OPCodeReturn CodeInterpreter::op_cmpeq(U32 &ip) 1260{ 1261 intStack[_UINT + 1] = bool(floatStack[_FLT] == floatStack[_FLT - 1]); 1262 _UINT++; 1263 _FLT -= 2; 1264 return OPCodeReturn::success; 1265} 1266 1267OPCodeReturn CodeInterpreter::op_cmpgr(U32 &ip) 1268{ 1269 intStack[_UINT + 1] = bool(floatStack[_FLT] > floatStack[_FLT - 1]); 1270 _UINT++; 1271 _FLT -= 2; 1272 return OPCodeReturn::success; 1273} 1274 1275OPCodeReturn CodeInterpreter::op_cmpge(U32 &ip) 1276{ 1277 intStack[_UINT + 1] = bool(floatStack[_FLT] >= floatStack[_FLT - 1]); 1278 _UINT++; 1279 _FLT -= 2; 1280 return OPCodeReturn::success; 1281} 1282 1283OPCodeReturn CodeInterpreter::op_cmplt(U32 &ip) 1284{ 1285 intStack[_UINT + 1] = bool(floatStack[_FLT] < floatStack[_FLT - 1]); 1286 _UINT++; 1287 _FLT -= 2; 1288 return OPCodeReturn::success; 1289} 1290 1291OPCodeReturn CodeInterpreter::op_cmple(U32 &ip) 1292{ 1293 intStack[_UINT + 1] = bool(floatStack[_FLT] <= floatStack[_FLT - 1]); 1294 _UINT++; 1295 _FLT -= 2; 1296 return OPCodeReturn::success; 1297} 1298 1299OPCodeReturn CodeInterpreter::op_cmpne(U32 &ip) 1300{ 1301 intStack[_UINT + 1] = bool(floatStack[_FLT] != floatStack[_FLT - 1]); 1302 _UINT++; 1303 _FLT -= 2; 1304 return OPCodeReturn::success; 1305} 1306 1307OPCodeReturn CodeInterpreter::op_xor(U32 &ip) 1308{ 1309 intStack[_UINT - 1] = intStack[_UINT] ^ intStack[_UINT - 1]; 1310 _UINT--; 1311 return OPCodeReturn::success; 1312} 1313 1314OPCodeReturn CodeInterpreter::op_mod(U32 &ip) 1315{ 1316 if (intStack[_UINT - 1] != 0) 1317 intStack[_UINT - 1] = intStack[_UINT] % intStack[_UINT - 1]; 1318 else 1319 intStack[_UINT - 1] = 0; 1320 _UINT--; 1321 return OPCodeReturn::success; 1322} 1323 1324OPCodeReturn CodeInterpreter::op_bitand(U32 &ip) 1325{ 1326 intStack[_UINT - 1] = intStack[_UINT] & intStack[_UINT - 1]; 1327 _UINT--; 1328 return OPCodeReturn::success; 1329} 1330 1331OPCodeReturn CodeInterpreter::op_bitor(U32 &ip) 1332{ 1333 intStack[_UINT - 1] = intStack[_UINT] | intStack[_UINT - 1]; 1334 _UINT--; 1335 return OPCodeReturn::success; 1336} 1337 1338OPCodeReturn CodeInterpreter::op_not(U32 &ip) 1339{ 1340 intStack[_UINT] = !intStack[_UINT]; 1341 return OPCodeReturn::success; 1342} 1343 1344OPCodeReturn CodeInterpreter::op_notf(U32 &ip) 1345{ 1346 intStack[_UINT + 1] = !floatStack[_FLT]; 1347 _FLT--; 1348 _UINT++; 1349 return OPCodeReturn::success; 1350} 1351 1352OPCodeReturn CodeInterpreter::op_onescomplement(U32 &ip) 1353{ 1354 intStack[_UINT] = ~<a href="/coding/file/codeinterpreter_8cpp/#codeinterpreter_8cpp_1a585e657b7dadf3b57573aac845ef36e4">intStack</a>[_UINT]; 1355 return OPCodeReturn::success; 1356} 1357 1358OPCodeReturn CodeInterpreter::op_shr(U32 &ip) 1359{ 1360 intStack[_UINT - 1] = intStack[_UINT] >> intStack[_UINT - 1]; 1361 _UINT--; 1362 return OPCodeReturn::success; 1363} 1364 1365OPCodeReturn CodeInterpreter::op_shl(U32 &ip) 1366{ 1367 intStack[_UINT - 1] = intStack[_UINT] << intStack[_UINT - 1]; 1368 _UINT--; 1369 return OPCodeReturn::success; 1370} 1371 1372OPCodeReturn CodeInterpreter::op_and(U32 &ip) 1373{ 1374 intStack[_UINT - 1] = intStack[_UINT] && intStack[_UINT - 1]; 1375 _UINT--; 1376 return OPCodeReturn::success; 1377} 1378 1379OPCodeReturn CodeInterpreter::op_or(U32 &ip) 1380{ 1381 intStack[_UINT - 1] = intStack[_UINT] || intStack[_UINT - 1]; 1382 _UINT--; 1383 return OPCodeReturn::success; 1384} 1385 1386OPCodeReturn CodeInterpreter::op_add(U32 &ip) 1387{ 1388 floatStack[_FLT - 1] = floatStack[_FLT] + floatStack[_FLT - 1]; 1389 _FLT--; 1390 return OPCodeReturn::success; 1391} 1392 1393OPCodeReturn CodeInterpreter::op_sub(U32 &ip) 1394{ 1395 floatStack[_FLT - 1] = floatStack[_FLT] - floatStack[_FLT - 1]; 1396 _FLT--; 1397 return OPCodeReturn::success; 1398} 1399 1400OPCodeReturn CodeInterpreter::op_mul(U32 &ip) 1401{ 1402 floatStack[_FLT - 1] = floatStack[_FLT] * floatStack[_FLT - 1]; 1403 _FLT--; 1404 return OPCodeReturn::success; 1405} 1406 1407OPCodeReturn CodeInterpreter::op_div(U32 &ip) 1408{ 1409 floatStack[_FLT - 1] = floatStack[_FLT] / floatStack[_FLT - 1]; 1410 _FLT--; 1411 return OPCodeReturn::success; 1412} 1413 1414OPCodeReturn CodeInterpreter::op_neg(U32 &ip) 1415{ 1416 floatStack[_FLT] = -floatStack[_FLT]; 1417 return OPCodeReturn::success; 1418} 1419 1420OPCodeReturn CodeInterpreter::op_inc(U32 &ip) 1421{ 1422 StringTableEntry var = CodeToSTE(mCodeBlock->code, ip); 1423 ip += 2; 1424 1425 // If a variable is set, then these must be NULL. It is necessary 1426 // to set this here so that the vector parser can appropriately 1427 // identify whether it's dealing with a vector. 1428 mPrevField = NULL; 1429 mPrevObject = NULL; 1430 mCurObject = NULL; 1431 1432 gEvalState.setCurVarNameCreate(var); 1433 1434 // In order to let docblocks work properly with variables, we have 1435 // clear the current docblock when we do an assign. This way it 1436 // won't inappropriately carry forward to following function decls. 1437 mCurFNDocBlock = NULL; 1438 mCurNSDocBlock = NULL; 1439 1440 F64 val = gEvalState.getFloatVariable() + 1.0; 1441 gEvalState.setFloatVariable(val); 1442 1443 // We gotta push val onto the stack. What if we have 1444 // more expressions that have to use this. 1445 // If we don't, we send out an op code to pop it. 1446 floatStack[_FLT + 1] = val; 1447 _FLT++; 1448 1449 return OPCodeReturn::success; 1450} 1451 1452OPCodeReturn CodeInterpreter::op_dec(U32 &ip) 1453{ 1454 StringTableEntry var = CodeToSTE(mCodeBlock->code, ip); 1455 ip += 2; 1456 1457 // If a variable is set, then these must be NULL. It is necessary 1458 // to set this here so that the vector parser can appropriately 1459 // identify whether it's dealing with a vector. 1460 mPrevField = NULL; 1461 mPrevObject = NULL; 1462 mCurObject = NULL; 1463 1464 gEvalState.setCurVarNameCreate(var); 1465 1466 // In order to let docblocks work properly with variables, we have 1467 // clear the current docblock when we do an assign. This way it 1468 // won't inappropriately carry forward to following function decls. 1469 mCurFNDocBlock = NULL; 1470 mCurNSDocBlock = NULL; 1471 1472 F64 val = gEvalState.getFloatVariable() - 1.0; 1473 gEvalState.setFloatVariable(val); 1474 1475 // We gotta push val onto the stack. What if we have 1476 // more expressions that have to use this. 1477 // If we don't, we send out an op code to pop it. 1478 floatStack[_FLT + 1] = val; 1479 _FLT++; 1480 1481 return OPCodeReturn::success; 1482} 1483 1484OPCodeReturn CodeInterpreter::op_setcurvar(U32 &ip) 1485{ 1486 StringTableEntry var = CodeToSTE(mCodeBlock->code, ip); 1487 ip += 2; 1488 1489 // If a variable is set, then these must be NULL. It is necessary 1490 // to set this here so that the vector parser can appropriately 1491 // identify whether it's dealing with a vector. 1492 mPrevField = NULL; 1493 mPrevObject = NULL; 1494 mCurObject = NULL; 1495 1496 gEvalState.setCurVarName(var); 1497 1498 // In order to let docblocks work properly with variables, we have 1499 // clear the current docblock when we do an assign. This way it 1500 // won't inappropriately carry forward to following function decls. 1501 mCurFNDocBlock = NULL; 1502 mCurNSDocBlock = NULL; 1503 return OPCodeReturn::success; 1504} 1505 1506OPCodeReturn CodeInterpreter::op_setcurvar_create(U32 &ip) 1507{ 1508 StringTableEntry var = CodeToSTE(mCodeBlock->code, ip); 1509 ip += 2; 1510 1511 // See OP_SETCURVAR 1512 mPrevField = NULL; 1513 mPrevObject = NULL; 1514 mCurObject = NULL; 1515 1516 gEvalState.setCurVarNameCreate(var); 1517 1518 // See OP_SETCURVAR for why we do this. 1519 mCurFNDocBlock = NULL; 1520 mCurNSDocBlock = NULL; 1521 return OPCodeReturn::success; 1522} 1523 1524OPCodeReturn CodeInterpreter::op_setcurvar_array(U32 &ip) 1525{ 1526 StringTableEntry var = STR.getSTValue(); 1527 1528 // See OP_SETCURVAR 1529 mPrevField = NULL; 1530 mPrevObject = NULL; 1531 mCurObject = NULL; 1532 1533 gEvalState.setCurVarName(var); 1534 1535 // See OP_SETCURVAR for why we do this. 1536 mCurFNDocBlock = NULL; 1537 mCurNSDocBlock = NULL; 1538 return OPCodeReturn::success; 1539} 1540 1541OPCodeReturn CodeInterpreter::op_setcurvar_array_varlookup(U32 &ip) 1542{ 1543 StringTableEntry arrayName = CodeToSTE(mCodeBlock->code, ip); 1544 StringTableEntry arrayLookup = CodeToSTE(mCodeBlock->code, ip + 2); 1545 ip += 4; 1546 1547 STR.setStringValue(arrayName); 1548 STR.advance(); 1549 1550 // See OP_SETCURVAR 1551 mPrevField = NULL; 1552 mPrevObject = NULL; 1553 mCurObject = NULL; 1554 1555 // resolve arrayLookup to get the 'value' 1556 // Note: we have to setCurVarNameCreate in case the var doesn't exist. 1557 // this won't cause much of a performance hit since vars are hashed. 1558 gEvalState.setCurVarNameCreate(arrayLookup); 1559 StringTableEntry hash = gEvalState.getStringVariable(); 1560 1561 STR.setStringValue(hash); 1562 STR.rewind(); 1563 1564 // Generate new array name. 1565 StringTableEntry var = STR.getSTValue(); 1566 gEvalState.setCurVarName(var); 1567 1568 // See OP_SETCURVAR for why we do this. 1569 mCurFNDocBlock = NULL; 1570 mCurNSDocBlock = NULL; 1571 1572 return OPCodeReturn::success; 1573} 1574 1575OPCodeReturn CodeInterpreter::op_setcurvar_array_create(U32 &ip) 1576{ 1577 StringTableEntry var = STR.getSTValue(); 1578 1579 // See OP_SETCURVAR 1580 mPrevField = NULL; 1581 mPrevObject = NULL; 1582 mCurObject = NULL; 1583 1584 gEvalState.setCurVarNameCreate(var); 1585 1586 // See OP_SETCURVAR for why we do this. 1587 mCurFNDocBlock = NULL; 1588 mCurNSDocBlock = NULL; 1589 return OPCodeReturn::success; 1590} 1591 1592OPCodeReturn CodeInterpreter::op_setcurvar_array_create_varlookup(U32 &ip) 1593{ 1594 StringTableEntry arrayName = CodeToSTE(mCodeBlock->code, ip); 1595 StringTableEntry arrayLookup = CodeToSTE(mCodeBlock->code, ip + 2); 1596 ip += 4; 1597 1598 // See OP_SETCURVAR 1599 mPrevField = NULL; 1600 mPrevObject = NULL; 1601 mCurObject = NULL; 1602 1603 STR.setStringValue(arrayName); 1604 STR.advance(); 1605 1606 // resolve arrayLookup to get the 'value' 1607 // Note: we have to setCurVarNameCreate in case the var doesn't exist. 1608 // this won't cause much of a performance hit since vars are hashed. 1609 gEvalState.setCurVarNameCreate(arrayLookup); 1610 StringTableEntry hash = gEvalState.getStringVariable(); 1611 1612 STR.setStringValue(hash); 1613 STR.rewind(); 1614 1615 // Generate new array name. 1616 StringTableEntry var = STR.getSTValue(); 1617 gEvalState.setCurVarNameCreate(var); 1618 1619 // See OP_SETCURVAR for why we do this. 1620 mCurFNDocBlock = NULL; 1621 mCurNSDocBlock = NULL; 1622 1623 return OPCodeReturn::success; 1624} 1625 1626OPCodeReturn CodeInterpreter::op_loadvar_uint(U32 &ip) 1627{ 1628 intStack[_UINT + 1] = gEvalState.getIntVariable(); 1629 _UINT++; 1630 return OPCodeReturn::success; 1631} 1632 1633OPCodeReturn CodeInterpreter::op_loadvar_flt(U32 &ip) 1634{ 1635 floatStack[_FLT + 1] = gEvalState.getFloatVariable(); 1636 _FLT++; 1637 return OPCodeReturn::success; 1638} 1639 1640OPCodeReturn CodeInterpreter::op_loadvar_str(U32 &ip) 1641{ 1642 StringTableEntry val = gEvalState.getStringVariable(); 1643 STR.setStringValue(val); 1644 return OPCodeReturn::success; 1645} 1646 1647OPCodeReturn CodeInterpreter::op_loadvar_var(U32 &ip) 1648{ 1649 // Sets current source of OP_SAVEVAR_VAR 1650 gEvalState.copyVariable = gEvalState.currentVariable; 1651 return OPCodeReturn::success; 1652} 1653 1654OPCodeReturn CodeInterpreter::op_savevar_uint(U32 &ip) 1655{ 1656 gEvalState.setIntVariable(intStack[_UINT]); 1657 return OPCodeReturn::success; 1658} 1659 1660OPCodeReturn CodeInterpreter::op_savevar_flt(U32 &ip) 1661{ 1662 gEvalState.setFloatVariable(floatStack[_FLT]); 1663 return OPCodeReturn::success; 1664} 1665 1666OPCodeReturn CodeInterpreter::op_savevar_str(U32 &ip) 1667{ 1668 gEvalState.setStringVariable(STR.getStringValue()); 1669 return OPCodeReturn::success; 1670} 1671 1672OPCodeReturn CodeInterpreter::op_savevar_var(U32 &ip) 1673{ 1674 // this basically handles %var1 = %var2 1675 gEvalState.setCopyVariable(); 1676 return OPCodeReturn::success; 1677} 1678 1679OPCodeReturn CodeInterpreter::op_setcurobject(U32 &ip) 1680{ 1681 // Save the previous object for parsing vector fields. 1682 mPrevObject = mCurObject; 1683 StringTableEntry val = STR.getStringValue(); 1684 1685 // Sim::findObject will sometimes find valid objects from 1686 // multi-component strings. This makes sure that doesn't 1687 // happen. 1688 for (const char* check = val; *check; check++) 1689 { 1690 if (*check == ' ') 1691 { 1692 val = ""; 1693 break; 1694 } 1695 } 1696 mCurObject = Sim::findObject(val); 1697 return OPCodeReturn::success; 1698} 1699 1700OPCodeReturn CodeInterpreter::op_setcurobject_internal(U32 &ip) 1701{ 1702 ++ip; // To skip the recurse flag if the object wasn't found 1703 if (mCurObject) 1704 { 1705 SimSet *set = dynamic_cast<SimSet *>(mCurObject); 1706 if (set) 1707 { 1708 StringTableEntry intName = StringTable->insert(STR.getStringValue()); 1709 bool recurse = mCodeBlock->code[ip - 1]; 1710 SimObject *obj = set->findObjectByInternalName(intName, recurse); 1711 intStack[_UINT + 1] = obj ? obj->getId() : 0; 1712 _UINT++; 1713 } 1714 else 1715 { 1716 Con::errorf(ConsoleLogEntry::Script, "%s: Attempt to use -> on non-set %s of class %s.", mCodeBlock->getFileLine(ip - 2), mCurObject->getName(), mCurObject->getClassName()); 1717 intStack[_UINT] = 0; 1718 } 1719 } 1720 return OPCodeReturn::success; 1721} 1722 1723OPCodeReturn CodeInterpreter::op_setcurobject_new(U32 &ip) 1724{ 1725 mCurObject = mCurrentNewObject; 1726 return OPCodeReturn::success; 1727} 1728 1729OPCodeReturn CodeInterpreter::op_setcurfield(U32 &ip) 1730{ 1731 // Save the previous field for parsing vector fields. 1732 mPrevField = mCurField; 1733 dStrcpy(prevFieldArray, curFieldArray, 256); 1734 mCurField = CodeToSTE(mCodeBlock->code, ip); 1735 curFieldArray[0] = 0; 1736 ip += 2; 1737 return OPCodeReturn::success; 1738} 1739 1740OPCodeReturn CodeInterpreter::op_setcurfield_array(U32 &ip) 1741{ 1742 dStrcpy(curFieldArray, STR.getStringValue(), 256); 1743 return OPCodeReturn::success; 1744} 1745 1746OPCodeReturn CodeInterpreter::op_setcurfield_type(U32 &ip) 1747{ 1748 if (mCurObject) 1749 mCurObject->setDataFieldType(mCodeBlock->code[ip], mCurField, curFieldArray); 1750 ip++; 1751 return OPCodeReturn::success; 1752} 1753 1754OPCodeReturn CodeInterpreter::op_setcurfield_array_var(U32 &ip) 1755{ 1756 StringTableEntry var = CodeToSTE(mCodeBlock->code, ip); 1757 ip += 2; 1758 1759 // We set the current var name (create it as well in case if it doesn't exist, 1760 // otherwise we will crash). 1761 gEvalState.setCurVarNameCreate(var); 1762 1763 // Then load the var and copy the contents to the current field array 1764 dStrncpy(curFieldArray, gEvalState.currentVariable->getStringValue(), sizeof(curFieldArray)); 1765 1766 return OPCodeReturn::success; 1767} 1768 1769OPCodeReturn CodeInterpreter::op_setcurfield_this(U32 &ip) 1770{ 1771 // set the 'this pointer' as the current object. 1772 mCurObject = mThisObject; 1773 1774 mPrevField = mCurField; 1775 dStrcpy(prevFieldArray, curFieldArray, 256); 1776 mCurField = CodeToSTE(mCodeBlock->code, ip); 1777 curFieldArray[0] = 0; 1778 ip += 2; 1779 return OPCodeReturn::success; 1780} 1781 1782OPCodeReturn CodeInterpreter::op_loadfield_uint(U32 &ip) 1783{ 1784 if (mCurObject) 1785 intStack[_UINT + 1] = U32(dAtoi(mCurObject->getDataField(mCurField, curFieldArray))); 1786 else 1787 { 1788 // The field is not being retrieved from an object. Maybe it's 1789 // a special accessor? 1790 char buff[FieldBufferSizeNumeric]; 1791 memset(buff, 0, sizeof(buff)); 1792 getFieldComponent(mPrevObject, mPrevField, prevFieldArray, mCurField, buff); 1793 intStack[_UINT + 1] = dAtoi(buff); 1794 } 1795 _UINT++; 1796 return OPCodeReturn::success; 1797} 1798 1799OPCodeReturn CodeInterpreter::op_loadfield_flt(U32 &ip) 1800{ 1801 if (mCurObject) 1802 floatStack[_FLT + 1] = dAtof(mCurObject->getDataField(mCurField, curFieldArray)); 1803 else 1804 { 1805 // The field is not being retrieved from an object. Maybe it's 1806 // a special accessor? 1807 char buff[FieldBufferSizeNumeric]; 1808 memset(buff, 0, sizeof(buff)); 1809 getFieldComponent(mPrevObject, mPrevField, prevFieldArray, mCurField, buff); 1810 floatStack[_FLT + 1] = dAtof(buff); 1811 } 1812 _FLT++; 1813 return OPCodeReturn::success; 1814} 1815 1816OPCodeReturn CodeInterpreter::op_loadfield_str(U32 &ip) 1817{ 1818 if (mCurObject) 1819 { 1820 StringTableEntry val = mCurObject->getDataField(mCurField, curFieldArray); 1821 STR.setStringValue(val); 1822 } 1823 else 1824 { 1825 // The field is not being retrieved from an object. Maybe it's 1826 // a special accessor? 1827 char buff[FieldBufferSizeString]; 1828 memset(buff, 0, sizeof(buff)); 1829 getFieldComponent(mPrevObject, mPrevField, prevFieldArray, mCurField, buff); 1830 STR.setStringValue(buff); 1831 } 1832 return OPCodeReturn::success; 1833} 1834 1835OPCodeReturn CodeInterpreter::op_savefield_uint(U32 &ip) 1836{ 1837 STR.setIntValue(intStack[_UINT]); 1838 if (mCurObject) 1839 mCurObject->setDataField(mCurField, curFieldArray, STR.getStringValue()); 1840 else 1841 { 1842 // The field is not being set on an object. Maybe it's 1843 // a special accessor? 1844 setFieldComponent(mPrevObject, mPrevField, prevFieldArray, mCurField); 1845 mPrevObject = NULL; 1846 } 1847 return OPCodeReturn::success; 1848} 1849 1850OPCodeReturn CodeInterpreter::op_savefield_flt(U32 &ip) 1851{ 1852 STR.setFloatValue(floatStack[_FLT]); 1853 if (mCurObject) 1854 mCurObject->setDataField(mCurField, curFieldArray, STR.getStringValue()); 1855 else 1856 { 1857 // The field is not being set on an object. Maybe it's 1858 // a special accessor? 1859 setFieldComponent(mPrevObject, mPrevField, prevFieldArray, mCurField); 1860 mPrevObject = NULL; 1861 } 1862 return OPCodeReturn::success; 1863} 1864 1865OPCodeReturn CodeInterpreter::op_savefield_str(U32 &ip) 1866{ 1867 if (mCurObject) 1868 mCurObject->setDataField(mCurField, curFieldArray, STR.getStringValue()); 1869 else 1870 { 1871 // The field is not being set on an object. Maybe it's 1872 // a special accessor? 1873 setFieldComponent(mPrevObject, mPrevField, prevFieldArray, mCurField); 1874 mPrevObject = NULL; 1875 } 1876 return OPCodeReturn::success; 1877} 1878 1879OPCodeReturn CodeInterpreter::op_str_to_uint(U32 &ip) 1880{ 1881 intStack[_UINT + 1] = STR.getIntValue(); 1882 _UINT++; 1883 return OPCodeReturn::success; 1884} 1885 1886OPCodeReturn CodeInterpreter::op_str_to_flt(U32 &ip) 1887{ 1888 floatStack[_FLT + 1] = STR.getFloatValue(); 1889 _FLT++; 1890 return OPCodeReturn::success; 1891} 1892 1893OPCodeReturn CodeInterpreter::op_str_to_none(U32 &ip) 1894{ 1895 // This exists simply to deal with certain typecast situations. 1896 return OPCodeReturn::success; 1897} 1898 1899OPCodeReturn CodeInterpreter::op_flt_to_uint(U32 &ip) 1900{ 1901 intStack[_UINT + 1] = (S64)floatStack[_FLT]; 1902 _FLT--; 1903 _UINT++; 1904 return OPCodeReturn::success; 1905} 1906 1907OPCodeReturn CodeInterpreter::op_flt_to_str(U32 &ip) 1908{ 1909 STR.setFloatValue(floatStack[_FLT]); 1910 _FLT--; 1911 return OPCodeReturn::success; 1912} 1913 1914OPCodeReturn CodeInterpreter::op_flt_to_none(U32 &ip) 1915{ 1916 _FLT--; 1917 return OPCodeReturn::success; 1918} 1919 1920OPCodeReturn CodeInterpreter::op_uint_to_flt(U32 &ip) 1921{ 1922 floatStack[_FLT + 1] = (F32)intStack[_UINT]; 1923 _UINT--; 1924 _FLT++; 1925 return OPCodeReturn::success; 1926} 1927 1928OPCodeReturn CodeInterpreter::op_uint_to_str(U32 &ip) 1929{ 1930 STR.setIntValue(intStack[_UINT]); 1931 _UINT--; 1932 return OPCodeReturn::success; 1933} 1934 1935OPCodeReturn CodeInterpreter::op_uint_to_none(U32 &ip) 1936{ 1937 _UINT--; 1938 return OPCodeReturn::success; 1939} 1940 1941OPCodeReturn CodeInterpreter::op_copyvar_to_none(U32 &ip) 1942{ 1943 gEvalState.copyVariable = NULL; 1944 return OPCodeReturn::success; 1945} 1946 1947OPCodeReturn CodeInterpreter::op_loadimmed_uint(U32 &ip) 1948{ 1949 intStack[_UINT + 1] = mCodeBlock->code[ip++]; 1950 _UINT++; 1951 return OPCodeReturn::success; 1952} 1953 1954OPCodeReturn CodeInterpreter::op_loadimmed_flt(U32 &ip) 1955{ 1956 floatStack[_FLT + 1] = mCurFloatTable[mCodeBlock->code[ip]]; 1957 ip++; 1958 _FLT++; 1959 return OPCodeReturn::success; 1960} 1961 1962OPCodeReturn CodeInterpreter::op_tag_to_str(U32 &ip) 1963{ 1964 mCodeBlock->code[ip - 1] = OP_LOADIMMED_STR; 1965 // it's possible the string has already been converted 1966 if (U8(mCurStringTable[mCodeBlock->code[ip]]) != StringTagPrefixByte) 1967 { 1968 U32 id = GameAddTaggedString(mCurStringTable + mCodeBlock->code[ip]); 1969 dSprintf(mCurStringTable + mCodeBlock->code[ip] + 1, 7, "%d", id); 1970 *(mCurStringTable + mCodeBlock->code[ip]) = StringTagPrefixByte; 1971 } 1972 1973 // Fallthrough 1974 OPCodeReturn ret = op_loadimmed_str(ip); 1975 1976 return ret; 1977} 1978 1979OPCodeReturn CodeInterpreter::op_loadimmed_str(U32 &ip) 1980{ 1981 STR.setStringValue(mCurStringTable + mCodeBlock->code[ip++]); 1982 return OPCodeReturn::success; 1983} 1984 1985OPCodeReturn CodeInterpreter::op_docblock_str(U32 &ip) 1986{ 1987 // If the first word of the doc is '\class' or '@class', then this 1988 // is a namespace doc block, otherwise it is a function doc block. 1989 const char* docblock = mCurStringTable + mCodeBlock->code[ip++]; 1990 1991 const char* sansClass = dStrstr(docblock, "@class"); 1992 if (!sansClass) 1993 sansClass = dStrstr(docblock, "\\class"); 1994 1995 if (sansClass) 1996 { 1997 // Don't save the class declaration. Scan past the 'class' 1998 // keyword and up to the first whitespace. 1999 sansClass += 7; 2000 S32 index = 0; 2001 while ((*sansClass != ' ') && (*sansClass != '\n') && *sansClass && (index < (nsDocLength - 1))) 2002 { 2003 mNSDocBlockClass[index++] = *sansClass; 2004 sansClass++; 2005 } 2006 mNSDocBlockClass[index] = '\0'; 2007 2008 mCurNSDocBlock = sansClass + 1; 2009 } 2010 else 2011 mCurFNDocBlock = docblock; 2012 2013 return OPCodeReturn::success; 2014} 2015 2016OPCodeReturn CodeInterpreter::op_loadimmed_ident(U32 &ip) 2017{ 2018 STR.setStringValue(CodeToSTE(mCodeBlock->code, ip)); 2019 ip += 2; 2020 return OPCodeReturn::success; 2021} 2022 2023OPCodeReturn CodeInterpreter::op_callfunc_resolve(U32 &ip) 2024{ 2025 // This deals with a function that is potentially living in a namespace. 2026 StringTableEntry fnNamespace = CodeToSTE(mCodeBlock->code, ip + 2); 2027 StringTableEntry fnName = CodeToSTE(mCodeBlock->code, ip); 2028 2029 // Try to look it up. 2030 mNSEntry = Namespace::find(fnNamespace)->lookup(fnName); 2031 if (!CInterface::GetCInterface().isMethod(fnNamespace, fnName) && !mNSEntry) 2032 { 2033 ip += 5; 2034 Con::warnf(ConsoleLogEntry::General, 2035 "%s: Unable to find function %s%s%s", 2036 mCodeBlock->getFileLine(ip - 7), fnNamespace ? fnNamespace : "", 2037 fnNamespace ? "::" : "", fnName); 2038 STR.popFrame(); 2039 CSTK.popFrame(); 2040 return OPCodeReturn::success; 2041 } 2042 2043 // Fallthrough to op_callfunc_resolve 2044 OPCodeReturn ret = op_callfunc(ip); 2045 2046 return ret; 2047} 2048 2049OPCodeReturn CodeInterpreter::op_callfunc(U32 &ip) 2050{ 2051 // This routingId is set when we query the object as to whether 2052 // it handles this method. It is set to an enum from the table 2053 // above indicating whether it handles it on a component it owns 2054 // or just on the object. 2055 S32 routingId = 0; 2056 2057 U32 *code = mCodeBlock->code; 2058 2059 StringTableEntry fnNamespace = CodeToSTE(mCodeBlock->code, ip + 2); 2060 StringTableEntry fnName = CodeToSTE(code, ip); 2061 2062 //if this is called from inside a function, append the ip and codeptr 2063 if (gEvalState.getStackDepth() > 0) 2064 { 2065 gEvalState.getCurrentFrame().code = mCodeBlock; 2066 gEvalState.getCurrentFrame().ip = ip - 1; 2067 } 2068 2069 U32 callType = code[ip + 4]; 2070 2071 ip += 5; 2072 CSTK.getArgcArgv(fnName, &mCallArgc, &mCallArgv); 2073 2074 const char *componentReturnValue = ""; 2075 Namespace *ns = NULL; 2076 2077 bool cFunctionRes = false; 2078 const char* cRetRes = NULL; 2079 2080 if (callType == FuncCallExprNode::FunctionCall) 2081 { 2082 if (!mNSEntry) 2083 mNSEntry = Namespace::global()->lookup(fnName); 2084 2085 StringStackWrapper args(mCallArgc, mCallArgv); 2086 cRetRes = CInterface::CallFunction(fnNamespace, fnName, args.argv + 1, args.argc - 1, &cFunctionRes); 2087 } 2088 else if (callType == FuncCallExprNode::MethodCall) 2089 { 2090 mSaveObject = gEvalState.thisObject; 2091 gEvalState.thisObject = Sim::findObject((const char*)mCallArgv[1]); 2092 if (!gEvalState.thisObject) 2093 { 2094 // Go back to the previous saved object. 2095 gEvalState.thisObject = mSaveObject; 2096 2097 Con::warnf(ConsoleLogEntry::General, "%s: Unable to find object: '%s' attempting to call function '%s'", mCodeBlock->getFileLine(ip - 4), (const char*)mCallArgv[1], fnName); 2098 STR.popFrame(); 2099 CSTK.popFrame(); 2100 STR.setStringValue(""); 2101 return OPCodeReturn::success; 2102 } 2103 2104 bool handlesMethod = gEvalState.thisObject->handlesConsoleMethod(fnName, &routingId); 2105 if (handlesMethod && routingId == MethodOnComponent) 2106 { 2107 ICallMethod *pComponent = dynamic_cast<ICallMethod *>(gEvalState.thisObject); 2108 if (pComponent) 2109 componentReturnValue = pComponent->callMethodArgList(mCallArgc, mCallArgv, false); 2110 } 2111 2112 ns = gEvalState.thisObject->getNamespace(); 2113 if (ns) 2114 mNSEntry = ns->lookup(fnName); 2115 else 2116 mNSEntry = NULL; 2117 2118 StringStackWrapper args(mCallArgc, mCallArgv); 2119 cRetRes = CInterface::CallMethod(gEvalState.thisObject, fnName, args.argv + 2, args.argc - 2, &cFunctionRes); 2120 } 2121 else // it's a ParentCall 2122 { 2123 if (mExec.thisNamespace) 2124 { 2125 ns = mExec.thisNamespace->mParent; 2126 if (ns) 2127 mNSEntry = ns->lookup(fnName); 2128 else 2129 mNSEntry = NULL; 2130 } 2131 else 2132 { 2133 ns = NULL; 2134 mNSEntry = NULL; 2135 } 2136 } 2137 2138 Namespace::Entry::CallbackUnion * nsCb = NULL; 2139 const char * nsUsage = NULL; 2140 if (mNSEntry) 2141 { 2142 nsCb = &mNSEntry->cb; 2143 nsUsage = mNSEntry->mUsage; 2144 routingId = 0; 2145 } 2146 if (!cFunctionRes && (!mNSEntry || mExec.noCalls)) 2147 { 2148 if (!mExec.noCalls && !(routingId == MethodOnComponent)) 2149 { 2150 if (callType == FuncCallExprNode::MethodCall) 2151 { 2152 if (gEvalState.thisObject != NULL) 2153 { 2154 // Try to use the name instead of the id 2155 StringTableEntry name = gEvalState.thisObject->getName() ? gEvalState.thisObject->getName() : gEvalState.thisObject->getIdString(); 2156 Con::warnf(ConsoleLogEntry::General, "%s: Unknown method %s.%s Namespace List: %s", mCodeBlock->getFileLine(ip - 6), name, fnName, Con::getNamespaceList(ns)); 2157 } 2158 else 2159 { 2160 // NULL. 2161 Con::warnf(ConsoleLogEntry::General, "%s: Unknown method NULL.%s", mCodeBlock->getFileLine(ip - 6), fnName); 2162 } 2163 } 2164 else if (callType == FuncCallExprNode::ParentCall) 2165 { 2166 Con::warnf(ConsoleLogEntry::General, "%s: Unknown parent call %s.", mCodeBlock->getFileLine(ip - 6), fnName); 2167 } 2168 else 2169 { 2170 Con::warnf(ConsoleLogEntry::General, "%s: Unknown function %s.", mCodeBlock->getFileLine(ip - 6), fnName); 2171 } 2172 } 2173 STR.popFrame(); 2174 CSTK.popFrame(); 2175 2176 if (routingId == MethodOnComponent) 2177 STR.setStringValue(componentReturnValue); 2178 else 2179 STR.setStringValue(""); 2180 return OPCodeReturn::success; 2181 } 2182 2183 // ConsoleFunctionType is for any function defined by script. 2184 // Any 'callback' type is an engine function that is exposed to script. 2185 if (cFunctionRes || mNSEntry->mType == Namespace::Entry::ConsoleFunctionType) 2186 { 2187 ConsoleValue retVal; 2188 ConsoleValueRef ret; 2189 if (cFunctionRes) 2190 { 2191 retVal.init(); 2192 ret.value = &retVal; 2193 retVal.setStackStringValue(cRetRes); 2194 } 2195 else if (mNSEntry->mFunctionOffset) 2196 { 2197 ret = mNSEntry->mCode->exec(mNSEntry->mFunctionOffset, fnName, mNSEntry->mNamespace, mCallArgc, mCallArgv, false, mNSEntry->mPackage); 2198 } 2199 2200 STR.popFrame(); 2201 // Functions are assumed to return strings, so look ahead to see if we can skip the conversion 2202 if (code[ip] == OP_STR_TO_UINT) 2203 { 2204 ip++; 2205 intStack[++_UINT] = (U32)((S32)ret); 2206 } 2207 else if (code[ip] == OP_STR_TO_FLT) 2208 { 2209 ip++; 2210 floatStack[++_FLT] = (F32)ret; 2211 } 2212 else if (code[ip] == OP_STR_TO_NONE) 2213 { 2214 STR.setStringValue(ret.getStringValue()); 2215 ip++; 2216 } 2217 else 2218 STR.setStringValue((const char*)ret); 2219 2220 // This will clear everything including returnValue 2221 CSTK.popFrame(); 2222 //STR.clearFunctionOffset(); 2223 } 2224 else 2225 { 2226 const char* nsName = ns ? ns->mName : ""; 2227#ifndef TORQUE_DEBUG 2228 // [tom, 12/13/2006] This stops tools functions from working in the console, 2229 // which is useful behavior when debugging so I'm ifdefing this out for debug builds. 2230 if (mNSEntry->mToolOnly && !Con::isCurrentScriptToolScript()) 2231 { 2232 Con::errorf(ConsoleLogEntry::Script, "%s: %s::%s - attempting to call tools only function from outside of tools.", mCodeBlock->getFileLine(ip - 6), nsName, fnName); 2233 } 2234 else 2235#endif 2236 if ((mNSEntry->mMinArgs && S32(mCallArgc) < mNSEntry->mMinArgs) || (mNSEntry->mMaxArgs && S32(mCallArgc) > mNSEntry->mMaxArgs)) 2237 { 2238 Con::warnf(ConsoleLogEntry::Script, "%s: %s::%s - wrong number of arguments (got %i, expected min %i and max %i).", 2239 mCodeBlock->getFileLine(ip - 6), nsName, fnName, 2240 mCallArgc, mNSEntry->mMinArgs, mNSEntry->mMaxArgs); 2241 Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", mCodeBlock->getFileLine(ip - 6), mNSEntry->mUsage); 2242 STR.popFrame(); 2243 CSTK.popFrame(); 2244 } 2245 else 2246 { 2247 switch (mNSEntry->mType) 2248 { 2249 case Namespace::Entry::StringCallbackType: 2250 { 2251 const char *ret = mNSEntry->cb.mStringCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv); 2252 STR.popFrame(); 2253 CSTK.popFrame(); 2254 if (ret != STR.getStringValue()) 2255 STR.setStringValue(ret); 2256 //else 2257 // sSTR.setLen(dStrlen(ret)); 2258 break; 2259 } 2260 case Namespace::Entry::IntCallbackType: 2261 { 2262 S32 result = mNSEntry->cb.mIntCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv); 2263 STR.popFrame(); 2264 CSTK.popFrame(); 2265 if (code[ip] == OP_STR_TO_UINT) 2266 { 2267 ip++; 2268 intStack[++_UINT] = result; 2269 break; 2270 } 2271 else if (code[ip] == OP_STR_TO_FLT) 2272 { 2273 ip++; 2274 floatStack[++_FLT] = result; 2275 break; 2276 } 2277 else if (code[ip] == OP_STR_TO_NONE) 2278 ip++; 2279 else 2280 STR.setIntValue(result); 2281 break; 2282 } 2283 case Namespace::Entry::FloatCallbackType: 2284 { 2285 F64 result = mNSEntry->cb.mFloatCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv); 2286 STR.popFrame(); 2287 CSTK.popFrame(); 2288 if (code[ip] == OP_STR_TO_UINT) 2289 { 2290 ip++; 2291 intStack[++_UINT] = (S64)result; 2292 break; 2293 } 2294 else if (code[ip] == OP_STR_TO_FLT) 2295 { 2296 ip++; 2297 floatStack[++_FLT] = result; 2298 break; 2299 } 2300 else if (code[ip] == OP_STR_TO_NONE) 2301 ip++; 2302 else 2303 STR.setFloatValue(result); 2304 break; 2305 } 2306 case Namespace::Entry::VoidCallbackType: 2307 mNSEntry->cb.mVoidCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv); 2308 if (code[ip] != OP_STR_TO_NONE && Con::getBoolVariable("$Con::warnVoidAssignment", true)) 2309 Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", mCodeBlock->getFileLine(ip - 6), fnName, mExec.functionName); 2310 2311 STR.popFrame(); 2312 CSTK.popFrame(); 2313 STR.setStringValue(""); 2314 break; 2315 case Namespace::Entry::BoolCallbackType: 2316 { 2317 bool result = mNSEntry->cb.mBoolCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv); 2318 STR.popFrame(); 2319 CSTK.popFrame(); 2320 if (code[ip] == OP_STR_TO_UINT) 2321 { 2322 ip++; 2323 intStack[++_UINT] = result; 2324 break; 2325 } 2326 else if (code[ip] == OP_STR_TO_FLT) 2327 { 2328 ip++; 2329 floatStack[++_FLT] = result; 2330 break; 2331 } 2332 else if (code[ip] == OP_STR_TO_NONE) 2333 ip++; 2334 else 2335 STR.setIntValue(result); 2336 break; 2337 } 2338 } 2339 } 2340 } 2341 2342 if (callType == FuncCallExprNode::MethodCall) 2343 gEvalState.thisObject = mSaveObject; 2344 return OPCodeReturn::success; 2345} 2346 2347OPCodeReturn CodeInterpreter::op_callfunc_pointer(U32 &ip) 2348{ 2349 // get function name. This is the 'function pointer'. 2350 StringTableEntry fnName = StringTable->insert(STR.getStringValue()); 2351 2352 U32 *code = mCodeBlock->code; 2353 2354 mNSEntry = Namespace::global()->lookup(fnName); 2355 2356 //if this is called from inside a function, append the ip and codeptr 2357 if (gEvalState.getStackDepth() > 0) 2358 { 2359 gEvalState.getCurrentFrame().code = mCodeBlock; 2360 gEvalState.getCurrentFrame().ip = ip - 1; 2361 } 2362 2363 CSTK.getArgcArgv(fnName, &mCallArgc, &mCallArgv); 2364 2365 2366 if (!mNSEntry || mExec.noCalls) 2367 { 2368 if (!mExec.noCalls) 2369 { 2370 Con::warnf(ConsoleLogEntry::General, "%s: Unknown function %s.", mCodeBlock->getFileLine(ip - 6), fnName); 2371 } 2372 STR.popFrame(); 2373 CSTK.popFrame(); 2374 2375 STR.setStringValue(""); 2376 return OPCodeReturn::success; 2377 } 2378 2379 // ConsoleFunctionType is for any function defined by script. 2380 // Any 'callback' type is an engine function that is exposed to script. 2381 if (mNSEntry->mType == Namespace::Entry::ConsoleFunctionType) 2382 { 2383 ConsoleValueRef ret; 2384 if (mNSEntry->mFunctionOffset) 2385 ret = mNSEntry->mCode->exec(mNSEntry->mFunctionOffset, fnName, mNSEntry->mNamespace, mCallArgc, mCallArgv, false, mNSEntry->mPackage); 2386 2387 STR.popFrame(); 2388 // Functions are assumed to return strings, so look ahead to see if we can skip the conversion 2389 if (code[ip] == OP_STR_TO_UINT) 2390 { 2391 ip++; 2392 intStack[++_UINT] = (U32)((S32)ret); 2393 } 2394 else if (code[ip] == OP_STR_TO_FLT) 2395 { 2396 ip++; 2397 floatStack[++_FLT] = (F32)ret; 2398 } 2399 else if (code[ip] == OP_STR_TO_NONE) 2400 { 2401 STR.setStringValue(ret.getStringValue()); 2402 ip++; 2403 } 2404 else 2405 STR.setStringValue((const char*)ret); 2406 2407 // This will clear everything including returnValue 2408 CSTK.popFrame(); 2409 //STR.clearFunctionOffset(); 2410 } 2411 else 2412 { 2413 const char* nsName = ""; 2414 2415#ifndef TORQUE_DEBUG 2416 // [tom, 12/13/2006] This stops tools functions from working in the console, 2417 // which is useful behavior when debugging so I'm ifdefing this out for debug builds. 2418 if (mNSEntry->mToolOnly && !Con::isCurrentScriptToolScript()) 2419 { 2420 Con::errorf(ConsoleLogEntry::Script, "%s: %s::%s - attempting to call tools only function from outside of tools.", mCodeBlock->getFileLine(ip - 6), nsName, fnName); 2421 } 2422 else 2423#endif 2424 if ((mNSEntry->mMinArgs && S32(mCallArgc) < mNSEntry->mMinArgs) || (mNSEntry->mMaxArgs && S32(mCallArgc) > mNSEntry->mMaxArgs)) 2425 { 2426 Con::warnf(ConsoleLogEntry::Script, "%s: %s::%s - wrong number of arguments (got %i, expected min %i and max %i).", 2427 mCodeBlock->getFileLine(ip - 6), nsName, fnName, 2428 mCallArgc, mNSEntry->mMinArgs, mNSEntry->mMaxArgs); 2429 Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", mCodeBlock->getFileLine(ip - 6), mNSEntry->mUsage); 2430 STR.popFrame(); 2431 CSTK.popFrame(); 2432 } 2433 else 2434 { 2435 switch (mNSEntry->mType) 2436 { 2437 case Namespace::Entry::StringCallbackType: 2438 { 2439 const char *ret = mNSEntry->cb.mStringCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv); 2440 STR.popFrame(); 2441 CSTK.popFrame(); 2442 if (ret != STR.getStringValue()) 2443 STR.setStringValue(ret); 2444 //else 2445 // sSTR.setLen(dStrlen(ret)); 2446 break; 2447 } 2448 case Namespace::Entry::IntCallbackType: 2449 { 2450 S32 result = mNSEntry->cb.mIntCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv); 2451 STR.popFrame(); 2452 CSTK.popFrame(); 2453 if (code[ip] == OP_STR_TO_UINT) 2454 { 2455 ip++; 2456 intStack[++_UINT] = result; 2457 break; 2458 } 2459 else if (code[ip] == OP_STR_TO_FLT) 2460 { 2461 ip++; 2462 floatStack[++_FLT] = result; 2463 break; 2464 } 2465 else if (code[ip] == OP_STR_TO_NONE) 2466 ip++; 2467 else 2468 STR.setIntValue(result); 2469 break; 2470 } 2471 case Namespace::Entry::FloatCallbackType: 2472 { 2473 F64 result = mNSEntry->cb.mFloatCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv); 2474 STR.popFrame(); 2475 CSTK.popFrame(); 2476 if (code[ip] == OP_STR_TO_UINT) 2477 { 2478 ip++; 2479 intStack[++_UINT] = (S64)result; 2480 break; 2481 } 2482 else if (code[ip] == OP_STR_TO_FLT) 2483 { 2484 ip++; 2485 floatStack[++_FLT] = result; 2486 break; 2487 } 2488 else if (code[ip] == OP_STR_TO_NONE) 2489 ip++; 2490 else 2491 STR.setFloatValue(result); 2492 break; 2493 } 2494 case Namespace::Entry::VoidCallbackType: 2495 mNSEntry->cb.mVoidCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv); 2496 if (code[ip] != OP_STR_TO_NONE && Con::getBoolVariable("$Con::warnVoidAssignment", true)) 2497 Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", mCodeBlock->getFileLine(ip - 6), fnName, mExec.functionName); 2498 2499 STR.popFrame(); 2500 CSTK.popFrame(); 2501 STR.setStringValue(""); 2502 break; 2503 case Namespace::Entry::BoolCallbackType: 2504 { 2505 bool result = mNSEntry->cb.mBoolCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv); 2506 STR.popFrame(); 2507 CSTK.popFrame(); 2508 if (code[ip] == OP_STR_TO_UINT) 2509 { 2510 ip++; 2511 intStack[++_UINT] = result; 2512 break; 2513 } 2514 else if (code[ip] == OP_STR_TO_FLT) 2515 { 2516 ip++; 2517 floatStack[++_FLT] = result; 2518 break; 2519 } 2520 else if (code[ip] == OP_STR_TO_NONE) 2521 ip++; 2522 else 2523 STR.setIntValue(result); 2524 break; 2525 } 2526 } 2527 } 2528 } 2529 2530 2531 return OPCodeReturn::success; 2532} 2533 2534OPCodeReturn CodeInterpreter::op_callfunc_this(U32 &ip) 2535{ 2536 U32 *code = mCodeBlock->code; 2537 2538 StringTableEntry fnName = CodeToSTE(code, ip); 2539 2540 //if this is called from inside a function, append the ip and codeptr 2541 if (gEvalState.getStackDepth() > 0) 2542 { 2543 gEvalState.getCurrentFrame().code = mCodeBlock; 2544 gEvalState.getCurrentFrame().ip = ip - 1; 2545 } 2546 2547 ip += 2; 2548 CSTK.getArgcArgv(fnName, &mCallArgc, &mCallArgv); 2549 2550 Namespace *ns = mThisObject ? mThisObject->getNamespace() : NULL; 2551 if (ns) 2552 mNSEntry = ns->lookup(fnName); 2553 else 2554 mNSEntry = NULL; 2555 2556 if (!mNSEntry || mExec.noCalls) 2557 { 2558 if (!mExec.noCalls) 2559 { 2560 if (mThisObject) 2561 { 2562 // Try to use the name instead of the id 2563 StringTableEntry name = mThisObject->getName() ? mThisObject->getName() : mThisObject->getIdString(); 2564 Con::warnf(ConsoleLogEntry::General, "%s: Unknown method %s.%s Namespace List: %s", mCodeBlock->getFileLine(ip - 6), name, fnName, Con::getNamespaceList(ns)); 2565 } 2566 else 2567 { 2568 // At least let the scripter know that they access the object. 2569 Con::warnf(ConsoleLogEntry::General, "%s: Unknown method NULL.%s", mCodeBlock->getFileLine(ip - 6), fnName); 2570 } 2571 } 2572 STR.popFrame(); 2573 CSTK.popFrame(); 2574 2575 STR.setStringValue(""); 2576 return OPCodeReturn::success; 2577 } 2578 2579 // ConsoleFunctionType is for any function defined by script. 2580 // Any 'callback' type is an engine function that is exposed to script. 2581 if (mNSEntry->mType == Namespace::Entry::ConsoleFunctionType) 2582 { 2583 ConsoleValueRef ret; 2584 if (mNSEntry->mFunctionOffset) 2585 ret = mNSEntry->mCode->exec(mNSEntry->mFunctionOffset, fnName, mNSEntry->mNamespace, mCallArgc, mCallArgv, false, mNSEntry->mPackage); 2586 2587 STR.popFrame(); 2588 // Functions are assumed to return strings, so look ahead to see if we can skip the conversion 2589 if (code[ip] == OP_STR_TO_UINT) 2590 { 2591 ip++; 2592 intStack[++_UINT] = (U32)((S32)ret); 2593 } 2594 else if (code[ip] == OP_STR_TO_FLT) 2595 { 2596 ip++; 2597 floatStack[++_FLT] = (F32)ret; 2598 } 2599 else if (code[ip] == OP_STR_TO_NONE) 2600 { 2601 STR.setStringValue(ret.getStringValue()); 2602 ip++; 2603 } 2604 else 2605 STR.setStringValue((const char*)ret); 2606 2607 // This will clear everything including returnValue 2608 CSTK.popFrame(); 2609 //STR.clearFunctionOffset(); 2610 } 2611 else 2612 { 2613 const char* nsName = ns ? ns->mName : ""; 2614#ifndef TORQUE_DEBUG 2615 // [tom, 12/13/2006] This stops tools functions from working in the console, 2616 // which is useful behavior when debugging so I'm ifdefing this out for debug builds. 2617 if (mNSEntry->mToolOnly && !Con::isCurrentScriptToolScript()) 2618 { 2619 Con::errorf(ConsoleLogEntry::Script, "%s: %s::%s - attempting to call tools only function from outside of tools.", mCodeBlock->getFileLine(ip - 6), nsName, fnName); 2620 } 2621 else 2622#endif 2623 if ((mNSEntry->mMinArgs && S32(mCallArgc) < mNSEntry->mMinArgs) || (mNSEntry->mMaxArgs && S32(mCallArgc) > mNSEntry->mMaxArgs)) 2624 { 2625 Con::warnf(ConsoleLogEntry::Script, "%s: %s::%s - wrong number of arguments (got %i, expected min %i and max %i).", 2626 mCodeBlock->getFileLine(ip - 6), nsName, fnName, 2627 mCallArgc, mNSEntry->mMinArgs, mNSEntry->mMaxArgs); 2628 Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", mCodeBlock->getFileLine(ip - 6), mNSEntry->mUsage); 2629 STR.popFrame(); 2630 CSTK.popFrame(); 2631 } 2632 else 2633 { 2634 switch (mNSEntry->mType) 2635 { 2636 case Namespace::Entry::StringCallbackType: 2637 { 2638 const char *ret = mNSEntry->cb.mStringCallbackFunc(mThisObject, mCallArgc, mCallArgv); 2639 STR.popFrame(); 2640 CSTK.popFrame(); 2641 if (ret != STR.getStringValue()) 2642 STR.setStringValue(ret); 2643 //else 2644 // sSTR.setLen(dStrlen(ret)); 2645 break; 2646 } 2647 case Namespace::Entry::IntCallbackType: 2648 { 2649 S32 result = mNSEntry->cb.mIntCallbackFunc(mThisObject, mCallArgc, mCallArgv); 2650 STR.popFrame(); 2651 CSTK.popFrame(); 2652 if (code[ip] == OP_STR_TO_UINT) 2653 { 2654 ip++; 2655 intStack[++_UINT] = result; 2656 break; 2657 } 2658 else if (code[ip] == OP_STR_TO_FLT) 2659 { 2660 ip++; 2661 floatStack[++_FLT] = result; 2662 break; 2663 } 2664 else if (code[ip] == OP_STR_TO_NONE) 2665 ip++; 2666 else 2667 STR.setIntValue(result); 2668 break; 2669 } 2670 case Namespace::Entry::FloatCallbackType: 2671 { 2672 F64 result = mNSEntry->cb.mFloatCallbackFunc(mThisObject, mCallArgc, mCallArgv); 2673 STR.popFrame(); 2674 CSTK.popFrame(); 2675 if (code[ip] == OP_STR_TO_UINT) 2676 { 2677 ip++; 2678 intStack[++_UINT] = (S64)result; 2679 break; 2680 } 2681 else if (code[ip] == OP_STR_TO_FLT) 2682 { 2683 ip++; 2684 floatStack[++_FLT] = result; 2685 break; 2686 } 2687 else if (code[ip] == OP_STR_TO_NONE) 2688 ip++; 2689 else 2690 STR.setFloatValue(result); 2691 break; 2692 } 2693 case Namespace::Entry::VoidCallbackType: 2694 mNSEntry->cb.mVoidCallbackFunc(mThisObject, mCallArgc, mCallArgv); 2695 if (code[ip] != OP_STR_TO_NONE && Con::getBoolVariable("$Con::warnVoidAssignment", true)) 2696 Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", mCodeBlock->getFileLine(ip - 6), fnName, mExec.functionName); 2697 2698 STR.popFrame(); 2699 CSTK.popFrame(); 2700 STR.setStringValue(""); 2701 break; 2702 case Namespace::Entry::BoolCallbackType: 2703 { 2704 bool result = mNSEntry->cb.mBoolCallbackFunc(mThisObject, mCallArgc, mCallArgv); 2705 STR.popFrame(); 2706 CSTK.popFrame(); 2707 if (code[ip] == OP_STR_TO_UINT) 2708 { 2709 ip++; 2710 intStack[++_UINT] = result; 2711 break; 2712 } 2713 else if (code[ip] == OP_STR_TO_FLT) 2714 { 2715 ip++; 2716 floatStack[++_FLT] = result; 2717 break; 2718 } 2719 else if (code[ip] == OP_STR_TO_NONE) 2720 ip++; 2721 else 2722 STR.setIntValue(result); 2723 break; 2724 } 2725 } 2726 } 2727 } 2728 2729 return OPCodeReturn::success; 2730} 2731 2732OPCodeReturn CodeInterpreter::op_advance_str(U32 &ip) 2733{ 2734 STR.advance(); 2735 return OPCodeReturn::success; 2736} 2737 2738OPCodeReturn CodeInterpreter::op_advance_str_appendchar(U32 &ip) 2739{ 2740 STR.advanceChar(mCodeBlock->code[ip++]); 2741 return OPCodeReturn::success; 2742} 2743 2744OPCodeReturn CodeInterpreter::op_advance_str_comma(U32 &ip) 2745{ 2746 STR.advanceChar('_'); 2747 return OPCodeReturn::success; 2748} 2749 2750OPCodeReturn CodeInterpreter::op_advance_str_nul(U32 &ip) 2751{ 2752 STR.advanceChar(0); 2753 return OPCodeReturn::success; 2754} 2755 2756OPCodeReturn CodeInterpreter::op_rewind_str(U32 &ip) 2757{ 2758 STR.rewind(); 2759 return OPCodeReturn::success; 2760} 2761 2762OPCodeReturn CodeInterpreter::op_terminate_rewind_str(U32 &ip) 2763{ 2764 STR.rewindTerminate(); 2765 return OPCodeReturn::success; 2766} 2767 2768OPCodeReturn CodeInterpreter::op_compare_str(U32 &ip) 2769{ 2770 intStack[++_UINT] = STR.compare(); 2771 return OPCodeReturn::success; 2772} 2773 2774OPCodeReturn CodeInterpreter::op_push(U32 &ip) 2775{ 2776 STR.push(); 2777 CSTK.pushStringStackPtr(STR.getPreviousStringValuePtr()); 2778 return OPCodeReturn::success; 2779} 2780 2781OPCodeReturn CodeInterpreter::op_push_uint(U32 &ip) 2782{ 2783 CSTK.pushUINT(intStack[_UINT]); 2784 _UINT--; 2785 return OPCodeReturn::success; 2786} 2787 2788OPCodeReturn CodeInterpreter::op_push_flt(U32 &ip) 2789{ 2790 CSTK.pushFLT(floatStack[_FLT]); 2791 _FLT--; 2792 return OPCodeReturn::success; 2793} 2794 2795OPCodeReturn CodeInterpreter::op_push_var(U32 &ip) 2796{ 2797 if (gEvalState.currentVariable) 2798 CSTK.pushValue(gEvalState.currentVariable->value); 2799 else 2800 CSTK.pushString(""); 2801 return OPCodeReturn::success; 2802} 2803 2804OPCodeReturn CodeInterpreter::op_push_this(U32 &ip) 2805{ 2806 StringTableEntry varName = CodeToSTE(mCodeBlock->code, ip); 2807 ip += 2; 2808 2809 // shorthand OP_SETCURVAR 2810 2811 // If a variable is set, then these must be NULL. It is necessary 2812 // to set this here so that the vector parser can appropriately 2813 // identify whether it's dealing with a vector. 2814 mPrevField = NULL; 2815 mPrevObject = NULL; 2816 mCurObject = NULL; 2817 2818 gEvalState.setCurVarName(varName); 2819 2820 // In order to let docblocks work properly with variables, we have 2821 // clear the current docblock when we do an assign. This way it 2822 // won't inappropriately carry forward to following function decls. 2823 mCurFNDocBlock = NULL; 2824 mCurNSDocBlock = NULL; 2825 2826 // shorthand OP_LOADVAR_STR (since objs can be by name we can't assume uint) 2827 STR.setStringValue(gEvalState.getStringVariable()); 2828 2829 // shorthand OP_PUSH 2830 STR.push(); 2831 CSTK.pushStringStackPtr(STR.getPreviousStringValuePtr()); 2832 2833 return OPCodeReturn::success; 2834} 2835 2836OPCodeReturn CodeInterpreter::op_push_frame(U32 &ip) 2837{ 2838 STR.pushFrame(); 2839 CSTK.pushFrame(); 2840 return OPCodeReturn::success; 2841} 2842 2843OPCodeReturn CodeInterpreter::op_assert(U32 &ip) 2844{ 2845 if (!intStack[_UINT--]) 2846 { 2847 const char *message = mCurStringTable + mCodeBlock->code[ip]; 2848 2849 U32 breakLine, inst; 2850 mCodeBlock->findBreakLine(ip - 1, breakLine, inst); 2851 2852 if (PlatformAssert::processAssert(PlatformAssert::Fatal, 2853 mCodeBlock->name ? mCodeBlock->name : "eval", 2854 breakLine, 2855 message)) 2856 { 2857 if (TelDebugger && TelDebugger->isConnected() && breakLine > 0) 2858 { 2859 TelDebugger->breakProcess(); 2860 } 2861 else 2862 Platform::debugBreak(); 2863 } 2864 } 2865 2866 ip++; 2867 2868 return OPCodeReturn::success; 2869} 2870 2871OPCodeReturn CodeInterpreter::op_break(U32 &ip) 2872{ 2873 //append the ip and codeptr before managing the breakpoint! 2874 AssertFatal(gEvalState.getStackDepth() > 0, "Empty eval stack on break!"); 2875 gEvalState.getCurrentFrame().code = mCodeBlock; 2876 gEvalState.getCurrentFrame().ip = ip - 1; 2877 2878 U32 breakLine; 2879 mCodeBlock->findBreakLine(ip - 1, breakLine, mCurrentInstruction); 2880 if (!breakLine) 2881 return OPCodeReturn::breakContinue; 2882 TelDebugger->executionStopped(mCodeBlock, breakLine); 2883 return OPCodeReturn::breakContinue; 2884} 2885 2886OPCodeReturn CodeInterpreter::op_iter_begin_str(U32 &ip) 2887{ 2888 iterStack[_ITER].mIsStringIter = true; 2889 2890 // Emulate fallthrough: 2891 OPCodeReturn fallthrough = op_iter_begin(ip); 2892 2893 return fallthrough; 2894} 2895 2896OPCodeReturn CodeInterpreter::op_iter_begin(U32 &ip) 2897{ 2898 StringTableEntry varName = CodeToSTE(mCodeBlock->code, ip); 2899 U32 failIp = mCodeBlock->code[ip + 2]; 2900 2901 IterStackRecord& iter = iterStack[_ITER]; 2902 2903 if (varName[0] == '$') 2904 iter.mVariable = gEvalState.globalVars.add(varName); 2905 else 2906 iter.mVariable = gEvalState.getCurrentFrame().add(varName); 2907 2908 if (iter.mIsStringIter) 2909 { 2910 iter.mData.mStr.mString = STR.getStringValuePtr(); 2911 iter.mData.mStr.mIndex = 0; 2912 } 2913 else 2914 { 2915 // Look up the object. 2916 2917 SimSet* set; 2918 if (!Sim::findObject(STR.getStringValue(), set)) 2919 { 2920 Con::errorf(ConsoleLogEntry::General, "No SimSet object '%s'", STR.getStringValue()); 2921 Con::errorf(ConsoleLogEntry::General, "Did you mean to use 'foreach$' instead of 'foreach'?"); 2922 ip = failIp; 2923 return OPCodeReturn::success; 2924 } 2925 2926 // Set up. 2927 2928 iter.mData.mObj.mSet = set; 2929 iter.mData.mObj.mIndex = 0; 2930 } 2931 2932 _ITER++; 2933 mIterDepth++; 2934 2935 STR.push(); 2936 2937 ip += 3; 2938 2939 return OPCodeReturn::success; 2940} 2941 2942OPCodeReturn CodeInterpreter::op_iter(U32 &ip) 2943{ 2944 U32 breakIp = mCodeBlock->code[ip]; 2945 IterStackRecord& iter = iterStack[_ITER - 1]; 2946 2947 if (iter.mIsStringIter) 2948 { 2949 const char* str = StringStackPtrRef(iter.mData.mStr.mString).getPtr(&STR); 2950 2951 U32 startIndex = iter.mData.mStr.mIndex; 2952 U32 endIndex = startIndex; 2953 2954 // Break if at end. 2955 2956 if (!str[startIndex]) 2957 { 2958 ip = breakIp; 2959 return OPCodeReturn::success; // continue in old interpreter 2960 } 2961 2962 // Find right end of current component. 2963 2964 if (!dIsspace(str[endIndex])) 2965 do ++endIndex; 2966 while (str[endIndex] && !dIsspace(str[endIndex])); 2967 2968 // Extract component. 2969 2970 if (endIndex != startIndex) 2971 { 2972 char savedChar = str[endIndex]; 2973 const_cast< char* >(str)[endIndex] = '\0'; // We are on the string stack so this is okay. 2974 iter.mVariable->setStringValue(&str[startIndex]); 2975 const_cast< char* >(str)[endIndex] = savedChar; 2976 } 2977 else 2978 iter.mVariable->setStringValue(""); 2979 2980 // Skip separator. 2981 if (str[endIndex] != '\0') 2982 ++endIndex; 2983 2984 iter.mData.mStr.mIndex = endIndex; 2985 } 2986 else 2987 { 2988 U32 index = iter.mData.mObj.mIndex; 2989 SimSet* set = iter.mData.mObj.mSet; 2990 2991 if (index >= set->size()) 2992 { 2993 ip = breakIp; 2994 return OPCodeReturn::success; // continue in old interpreter 2995 } 2996 2997 iter.mVariable->setIntValue(set->at(index)->getId()); 2998 iter.mData.mObj.mIndex = index + 1; 2999 } 3000 3001 ++ip; 3002 3003 return OPCodeReturn::success; 3004} 3005 3006OPCodeReturn CodeInterpreter::op_iter_end(U32 &ip) 3007{ 3008 --_ITER; 3009 --mIterDepth; 3010 STR.rewind(); 3011 iterStack[_ITER].mIsStringIter = false; 3012 return OPCodeReturn::success; 3013} 3014 3015OPCodeReturn CodeInterpreter::op_invalid(U32 &ip) 3016{ 3017 // Invalid does nothing. 3018 return OPCodeReturn::exitCode; 3019} 3020