compiledEval.cc 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "console/console.h"
  24. #include "console/ast.h"
  25. #include "collection/findIterator.h"
  26. #include "io/resource/resourceManager.h"
  27. #include "string/findMatch.h"
  28. #include "console/consoleInternal.h"
  29. #include "io/fileStream.h"
  30. #include "console/compiler.h"
  31. #include "sim/simBase.h"
  32. #include "network/netStringTable.h"
  33. #include "component/dynamicConsoleMethodComponent.h"
  34. #include "string/stringStack.h"
  35. #include "messaging/message.h"
  36. #include "memory/frameAllocator.h"
  37. #include "debug/telnetDebugger.h"
  38. #ifndef _REMOTE_DEBUGGER_BASE_H_
  39. #include "debug/remote/RemoteDebuggerBase.h"
  40. #endif
  41. using namespace Compiler;
  42. enum EvalConstants {
  43. MaxStackSize = 1024,
  44. MethodOnComponent = -2
  45. };
  46. namespace Con
  47. {
  48. // Current script file name and root, these are registered as
  49. // console variables.
  50. extern StringTableEntry gCurrentFile;
  51. extern StringTableEntry gCurrentRoot;
  52. }
  53. F64 floatStack[MaxStackSize];
  54. S64 intStack[MaxStackSize];
  55. StringStack STR;
  56. U32 FLT = 0;
  57. U32 UINT = 0;
  58. static const char *getNamespaceList(Namespace *ns)
  59. {
  60. U32 size = 1;
  61. Namespace * walk;
  62. for(walk = ns; walk; walk = walk->mParent)
  63. size += dStrlen(walk->mName) + 4;
  64. char *ret = Con::getReturnBuffer(size);
  65. ret[0] = 0;
  66. for(walk = ns; walk; walk = walk->mParent)
  67. {
  68. dStrcat(ret, walk->mName);
  69. if(walk->mParent)
  70. dStrcat(ret, " -> ");
  71. }
  72. return ret;
  73. }
  74. //------------------------------------------------------------
  75. F64 consoleStringToNumber(const char *str, StringTableEntry file, U32 line)
  76. {
  77. F64 val = dAtof(str);
  78. if(val != 0)
  79. return val;
  80. else if(!dStricmp(str, "true"))
  81. return 1;
  82. else if(!dStricmp(str, "false"))
  83. return 0;
  84. else if(file)
  85. {
  86. Con::warnf(ConsoleLogEntry::General, "%s (%d): string always evaluates to 0.", file, line);
  87. return 0;
  88. }
  89. return 0;
  90. }
  91. //------------------------------------------------------------
  92. namespace Con
  93. {
  94. char *getReturnBuffer(U32 bufferSize)
  95. {
  96. return STR.getReturnBuffer(bufferSize);
  97. }
  98. char *getReturnBuffer( const char *stringToCopy )
  99. {
  100. char *ret = STR.getReturnBuffer( dStrlen( stringToCopy ) + 1 );
  101. dStrcpy( ret, stringToCopy );
  102. ret[dStrlen( stringToCopy )] = '\0';
  103. return ret;
  104. }
  105. char *getArgBuffer(U32 bufferSize)
  106. {
  107. return STR.getArgBuffer(bufferSize);
  108. }
  109. char *getFloatArg(F64 arg)
  110. {
  111. char *ret = STR.getArgBuffer(32);
  112. dSprintf(ret, 32, "%g", arg);
  113. return ret;
  114. }
  115. char *getIntArg(S32 arg)
  116. {
  117. char *ret = STR.getArgBuffer(32);
  118. dSprintf(ret, 32, "%d", arg);
  119. return ret;
  120. }
  121. char* getBoolArg(bool arg)
  122. {
  123. char *ret = STR.getArgBuffer(32);
  124. dSprintf(ret, 32, "%d", arg);
  125. return ret;
  126. }
  127. }
  128. //------------------------------------------------------------
  129. inline void ExprEvalState::setCurVarName(StringTableEntry name)
  130. {
  131. if(name[0] == '$')
  132. currentVariable = globalVars.lookup(name);
  133. else if(stack.size())
  134. currentVariable = stack.last()->lookup(name);
  135. if(!currentVariable && gWarnUndefinedScriptVariables)
  136. Con::warnf(ConsoleLogEntry::Script, "Variable referenced before assignment: %s", name);
  137. }
  138. inline void ExprEvalState::setCurVarNameCreate(StringTableEntry name)
  139. {
  140. if(name[0] == '$')
  141. currentVariable = globalVars.add(name);
  142. else if(stack.size())
  143. currentVariable = stack.last()->add(name);
  144. else
  145. {
  146. currentVariable = NULL;
  147. Con::warnf(ConsoleLogEntry::Script, "Accessing local variable in global scope... failed: %s", name);
  148. }
  149. }
  150. //------------------------------------------------------------
  151. inline S32 ExprEvalState::getIntVariable()
  152. {
  153. return currentVariable ? currentVariable->getIntValue() : 0;
  154. }
  155. inline F64 ExprEvalState::getFloatVariable()
  156. {
  157. return currentVariable ? currentVariable->getFloatValue() : 0;
  158. }
  159. inline const char *ExprEvalState::getStringVariable()
  160. {
  161. return currentVariable ? currentVariable->getStringValue() : "";
  162. }
  163. //------------------------------------------------------------
  164. inline void ExprEvalState::setIntVariable(S32 val)
  165. {
  166. AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!");
  167. currentVariable->setIntValue(val);
  168. }
  169. inline void ExprEvalState::setFloatVariable(F64 val)
  170. {
  171. AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!");
  172. currentVariable->setFloatValue((F32)val);
  173. }
  174. inline void ExprEvalState::setStringVariable(const char *val)
  175. {
  176. AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!");
  177. currentVariable->setStringValue(val);
  178. }
  179. //------------------------------------------------------------
  180. void CodeBlock::getFunctionArgs(char buffer[1024], U32 ip)
  181. {
  182. U32 fnArgc = code[ip + 5];
  183. buffer[0] = 0;
  184. for(U32 i = 0; i < fnArgc; i++)
  185. {
  186. StringTableEntry var = U32toSTE(code[ip + i + 6]);
  187. // Add a comma so it looks nice!
  188. if(i != 0)
  189. dStrcat(buffer, ", ");
  190. dStrcat(buffer, "var ");
  191. // Try to capture junked parameters
  192. if(var[0])
  193. dStrcat(buffer, var+1);
  194. else
  195. dStrcat(buffer, "JUNK");
  196. }
  197. }
  198. // Returns, in 'val', the specified component of a string.
  199. static void getUnit(const char *string, U32 index, const char *set, char val[], S32 len)
  200. {
  201. U32 sz;
  202. while(index--)
  203. {
  204. if(!*string)
  205. return;
  206. sz = dStrcspn(string, set);
  207. if (string[sz] == 0)
  208. return;
  209. string += (sz + 1);
  210. }
  211. sz = dStrcspn(string, set);
  212. if (sz == 0)
  213. return;
  214. if( ( sz + 1 ) > (U32)len )
  215. return;
  216. dStrncpy(val, string, sz);
  217. val[sz] = '\0';
  218. }
  219. // Copies a string, replacing the (space separated) specified component. The
  220. // return value is stored in 'val'.
  221. static void setUnit(const char *string, U32 index, const char *replace, const char *set, char val[], S32 len)
  222. {
  223. U32 sz;
  224. const char *start = string;
  225. if( ( dStrlen(string) + dStrlen(replace) + 1 ) > (U32)len )
  226. return;
  227. U32 padCount = 0;
  228. while(index--)
  229. {
  230. sz = dStrcspn(string, set);
  231. if(string[sz] == 0)
  232. {
  233. string += sz;
  234. padCount = index + 1;
  235. break;
  236. }
  237. else
  238. string += (sz + 1);
  239. }
  240. // copy first chunk
  241. sz = string-start;
  242. dStrncpy(val, start, sz);
  243. for(U32 i = 0; i < padCount; i++)
  244. val[sz++] = set[0];
  245. // replace this unit
  246. val[sz] = '\0';
  247. dStrcat(val, replace);
  248. // copy remaining chunks
  249. sz = dStrcspn(string, set); // skip chunk we're replacing
  250. if(!sz && !string[sz])
  251. return;
  252. string += sz;
  253. dStrcat(val, string);
  254. return;
  255. }
  256. // Gets a component of an object's field value or a variable and returns it
  257. // in val.
  258. static void getFieldComponent( SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField, char val[], S32 count )
  259. {
  260. const char* prevVal = NULL;
  261. // Grab value from object.
  262. if( object && field )
  263. prevVal = object->getDataField( field, array );
  264. // Otherwise, grab from the string stack. The value coming in will always
  265. // be a string because that is how multicomponent variables are handled.
  266. else
  267. prevVal = STR.getStringValue();
  268. // Make sure we got a value.
  269. if( prevVal && *prevVal )
  270. {
  271. // 'x', 'y', and 'z' grab the 1st, 2nd, or 3rd component of the
  272. // variable or field.
  273. if( subField == StringTable->insert( "x" ) )
  274. getUnit( prevVal, 0, " ", val, count );
  275. else if( subField == StringTable->insert( "y" ) )
  276. getUnit( prevVal, 1, " ", val, count );
  277. else if( subField == StringTable->insert( "z" ) )
  278. getUnit( prevVal, 2, " ", val, count );
  279. }
  280. }
  281. // Sets a component of an object's field value based on the sub field. 'x' will
  282. // set the first field, 'y' the second, and 'z' the third.
  283. static void setFieldComponent( SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField )
  284. {
  285. char val[1024] = "";
  286. const char* prevVal;
  287. // Set the value on an object field.
  288. if( object && field )
  289. prevVal = object->getDataField( field, array );
  290. // Set the value on a variable.
  291. else if( gEvalState.currentVariable )
  292. prevVal = gEvalState.getStringVariable();
  293. // Insert the value into the specified component of the string.
  294. bool set = false;
  295. if( subField == StringTable->insert( "x" ) )
  296. {
  297. setUnit( prevVal, 0, STR.getStringValue(), " ", val, 1024 );
  298. set = true;
  299. }
  300. else if( subField == StringTable->insert( "y" ) )
  301. {
  302. setUnit( prevVal, 1, STR.getStringValue(), " ", val, 1024 );
  303. set = true;
  304. }
  305. else if( subField == StringTable->insert( "z" ) )
  306. {
  307. setUnit( prevVal, 2, STR.getStringValue(), " ", val, 1024 );
  308. set = true;
  309. }
  310. if( set )
  311. {
  312. // Update the field or variable.
  313. if( object && field )
  314. object->setDataField( field, array, val );
  315. else if( gEvalState.currentVariable )
  316. gEvalState.setStringVariable( val );
  317. }
  318. }
  319. const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNamespace, U32 argc, const char **argv, bool noCalls, StringTableEntry packageName, S32 setFrame)
  320. {
  321. #ifdef TORQUE_DEBUG
  322. U32 stackStart = STR.mStartStackSize;
  323. #endif
  324. static char traceBuffer[1024];
  325. U32 i;
  326. incRefCount();
  327. F64 *curFloatTable;
  328. char *curStringTable;
  329. STR.clearFunctionOffset();
  330. StringTableEntry thisFunctionName = NULL;
  331. bool popFrame = false;
  332. if(argv)
  333. {
  334. // assume this points into a function decl:
  335. U32 fnArgc = code[ip + 5];
  336. thisFunctionName = U32toSTE(code[ip]);
  337. argc = getMin(argc-1, fnArgc); // argv[0] is func name
  338. if(gEvalState.traceOn)
  339. {
  340. traceBuffer[0] = 0;
  341. dStrcat(traceBuffer, "Entering ");
  342. if(packageName)
  343. {
  344. dStrcat(traceBuffer, "[");
  345. dStrcat(traceBuffer, packageName);
  346. dStrcat(traceBuffer, "]");
  347. }
  348. if(thisNamespace && thisNamespace->mName)
  349. {
  350. dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
  351. "%s::%s(", thisNamespace->mName, thisFunctionName);
  352. }
  353. else
  354. {
  355. dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
  356. "%s(", thisFunctionName);
  357. }
  358. for(i = 0; i < argc; i++)
  359. {
  360. dStrcat(traceBuffer, argv[i+1]);
  361. if(i != argc - 1)
  362. dStrcat(traceBuffer, ", ");
  363. }
  364. dStrcat(traceBuffer, ")");
  365. Con::printf("%s", traceBuffer);
  366. }
  367. gEvalState.pushFrame(thisFunctionName, thisNamespace);
  368. popFrame = true;
  369. for(i = 0; i < argc; i++)
  370. {
  371. StringTableEntry var = U32toSTE(code[ip + i + 6]);
  372. gEvalState.setCurVarNameCreate(var);
  373. gEvalState.setStringVariable(argv[i+1]);
  374. }
  375. ip = ip + fnArgc + 6;
  376. curFloatTable = functionFloats;
  377. curStringTable = functionStrings;
  378. }
  379. else
  380. {
  381. curFloatTable = globalFloats;
  382. curStringTable = globalStrings;
  383. // Do we want this code to execute using a new stack frame?
  384. if (setFrame < 0)
  385. {
  386. gEvalState.pushFrame(NULL, NULL);
  387. popFrame = true;
  388. }
  389. else if (!gEvalState.stack.empty())
  390. {
  391. // We want to copy a reference to an existing stack frame
  392. // on to the top of the stack. Any change that occurs to
  393. // the locals during this new frame will also occur in the
  394. // original frame.
  395. S32 stackIndex = gEvalState.stack.size() - setFrame - 1;
  396. gEvalState.pushFrameRef( stackIndex );
  397. popFrame = true;
  398. }
  399. }
  400. // Grab the state of the telenet debugger here once
  401. // so that the push and pop frames are always balanced.
  402. const bool telDebuggerOn = TelDebugger && TelDebugger->isConnected();
  403. if ( telDebuggerOn && setFrame < 0 )
  404. TelDebugger->pushStackFrame();
  405. // Notify the remote debugger.
  406. RemoteDebuggerBase* pRemoteDebugger = RemoteDebuggerBase::getRemoteDebugger();
  407. if ( pRemoteDebugger != NULL && setFrame < 0 )
  408. pRemoteDebugger->pushStackFrame();
  409. StringTableEntry var, objParent;
  410. U32 failJump;
  411. StringTableEntry fnName;
  412. StringTableEntry fnNamespace, fnPackage;
  413. SimObject *currentNewObject = 0;
  414. StringTableEntry prevField = NULL;
  415. StringTableEntry curField = NULL;
  416. SimObject *prevObject = NULL;
  417. SimObject *curObject = NULL;
  418. SimObject *saveObject=NULL;
  419. Namespace::Entry *nsEntry;
  420. Namespace *ns;
  421. const char* curFNDocBlock = NULL;
  422. const char* curNSDocBlock = NULL;
  423. const S32 nsDocLength = 128;
  424. char nsDocBlockClass[nsDocLength];
  425. U32 callArgc;
  426. const char **callArgv;
  427. static char curFieldArray[256];
  428. static char prevFieldArray[256];
  429. CodeBlock *saveCodeBlock = smCurrentCodeBlock;
  430. smCurrentCodeBlock = this;
  431. if(this->name)
  432. {
  433. Con::gCurrentFile = this->name;
  434. Con::gCurrentRoot = mRoot;
  435. }
  436. const char * val;
  437. // The frame temp is used by the variable accessor ops (OP_SAVEFIELD_* and
  438. // OP_LOADFIELD_*) to store temporary values for the fields.
  439. static S32 VAL_BUFFER_SIZE = 1024;
  440. FrameTemp<char> valBuffer( VAL_BUFFER_SIZE );
  441. for(;;)
  442. {
  443. U32 instruction = code[ip++];
  444. breakContinue:
  445. switch(instruction)
  446. {
  447. case OP_FUNC_DECL:
  448. if(!noCalls)
  449. {
  450. fnName = U32toSTE(code[ip]);
  451. fnNamespace = U32toSTE(code[ip+1]);
  452. fnPackage = U32toSTE(code[ip+2]);
  453. bool hasBody = bool(code[ip+3]);
  454. Namespace::unlinkPackages();
  455. ns = Namespace::find(fnNamespace, fnPackage);
  456. ns->addFunction(fnName, this, hasBody ? ip : 0, curFNDocBlock ? dStrdup( curFNDocBlock ) : NULL );// if no body, set the IP to 0
  457. if( curNSDocBlock )
  458. {
  459. if( fnNamespace == StringTable->lookup( nsDocBlockClass ) )
  460. {
  461. char *usageStr = dStrdup( curNSDocBlock );
  462. usageStr[dStrlen(usageStr)] = '\0';
  463. ns->mUsage = usageStr;
  464. ns->mCleanUpUsage = true;
  465. curNSDocBlock = NULL;
  466. }
  467. }
  468. Namespace::relinkPackages();
  469. // If we had a docblock, it's definitely not valid anymore, so clear it out.
  470. curFNDocBlock = NULL;
  471. //Con::printf("Adding function %s::%s (%d)", fnNamespace, fnName, ip);
  472. }
  473. ip = code[ip + 4];
  474. break;
  475. case OP_CREATE_OBJECT:
  476. {
  477. // Read some useful info.
  478. objParent = U32toSTE(code[ip ]);
  479. bool isDataBlock = code[ip + 1];
  480. bool isInternal = code[ip + 2];
  481. bool isMessage = code[ip + 3];
  482. failJump = code[ip + 4];
  483. // If we don't allow calls, we certainly don't allow creating objects!
  484. // Moved this to after failJump is set. Engine was crashing when
  485. // noCalls = true and an object was being created at the beginning of
  486. // a file. ADL.
  487. if(noCalls)
  488. {
  489. ip = failJump;
  490. break;
  491. }
  492. // Get the constructor information off the stack.
  493. STR.getArgcArgv(NULL, &callArgc, &callArgv, true);
  494. // Con::printf("Creating object...");
  495. // objectName = argv[1]...
  496. currentNewObject = NULL;
  497. // Are we creating a datablock? If so, deal with case where we override
  498. // an old one.
  499. if(isDataBlock)
  500. {
  501. // Con::printf(" - is a datablock");
  502. // Find the old one if any.
  503. SimObject *db = Sim::getDataBlockGroup()->findObject(callArgv[2]);
  504. // Make sure we're not changing types on ourselves...
  505. if(db && dStricmp(db->getClassName(), callArgv[1]))
  506. {
  507. Con::errorf(ConsoleLogEntry::General, "Cannot re-declare data block %s with a different class.", callArgv[2]);
  508. ip = failJump;
  509. break;
  510. }
  511. // If there was one, set the currentNewObject and move on.
  512. if(db)
  513. currentNewObject = db;
  514. }
  515. if(!currentNewObject)
  516. {
  517. // Well, looks like we have to create a new object.
  518. ConsoleObject *object = ConsoleObject::create(callArgv[1]);
  519. // Deal with failure!
  520. if(!object)
  521. {
  522. Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-conobject class %s.", getFileLine(ip-1), callArgv[1]);
  523. ip = failJump;
  524. break;
  525. }
  526. // Do special datablock init if appropros
  527. if(isDataBlock)
  528. {
  529. SimDataBlock *dataBlock = dynamic_cast<SimDataBlock *>(object);
  530. if(dataBlock)
  531. {
  532. dataBlock->assignId();
  533. }
  534. else
  535. {
  536. // They tried to make a non-datablock with a datablock keyword!
  537. Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-datablock class %s.", getFileLine(ip-1), callArgv[1]);
  538. // Clean up...
  539. delete object;
  540. ip = failJump;
  541. break;
  542. }
  543. }
  544. // Finally, set currentNewObject to point to the new one.
  545. currentNewObject = dynamic_cast<SimObject *>(object);
  546. // Deal with the case of a non-SimObject.
  547. if(!currentNewObject)
  548. {
  549. Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-SimObject class %s.", getFileLine(ip-1), callArgv[1]);
  550. delete object;
  551. ip = failJump;
  552. break;
  553. }
  554. // Does it have a parent object? (ie, the copy constructor : syntax, not inheriance)
  555. // [tom, 9/8/2006] it is inheritance if it's a message ... muwahahah!
  556. if(!isMessage && *objParent)
  557. {
  558. // Find it!
  559. SimObject *parent;
  560. if(Sim::findObject(objParent, parent))
  561. {
  562. // Con::printf(" - Parent object found: %s", parent->getClassName());
  563. // and suck the juices from it!
  564. currentNewObject->assignFieldsFrom(parent);
  565. }
  566. else
  567. Con::errorf(ConsoleLogEntry::General, "%s: Unable to find parent object %s for %s.", getFileLine(ip-1), objParent, callArgv[1]);
  568. // Mm! Juices!
  569. }
  570. // If a name was passed, assign it.
  571. if(callArgv[2][0])
  572. {
  573. if(! isMessage)
  574. {
  575. if(! isInternal)
  576. currentNewObject->assignName(callArgv[2]);
  577. else
  578. currentNewObject->setInternalName(callArgv[2]);
  579. }
  580. else
  581. {
  582. Message *msg = dynamic_cast<Message *>(currentNewObject);
  583. if(msg)
  584. {
  585. msg->setClassNamespace(callArgv[2]);
  586. msg->setSuperClassNamespace(objParent);
  587. }
  588. else
  589. {
  590. Con::errorf(ConsoleLogEntry::General, "%s: Attempting to use newmsg on non-message type %s", getFileLine(ip-1), callArgv[1]);
  591. delete currentNewObject;
  592. currentNewObject = NULL;
  593. ip = failJump;
  594. break;
  595. }
  596. }
  597. }
  598. // Do the constructor parameters.
  599. if(!currentNewObject->processArguments(callArgc-3, callArgv+3))
  600. {
  601. delete currentNewObject;
  602. currentNewObject = NULL;
  603. ip = failJump;
  604. break;
  605. }
  606. // If it's not a datablock, allow people to modify bits of it.
  607. if(!isDataBlock)
  608. {
  609. currentNewObject->setModStaticFields(true);
  610. currentNewObject->setModDynamicFields(true);
  611. }
  612. }
  613. // Advance the IP past the create info...
  614. ip += 5;
  615. break;
  616. }
  617. case OP_ADD_OBJECT:
  618. {
  619. // See OP_SETCURVAR for why we do this.
  620. curFNDocBlock = NULL;
  621. curNSDocBlock = NULL;
  622. // Do we place this object at the root?
  623. bool placeAtRoot = code[ip++];
  624. // Con::printf("Adding object %s", currentNewObject->getName());
  625. // Make sure it wasn't already added, then add it.
  626. if (currentNewObject == NULL)
  627. {
  628. break;
  629. }
  630. if(currentNewObject->isProperlyAdded() == false)
  631. {
  632. bool ret = false;
  633. Message *msg = dynamic_cast<Message *>(currentNewObject);
  634. if(msg)
  635. {
  636. SimObjectId id = Message::getNextMessageID();
  637. if(id != 0xffffffff)
  638. ret = currentNewObject->registerObject(id);
  639. else
  640. Con::errorf("%s: No more object IDs available for messages", getFileLine(ip-2));
  641. }
  642. else
  643. ret = currentNewObject->registerObject();
  644. if(! ret)
  645. {
  646. // This error is usually caused by failing to call Parent::initPersistFields in the class' initPersistFields().
  647. Con::warnf(ConsoleLogEntry::General, "%s: Register object failed for object %s of class %s.", getFileLine(ip-2), currentNewObject->getName(), currentNewObject->getClassName());
  648. delete currentNewObject;
  649. ip = failJump;
  650. break;
  651. }
  652. }
  653. // Are we dealing with a datablock?
  654. SimDataBlock *dataBlock = dynamic_cast<SimDataBlock *>(currentNewObject);
  655. static char errorBuffer[256];
  656. // If so, preload it.
  657. if(dataBlock && !dataBlock->preload(true, errorBuffer))
  658. {
  659. Con::errorf(ConsoleLogEntry::General, "%s: preload failed for %s: %s.", getFileLine(ip-2),
  660. currentNewObject->getName(), errorBuffer);
  661. dataBlock->deleteObject();
  662. ip = failJump;
  663. break;
  664. }
  665. // What group will we be added to, if any?
  666. U32 groupAddId = (U32)intStack[UINT];
  667. SimGroup *grp = NULL;
  668. SimSet *set = NULL;
  669. SimComponent *comp = NULL;
  670. bool isMessage = dynamic_cast<Message *>(currentNewObject) != NULL;
  671. if(!placeAtRoot || !currentNewObject->getGroup())
  672. {
  673. if(! isMessage)
  674. {
  675. if(! placeAtRoot)
  676. {
  677. // Otherwise just add to the requested group or set.
  678. if(!Sim::findObject(groupAddId, grp))
  679. if(!Sim::findObject(groupAddId, comp))
  680. Sim::findObject(groupAddId, set);
  681. }
  682. if(placeAtRoot || comp != NULL)
  683. {
  684. // Deal with the instantGroup if we're being put at the root or we're adding to a component.
  685. const char *addGroupName = Con::getVariable("instantGroup");
  686. if(!Sim::findObject(addGroupName, grp))
  687. Sim::findObject(RootGroupId, grp);
  688. }
  689. if(comp)
  690. {
  691. SimComponent *newComp = dynamic_cast<SimComponent *>(currentNewObject);
  692. if(newComp)
  693. {
  694. if(! comp->addComponent(newComp))
  695. Con::errorf("%s: Unable to add component %s, template not loaded?", getFileLine(ip-2), currentNewObject->getName() ? currentNewObject->getName() : currentNewObject->getIdString());
  696. }
  697. }
  698. }
  699. // If we didn't get a group, then make sure we have a pointer to
  700. // the rootgroup.
  701. if(!grp)
  702. Sim::findObject(RootGroupId, grp);
  703. // add to the parent group
  704. grp->addObject(currentNewObject);
  705. // add to any set we might be in
  706. if(set)
  707. set->addObject(currentNewObject);
  708. }
  709. // store the new object's ID on the stack (overwriting the group/set
  710. // id, if one was given, otherwise getting pushed)
  711. if(placeAtRoot)
  712. intStack[UINT] = currentNewObject->getId();
  713. else
  714. intStack[++UINT] = currentNewObject->getId();
  715. break;
  716. }
  717. case OP_END_OBJECT:
  718. {
  719. // If we're not to be placed at the root, make sure we clean up
  720. // our group reference.
  721. bool placeAtRoot = code[ip++];
  722. if(!placeAtRoot)
  723. UINT--;
  724. break;
  725. }
  726. case OP_JMPIFFNOT:
  727. if(floatStack[FLT--])
  728. {
  729. ip++;
  730. break;
  731. }
  732. ip = code[ip];
  733. break;
  734. case OP_JMPIFNOT:
  735. if(intStack[UINT--])
  736. {
  737. ip++;
  738. break;
  739. }
  740. ip = code[ip];
  741. break;
  742. case OP_JMPIFF:
  743. if(!floatStack[FLT--])
  744. {
  745. ip++;
  746. break;
  747. }
  748. ip = code[ip];
  749. break;
  750. case OP_JMPIF:
  751. if(!intStack[UINT--])
  752. {
  753. ip ++;
  754. break;
  755. }
  756. ip = code[ip];
  757. break;
  758. case OP_JMPIFNOT_NP:
  759. if(intStack[UINT])
  760. {
  761. UINT--;
  762. ip++;
  763. break;
  764. }
  765. ip = code[ip];
  766. break;
  767. case OP_JMPIF_NP:
  768. if(!intStack[UINT])
  769. {
  770. UINT--;
  771. ip++;
  772. break;
  773. }
  774. ip = code[ip];
  775. break;
  776. case OP_JMP:
  777. ip = code[ip];
  778. break;
  779. case OP_RETURN:
  780. goto execFinished;
  781. case OP_CMPEQ:
  782. intStack[UINT+1] = bool(floatStack[FLT] == floatStack[FLT-1]);
  783. UINT++;
  784. FLT -= 2;
  785. break;
  786. case OP_CMPGR:
  787. intStack[UINT+1] = bool(floatStack[FLT] > floatStack[FLT-1]);
  788. UINT++;
  789. FLT -= 2;
  790. break;
  791. case OP_CMPGE:
  792. intStack[UINT+1] = bool(floatStack[FLT] >= floatStack[FLT-1]);
  793. UINT++;
  794. FLT -= 2;
  795. break;
  796. case OP_CMPLT:
  797. intStack[UINT+1] = bool(floatStack[FLT] < floatStack[FLT-1]);
  798. UINT++;
  799. FLT -= 2;
  800. break;
  801. case OP_CMPLE:
  802. intStack[UINT+1] = bool(floatStack[FLT] <= floatStack[FLT-1]);
  803. UINT++;
  804. FLT -= 2;
  805. break;
  806. case OP_CMPNE:
  807. intStack[UINT+1] = bool(floatStack[FLT] != floatStack[FLT-1]);
  808. UINT++;
  809. FLT -= 2;
  810. break;
  811. case OP_XOR:
  812. intStack[UINT-1] = intStack[UINT] ^ intStack[UINT-1];
  813. UINT--;
  814. break;
  815. case OP_MOD:
  816. if( intStack[UINT-1] != 0 )
  817. intStack[UINT-1] = intStack[UINT] % intStack[UINT-1];
  818. else
  819. intStack[UINT-1] = 0;
  820. UINT--;
  821. break;
  822. case OP_BITAND:
  823. intStack[UINT-1] = intStack[UINT] & intStack[UINT-1];
  824. UINT--;
  825. break;
  826. case OP_BITOR:
  827. intStack[UINT-1] = intStack[UINT] | intStack[UINT-1];
  828. UINT--;
  829. break;
  830. case OP_NOT:
  831. intStack[UINT] = !intStack[UINT];
  832. break;
  833. case OP_NOTF:
  834. intStack[UINT+1] = !floatStack[FLT];
  835. FLT--;
  836. UINT++;
  837. break;
  838. case OP_ONESCOMPLEMENT:
  839. intStack[UINT] = ~intStack[UINT];
  840. break;
  841. case OP_SHR:
  842. intStack[UINT-1] = intStack[UINT] >> intStack[UINT-1];
  843. UINT--;
  844. break;
  845. case OP_SHL:
  846. intStack[UINT-1] = intStack[UINT] << intStack[UINT-1];
  847. UINT--;
  848. break;
  849. case OP_AND:
  850. intStack[UINT-1] = intStack[UINT] && intStack[UINT-1];
  851. UINT--;
  852. break;
  853. case OP_OR:
  854. intStack[UINT-1] = intStack[UINT] || intStack[UINT-1];
  855. UINT--;
  856. break;
  857. case OP_ADD:
  858. floatStack[FLT-1] = floatStack[FLT] + floatStack[FLT-1];
  859. FLT--;
  860. break;
  861. case OP_SUB:
  862. floatStack[FLT-1] = floatStack[FLT] - floatStack[FLT-1];
  863. FLT--;
  864. break;
  865. case OP_MUL:
  866. floatStack[FLT-1] = floatStack[FLT] * floatStack[FLT-1];
  867. FLT--;
  868. break;
  869. case OP_DIV:
  870. floatStack[FLT-1] = floatStack[FLT] / floatStack[FLT-1];
  871. FLT--;
  872. break;
  873. case OP_NEG:
  874. floatStack[FLT] = -floatStack[FLT];
  875. break;
  876. case OP_SETCURVAR:
  877. var = U32toSTE(code[ip]);
  878. ip++;
  879. // If a variable is set, then these must be NULL. It is necessary
  880. // to set this here so that the vector parser can appropriately
  881. // identify whether it's dealing with a vector.
  882. prevField = NULL;
  883. prevObject = NULL;
  884. curObject = NULL;
  885. gEvalState.setCurVarName(var);
  886. // In order to let docblocks work properly with variables, we have
  887. // clear the current docblock when we do an assign. This way it
  888. // won't inappropriately carry forward to following function decls.
  889. curFNDocBlock = NULL;
  890. curNSDocBlock = NULL;
  891. break;
  892. case OP_SETCURVAR_CREATE:
  893. var = U32toSTE(code[ip]);
  894. ip++;
  895. // See OP_SETCURVAR
  896. prevField = NULL;
  897. prevObject = NULL;
  898. curObject = NULL;
  899. gEvalState.setCurVarNameCreate(var);
  900. // See OP_SETCURVAR for why we do this.
  901. curFNDocBlock = NULL;
  902. curNSDocBlock = NULL;
  903. break;
  904. case OP_SETCURVAR_ARRAY:
  905. var = STR.getSTValue();
  906. // See OP_SETCURVAR
  907. prevField = NULL;
  908. prevObject = NULL;
  909. curObject = NULL;
  910. gEvalState.setCurVarName(var);
  911. // See OP_SETCURVAR for why we do this.
  912. curFNDocBlock = NULL;
  913. curNSDocBlock = NULL;
  914. break;
  915. case OP_SETCURVAR_ARRAY_CREATE:
  916. var = STR.getSTValue();
  917. // See OP_SETCURVAR
  918. prevField = NULL;
  919. prevObject = NULL;
  920. curObject = NULL;
  921. gEvalState.setCurVarNameCreate(var);
  922. // See OP_SETCURVAR for why we do this.
  923. curFNDocBlock = NULL;
  924. curNSDocBlock = NULL;
  925. break;
  926. case OP_LOADVAR_UINT:
  927. intStack[UINT+1] = gEvalState.getIntVariable();
  928. UINT++;
  929. break;
  930. case OP_LOADVAR_FLT:
  931. floatStack[FLT+1] = gEvalState.getFloatVariable();
  932. FLT++;
  933. break;
  934. case OP_LOADVAR_STR:
  935. val = gEvalState.getStringVariable();
  936. STR.setStringValue(val);
  937. break;
  938. case OP_SAVEVAR_UINT:
  939. gEvalState.setIntVariable((S32)intStack[UINT]);
  940. break;
  941. case OP_SAVEVAR_FLT:
  942. gEvalState.setFloatVariable(floatStack[FLT]);
  943. break;
  944. case OP_SAVEVAR_STR:
  945. gEvalState.setStringVariable(STR.getStringValue());
  946. break;
  947. case OP_SETCUROBJECT:
  948. // Save the previous object for parsing vector fields.
  949. prevObject = curObject;
  950. val = STR.getStringValue();
  951. // Sim::findObject will sometimes find valid objects from
  952. // multi-component strings. This makes sure that doesn't
  953. // happen.
  954. for( const char* check = val; *check; check++ )
  955. {
  956. if( *check == ' ' )
  957. {
  958. val = "";
  959. break;
  960. }
  961. }
  962. curObject = Sim::findObject(val);
  963. break;
  964. case OP_SETCUROBJECT_INTERNAL:
  965. ++ip; // To skip the recurse flag if the object wasnt found
  966. if(curObject)
  967. {
  968. SimGroup *group = dynamic_cast<SimGroup *>(curObject);
  969. if(group)
  970. {
  971. StringTableEntry intName = StringTable->insert(STR.getStringValue());
  972. bool recurse = code[ip-1];
  973. SimObject *obj = group->findObjectByInternalName(intName, recurse);
  974. intStack[UINT+1] = obj ? obj->getId() : 0;
  975. UINT++;
  976. }
  977. else
  978. {
  979. Con::errorf(ConsoleLogEntry::Script, "%s: Attempt to use -> on non-group %s of class %s.", getFileLine(ip-2), curObject->getName(), curObject->getClassName());
  980. intStack[UINT] = 0;
  981. }
  982. }
  983. break;
  984. case OP_SETCUROBJECT_NEW:
  985. curObject = currentNewObject;
  986. break;
  987. case OP_SETCURFIELD:
  988. // Save the previous field for parsing vector fields.
  989. prevField = curField;
  990. dStrcpy( prevFieldArray, curFieldArray );
  991. curField = U32toSTE(code[ip]);
  992. curFieldArray[0] = 0;
  993. ip++;
  994. break;
  995. case OP_SETCURFIELD_ARRAY:
  996. dStrcpy(curFieldArray, STR.getStringValue());
  997. break;
  998. case OP_LOADFIELD_UINT:
  999. if(curObject)
  1000. intStack[UINT+1] = U32(dAtoi(curObject->getDataField(curField, curFieldArray)));
  1001. else
  1002. {
  1003. // The field is not being retrieved from an object. Maybe it's
  1004. // a special accessor?
  1005. getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer, VAL_BUFFER_SIZE );
  1006. intStack[UINT+1] = dAtoi( valBuffer );
  1007. }
  1008. UINT++;
  1009. break;
  1010. case OP_LOADFIELD_FLT:
  1011. if(curObject)
  1012. floatStack[FLT+1] = dAtof(curObject->getDataField(curField, curFieldArray));
  1013. else
  1014. {
  1015. // The field is not being retrieved from an object. Maybe it's
  1016. // a special accessor?
  1017. getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer, VAL_BUFFER_SIZE );
  1018. floatStack[FLT+1] = dAtof( valBuffer );
  1019. }
  1020. FLT++;
  1021. break;
  1022. case OP_LOADFIELD_STR:
  1023. if(curObject)
  1024. {
  1025. val = curObject->getDataField(curField, curFieldArray);
  1026. STR.setStringValue( val );
  1027. }
  1028. else
  1029. {
  1030. // The field is not being retrieved from an object. Maybe it's
  1031. // a special accessor?
  1032. getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer, VAL_BUFFER_SIZE );
  1033. STR.setStringValue( valBuffer );
  1034. }
  1035. break;
  1036. case OP_SAVEFIELD_UINT:
  1037. STR.setIntValue((U32)intStack[UINT]);
  1038. if(curObject)
  1039. curObject->setDataField(curField, curFieldArray, STR.getStringValue());
  1040. else
  1041. {
  1042. // The field is not being set on an object. Maybe it's
  1043. // a special accessor?
  1044. setFieldComponent( prevObject, prevField, prevFieldArray, curField );
  1045. prevObject = NULL;
  1046. }
  1047. break;
  1048. case OP_SAVEFIELD_FLT:
  1049. STR.setFloatValue(floatStack[FLT]);
  1050. if(curObject)
  1051. curObject->setDataField(curField, curFieldArray, STR.getStringValue());
  1052. else
  1053. {
  1054. // The field is not being set on an object. Maybe it's
  1055. // a special accessor?
  1056. setFieldComponent( prevObject, prevField, prevFieldArray, curField );
  1057. prevObject = NULL;
  1058. }
  1059. break;
  1060. case OP_SAVEFIELD_STR:
  1061. if(curObject)
  1062. curObject->setDataField(curField, curFieldArray, STR.getStringValue());
  1063. else
  1064. {
  1065. // The field is not being set on an object. Maybe it's
  1066. // a special accessor?
  1067. setFieldComponent( prevObject, prevField, prevFieldArray, curField );
  1068. prevObject = NULL;
  1069. }
  1070. break;
  1071. case OP_STR_TO_UINT:
  1072. intStack[UINT+1] = STR.getIntValue();
  1073. UINT++;
  1074. break;
  1075. case OP_STR_TO_FLT:
  1076. floatStack[FLT+1] = STR.getFloatValue();
  1077. FLT++;
  1078. break;
  1079. case OP_STR_TO_NONE:
  1080. // This exists simply to deal with certain typecast situations.
  1081. break;
  1082. case OP_FLT_TO_UINT:
  1083. intStack[UINT+1] = (S64)floatStack[FLT];
  1084. FLT--;
  1085. UINT++;
  1086. break;
  1087. case OP_FLT_TO_STR:
  1088. STR.setFloatValue(floatStack[FLT]);
  1089. FLT--;
  1090. break;
  1091. case OP_FLT_TO_NONE:
  1092. FLT--;
  1093. break;
  1094. case OP_UINT_TO_FLT:
  1095. floatStack[FLT+1] = (F64)intStack[UINT];
  1096. UINT--;
  1097. FLT++;
  1098. break;
  1099. case OP_UINT_TO_STR:
  1100. STR.setIntValue((U32)intStack[UINT]);
  1101. UINT--;
  1102. break;
  1103. case OP_UINT_TO_NONE:
  1104. UINT--;
  1105. break;
  1106. case OP_LOADIMMED_UINT:
  1107. intStack[UINT+1] = code[ip++];
  1108. UINT++;
  1109. break;
  1110. case OP_LOADIMMED_FLT:
  1111. floatStack[FLT+1] = curFloatTable[code[ip]];
  1112. ip++;
  1113. FLT++;
  1114. break;
  1115. case OP_TAG_TO_STR:
  1116. code[ip-1] = OP_LOADIMMED_STR;
  1117. // it's possible the string has already been converted
  1118. if(U8(curStringTable[code[ip]]) != StringTagPrefixByte)
  1119. {
  1120. U32 id = GameAddTaggedString(curStringTable + code[ip]);
  1121. dSprintf(curStringTable + code[ip] + 1, 7, "%d", id);
  1122. *(curStringTable + code[ip]) = StringTagPrefixByte;
  1123. }
  1124. case OP_LOADIMMED_STR:
  1125. STR.setStringValue(curStringTable + code[ip++]);
  1126. break;
  1127. case OP_DOCBLOCK_STR:
  1128. {
  1129. // If the first word of the doc is '\class' or '@class', then this
  1130. // is a namespace doc block, otherwise it is a function doc block.
  1131. const char* docblock = curStringTable + code[ip++];
  1132. const char* sansClass = dStrstr( docblock, "@class" );
  1133. if( !sansClass )
  1134. sansClass = dStrstr( docblock, "\\class" );
  1135. if( sansClass )
  1136. {
  1137. // Don't save the class declaration. Scan past the 'class'
  1138. // keyword and up to the first whitespace.
  1139. sansClass += 7;
  1140. S32 index = 0;
  1141. while( ( *sansClass != ' ' ) && ( *sansClass != '\n' ) && *sansClass && ( index < ( nsDocLength - 1 ) ) )
  1142. {
  1143. nsDocBlockClass[index++] = *sansClass;
  1144. sansClass++;
  1145. }
  1146. nsDocBlockClass[index] = '\0';
  1147. curNSDocBlock = sansClass + 1;
  1148. }
  1149. else
  1150. curFNDocBlock = docblock;
  1151. }
  1152. break;
  1153. case OP_LOADIMMED_IDENT:
  1154. STR.setStringValue(U32toSTE(code[ip++]));
  1155. break;
  1156. case OP_CALLFUNC_RESOLVE:
  1157. // This deals with a function that is potentially living in a namespace.
  1158. fnNamespace = U32toSTE(code[ip+1]);
  1159. fnName = U32toSTE(code[ip]);
  1160. // Try to look it up.
  1161. ns = Namespace::find(fnNamespace);
  1162. nsEntry = ns->lookup(fnName);
  1163. if(!nsEntry)
  1164. {
  1165. ip+= 3;
  1166. Con::warnf(ConsoleLogEntry::General,
  1167. "%s: Unable to find function %s%s%s",
  1168. getFileLine(ip-4), fnNamespace ? fnNamespace : "",
  1169. fnNamespace ? "::" : "", fnName);
  1170. STR.popFrame();
  1171. break;
  1172. }
  1173. // Now, rewrite our code a bit (ie, avoid future lookups) and fall
  1174. // through to OP_CALLFUNC
  1175. code[ip+1] = *((U32 *) &nsEntry);
  1176. code[ip-1] = OP_CALLFUNC;
  1177. case OP_CALLFUNC:
  1178. {
  1179. // This routingId is set when we query the object as to whether
  1180. // it handles this method. It is set to an enum from the table
  1181. // above indicating whether it handles it on a component it owns
  1182. // or just on the object.
  1183. S32 routingId = 0;
  1184. fnName = U32toSTE(code[ip]);
  1185. //if this is called from inside a function, append the ip and codeptr
  1186. if (!gEvalState.stack.empty())
  1187. {
  1188. gEvalState.stack.last()->code = this;
  1189. gEvalState.stack.last()->ip = ip - 1;
  1190. }
  1191. U32 callType = code[ip+2];
  1192. ip += 3;
  1193. STR.getArgcArgv(fnName, &callArgc, &callArgv);
  1194. if(callType == FuncCallExprNode::FunctionCall)
  1195. {
  1196. nsEntry = *((Namespace::Entry **) &code[ip-2]);
  1197. ns = NULL;
  1198. }
  1199. else if(callType == FuncCallExprNode::MethodCall)
  1200. {
  1201. saveObject = gEvalState.thisObject;
  1202. gEvalState.thisObject = Sim::findObject(callArgv[1]);
  1203. if(!gEvalState.thisObject)
  1204. {
  1205. gEvalState.thisObject = 0;
  1206. Con::warnf(ConsoleLogEntry::General,"%s: Unable to find object: '%s' attempting to call function '%s'", getFileLine(ip-4), callArgv[1], fnName);
  1207. STR.popFrame(); // [neo, 5/7/2007 - #2974]
  1208. break;
  1209. }
  1210. bool handlesMethod = gEvalState.thisObject->handlesConsoleMethod(fnName,&routingId);
  1211. if( handlesMethod && routingId == MethodOnComponent )
  1212. {
  1213. DynamicConsoleMethodComponent *pComponent = dynamic_cast<DynamicConsoleMethodComponent*>( gEvalState.thisObject );
  1214. if( pComponent )
  1215. pComponent->callMethodArgList( callArgc, callArgv, false );
  1216. }
  1217. ns = gEvalState.thisObject->getNamespace();
  1218. if(ns)
  1219. nsEntry = ns->lookup(fnName);
  1220. else
  1221. nsEntry = NULL;
  1222. }
  1223. else // it's a ParentCall
  1224. {
  1225. if(thisNamespace)
  1226. {
  1227. ns = thisNamespace->mParent;
  1228. if(ns)
  1229. nsEntry = ns->lookup(fnName);
  1230. else
  1231. nsEntry = NULL;
  1232. }
  1233. else
  1234. {
  1235. ns = NULL;
  1236. nsEntry = NULL;
  1237. }
  1238. }
  1239. S32 nsType = -1;
  1240. S32 nsMinArgs = 0;
  1241. S32 nsMaxArgs = 0;
  1242. Namespace::Entry::CallbackUnion * nsCb = NULL;
  1243. //Namespace::Entry::CallbackUnion cbu;
  1244. const char * nsUsage = NULL;
  1245. if (nsEntry)
  1246. {
  1247. nsType = nsEntry->mType;
  1248. nsMinArgs = nsEntry->mMinArgs;
  1249. nsMaxArgs = nsEntry->mMaxArgs;
  1250. nsCb = &nsEntry->cb;
  1251. nsUsage = nsEntry->mUsage;
  1252. routingId = 0;
  1253. }
  1254. if(!nsEntry || noCalls)
  1255. {
  1256. if(!noCalls && !( routingId == MethodOnComponent ) )
  1257. {
  1258. Con::warnf(ConsoleLogEntry::General,"%s: Unknown command %s.", getFileLine(ip-4), fnName);
  1259. if(callType == FuncCallExprNode::MethodCall)
  1260. {
  1261. Con::warnf(ConsoleLogEntry::General, " Object %s(%d) %s",
  1262. gEvalState.thisObject->getName() ? gEvalState.thisObject->getName() : "",
  1263. gEvalState.thisObject->getId(), getNamespaceList(ns) );
  1264. }
  1265. }
  1266. STR.popFrame();
  1267. STR.setStringValue("");
  1268. break;
  1269. }
  1270. if(nsEntry->mType == Namespace::Entry::ScriptFunctionType)
  1271. {
  1272. const char *ret = "";
  1273. if(nsEntry->mFunctionOffset)
  1274. ret = nsEntry->mCode->exec(nsEntry->mFunctionOffset, fnName, nsEntry->mNamespace, callArgc, callArgv, false, nsEntry->mPackage);
  1275. STR.popFrame();
  1276. STR.setStringValue(ret);
  1277. }
  1278. else
  1279. {
  1280. const char* nsName = ns? ns->mName: "";
  1281. if((nsEntry->mMinArgs && S32(callArgc) < nsEntry->mMinArgs) || (nsEntry->mMaxArgs && S32(callArgc) > nsEntry->mMaxArgs))
  1282. {
  1283. Con::warnf(ConsoleLogEntry::Script, "%s: %s::%s - wrong number of arguments.", getFileLine(ip-4), nsName, fnName);
  1284. Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", getFileLine(ip-4), nsEntry->mUsage);
  1285. STR.popFrame();
  1286. }
  1287. else
  1288. {
  1289. switch(nsEntry->mType)
  1290. {
  1291. case Namespace::Entry::StringCallbackType:
  1292. {
  1293. const char *ret = nsEntry->cb.mStringCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
  1294. STR.popFrame();
  1295. if(ret != STR.getStringValue())
  1296. STR.setStringValue(ret);
  1297. else
  1298. STR.setLen(dStrlen(ret));
  1299. break;
  1300. }
  1301. case Namespace::Entry::IntCallbackType:
  1302. {
  1303. S32 result = nsEntry->cb.mIntCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
  1304. STR.popFrame();
  1305. if(code[ip] == OP_STR_TO_UINT)
  1306. {
  1307. ip++;
  1308. intStack[++UINT] = result;
  1309. break;
  1310. }
  1311. else if(code[ip] == OP_STR_TO_FLT)
  1312. {
  1313. ip++;
  1314. floatStack[++FLT] = result;
  1315. break;
  1316. }
  1317. else if(code[ip] == OP_STR_TO_NONE)
  1318. ip++;
  1319. else
  1320. STR.setIntValue(result);
  1321. break;
  1322. }
  1323. case Namespace::Entry::FloatCallbackType:
  1324. {
  1325. F64 result = nsEntry->cb.mFloatCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
  1326. STR.popFrame();
  1327. if(code[ip] == OP_STR_TO_UINT)
  1328. {
  1329. ip++;
  1330. intStack[++UINT] = (S64)result;
  1331. break;
  1332. }
  1333. else if(code[ip] == OP_STR_TO_FLT)
  1334. {
  1335. ip++;
  1336. floatStack[++FLT] = result;
  1337. break;
  1338. }
  1339. else if(code[ip] == OP_STR_TO_NONE)
  1340. ip++;
  1341. else
  1342. STR.setFloatValue(result);
  1343. break;
  1344. }
  1345. case Namespace::Entry::VoidCallbackType:
  1346. nsEntry->cb.mVoidCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
  1347. if(code[ip] != OP_STR_TO_NONE)
  1348. Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", getFileLine(ip-4), fnName, functionName);
  1349. STR.popFrame();
  1350. STR.setStringValue("");
  1351. break;
  1352. case Namespace::Entry::BoolCallbackType:
  1353. {
  1354. bool result = nsEntry->cb.mBoolCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
  1355. STR.popFrame();
  1356. if(code[ip] == OP_STR_TO_UINT)
  1357. {
  1358. ip++;
  1359. intStack[++UINT] = result;
  1360. break;
  1361. }
  1362. else if(code[ip] == OP_STR_TO_FLT)
  1363. {
  1364. ip++;
  1365. floatStack[++FLT] = result;
  1366. break;
  1367. }
  1368. else if(code[ip] == OP_STR_TO_NONE)
  1369. ip++;
  1370. else
  1371. STR.setIntValue(result);
  1372. break;
  1373. }
  1374. }
  1375. }
  1376. }
  1377. if(callType == FuncCallExprNode::MethodCall)
  1378. gEvalState.thisObject = saveObject;
  1379. break;
  1380. }
  1381. case OP_ADVANCE_STR:
  1382. STR.advance();
  1383. break;
  1384. case OP_ADVANCE_STR_APPENDCHAR:
  1385. STR.advanceChar(code[ip++]);
  1386. break;
  1387. case OP_ADVANCE_STR_COMMA:
  1388. STR.advanceChar('_');
  1389. break;
  1390. case OP_ADVANCE_STR_NUL:
  1391. STR.advanceChar(0);
  1392. break;
  1393. case OP_REWIND_STR:
  1394. STR.rewind();
  1395. break;
  1396. case OP_TERMINATE_REWIND_STR:
  1397. STR.rewindTerminate();
  1398. break;
  1399. case OP_COMPARE_STR:
  1400. intStack[++UINT] = STR.compare();
  1401. break;
  1402. case OP_PUSH:
  1403. STR.push();
  1404. break;
  1405. case OP_PUSH_FRAME:
  1406. STR.pushFrame();
  1407. break;
  1408. case OP_BREAK:
  1409. {
  1410. //append the ip and codeptr before managing the breakpoint!
  1411. AssertFatal( !gEvalState.stack.empty(), "Empty eval stack on break!");
  1412. gEvalState.stack.last()->code = this;
  1413. gEvalState.stack.last()->ip = ip - 1;
  1414. U32 breakLine;
  1415. findBreakLine(ip-1, breakLine, instruction);
  1416. if(!breakLine)
  1417. goto breakContinue;
  1418. TelDebugger->executionStopped(this, breakLine);
  1419. // Notify the remote debugger.
  1420. if ( pRemoteDebugger != NULL )
  1421. pRemoteDebugger->executionStopped(this, breakLine);
  1422. goto breakContinue;
  1423. }
  1424. case OP_INVALID:
  1425. default:
  1426. // error!
  1427. goto execFinished;
  1428. }
  1429. }
  1430. execFinished:
  1431. if ( telDebuggerOn && setFrame < 0 )
  1432. TelDebugger->popStackFrame();
  1433. // Notify the remote debugger.
  1434. if ( pRemoteDebugger != NULL && setFrame < 0 )
  1435. pRemoteDebugger->popStackFrame();
  1436. if ( popFrame )
  1437. gEvalState.popFrame();
  1438. if(argv)
  1439. {
  1440. if(gEvalState.traceOn)
  1441. {
  1442. traceBuffer[0] = 0;
  1443. dStrcat(traceBuffer, "Leaving ");
  1444. if(packageName)
  1445. {
  1446. dStrcat(traceBuffer, "[");
  1447. dStrcat(traceBuffer, packageName);
  1448. dStrcat(traceBuffer, "]");
  1449. }
  1450. if(thisNamespace && thisNamespace->mName)
  1451. {
  1452. dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
  1453. "%s::%s() - return %s", thisNamespace->mName, thisFunctionName, STR.getStringValue());
  1454. }
  1455. else
  1456. {
  1457. dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
  1458. "%s() - return %s", thisFunctionName, STR.getStringValue());
  1459. }
  1460. Con::printf("%s", traceBuffer);
  1461. }
  1462. }
  1463. else
  1464. {
  1465. delete[] const_cast<char*>(globalStrings);
  1466. delete[] globalFloats;
  1467. globalStrings = NULL;
  1468. globalFloats = NULL;
  1469. }
  1470. smCurrentCodeBlock = saveCodeBlock;
  1471. if(saveCodeBlock && saveCodeBlock->name)
  1472. {
  1473. Con::gCurrentFile = saveCodeBlock->name;
  1474. Con::gCurrentRoot = saveCodeBlock->mRoot;
  1475. }
  1476. decRefCount();
  1477. #ifdef TORQUE_DEBUG
  1478. AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec");
  1479. AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec");
  1480. #endif
  1481. return STR.getStringValue();
  1482. }
  1483. //------------------------------------------------------------