compiledEval.cpp 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. // Copyright (c) 2015 Faust Logic, Inc.
  4. // Copyright (c) 2021 TGEMIT Authors & Contributors
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to
  8. // deal in the Software without restriction, including without limitation the
  9. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10. // sell copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  22. // IN THE SOFTWARE.
  23. //-----------------------------------------------------------------------------
  24. #include "platform/platform.h"
  25. #include "console/console.h"
  26. #include "console/ast.h"
  27. #include "core/tAlgorithm.h"
  28. #include "core/strings/findMatch.h"
  29. #include "core/strings/stringUnit.h"
  30. #include "console/consoleInternal.h"
  31. #include "core/stream/fileStream.h"
  32. #include "console/compiler.h"
  33. #include "console/simBase.h"
  34. #include "console/telnetDebugger.h"
  35. #include "sim/netStringTable.h"
  36. #include "console/ICallMethod.h"
  37. #include "console/stringStack.h"
  38. #include "util/messaging/message.h"
  39. #include "core/frameAllocator.h"
  40. #include "console/returnBuffer.h"
  41. #include "console/consoleValueStack.h"
  42. #ifndef TORQUE_TGB_ONLY
  43. #include "materials/materialDefinition.h"
  44. #include "materials/materialManager.h"
  45. #endif
  46. using namespace Compiler;
  47. enum EvalConstants
  48. {
  49. MaxStackSize = 1024,
  50. FieldBufferSizeString = 2048,
  51. FieldBufferSizeNumeric = 128,
  52. ConcatBufferInitialSize = 8192,
  53. MethodOnComponent = -2
  54. };
  55. /// Frame data for a foreach/foreach$ loop.
  56. struct IterStackRecord
  57. {
  58. /// If true, this is a foreach$ loop; if not, it's a foreach loop.
  59. bool mIsStringIter;
  60. /// True if the variable referenced is a global
  61. bool mIsGlobalVariable;
  62. union
  63. {
  64. /// The iterator variable if we are a global variable
  65. Dictionary::Entry* mVariable;
  66. /// The register variable if we are a local variable
  67. S32 mRegister;
  68. } mVar;
  69. /// Information for an object iterator loop.
  70. struct ObjectPos
  71. {
  72. /// The set being iterated over.
  73. SimSet* mSet;
  74. /// Current index in the set.
  75. U32 mIndex;
  76. };
  77. /// Information for a string iterator loop.
  78. struct StringPos
  79. {
  80. /// The raw string data on the string stack.
  81. const char* mString;
  82. /// Current parsing position.
  83. U32 mIndex;
  84. };
  85. union
  86. {
  87. ObjectPos mObj;
  88. StringPos mStr;
  89. } mData;
  90. };
  91. ConsoleValueStack<4096> gCallStack;
  92. StringStack STR;
  93. IterStackRecord iterStack[MaxStackSize];
  94. U32 _ITER = 0; ///< Stack pointer for iterStack.
  95. ConsoleValue stack[MaxStackSize];
  96. S32 _STK = 0;
  97. char curFieldArray[256];
  98. char prevFieldArray[256];
  99. const char* tsconcat(const char* strA, const char* strB, S32& outputLen)
  100. {
  101. S32 lenA = dStrlen(strA);
  102. S32 lenB = dStrlen(strB);
  103. S32 len = lenA + lenB + 1;
  104. char* concatBuffer = (char*)dMalloc(len);
  105. concatBuffer[len - 1] = '\0';
  106. memcpy(concatBuffer, strA, lenA);
  107. memcpy(concatBuffer + lenA, strB, lenB);
  108. outputLen = lenA + lenB;
  109. return concatBuffer;
  110. }
  111. namespace Con
  112. {
  113. // Current script file name and root, these are registered as
  114. // console variables.
  115. extern StringTableEntry gCurrentFile;
  116. extern StringTableEntry gCurrentRoot;
  117. }
  118. namespace Con
  119. {
  120. const char *getNamespaceList(Namespace *ns)
  121. {
  122. U32 size = 1;
  123. Namespace * walk;
  124. for (walk = ns; walk; walk = walk->mParent)
  125. size += dStrlen(walk->mName) + 4;
  126. char *ret = Con::getReturnBuffer(size);
  127. ret[0] = 0;
  128. for (walk = ns; walk; walk = walk->mParent)
  129. {
  130. dStrcat(ret, walk->mName, size);
  131. if (walk->mParent)
  132. dStrcat(ret, " -> ", size);
  133. }
  134. return ret;
  135. }
  136. }
  137. // Gets a component of an object's field value or a variable and returns it
  138. // in val.
  139. static void getFieldComponent(SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField, char val[])
  140. {
  141. const char* prevVal = NULL;
  142. // Grab value from object.
  143. if (object && field)
  144. prevVal = object->getDataField(field, array);
  145. // Otherwise, grab from the string stack. The value coming in will always
  146. // be a string because that is how multicomponent variables are handled.
  147. else
  148. prevVal = stack[_STK].getString();
  149. // Make sure we got a value.
  150. if (prevVal && *prevVal)
  151. {
  152. static const StringTableEntry xyzw[] =
  153. {
  154. StringTable->insert("x"),
  155. StringTable->insert("y"),
  156. StringTable->insert("z"),
  157. StringTable->insert("w")
  158. };
  159. static const StringTableEntry rgba[] =
  160. {
  161. StringTable->insert("r"),
  162. StringTable->insert("g"),
  163. StringTable->insert("b"),
  164. StringTable->insert("a")
  165. };
  166. // Translate xyzw and rgba into the indexed component
  167. // of the variable or field.
  168. if (subField == xyzw[0] || subField == rgba[0])
  169. dStrcpy(val, StringUnit::getUnit(prevVal, 0, " \t\n"), 128);
  170. else if (subField == xyzw[1] || subField == rgba[1])
  171. dStrcpy(val, StringUnit::getUnit(prevVal, 1, " \t\n"), 128);
  172. else if (subField == xyzw[2] || subField == rgba[2])
  173. dStrcpy(val, StringUnit::getUnit(prevVal, 2, " \t\n"), 128);
  174. else if (subField == xyzw[3] || subField == rgba[3])
  175. dStrcpy(val, StringUnit::getUnit(prevVal, 3, " \t\n"), 128);
  176. else
  177. val[0] = 0;
  178. }
  179. else
  180. val[0] = 0;
  181. }
  182. // Sets a component of an object's field value based on the sub field. 'x' will
  183. // set the first field, 'y' the second, and 'z' the third.
  184. static void setFieldComponent(SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField)
  185. {
  186. // Copy the current string value
  187. char strValue[1024];
  188. dStrncpy(strValue, stack[_STK].getString(), 1024);
  189. char val[1024] = "";
  190. const char* prevVal = NULL;
  191. // Set the value on an object field.
  192. if (object && field)
  193. prevVal = object->getDataField(field, array);
  194. // Set the value on a variable.
  195. else if (gEvalState.currentVariable)
  196. prevVal = gEvalState.getStringVariable();
  197. // Ensure that the variable has a value
  198. if (!prevVal)
  199. return;
  200. static const StringTableEntry xyzw[] =
  201. {
  202. StringTable->insert("x"),
  203. StringTable->insert("y"),
  204. StringTable->insert("z"),
  205. StringTable->insert("w")
  206. };
  207. static const StringTableEntry rgba[] =
  208. {
  209. StringTable->insert("r"),
  210. StringTable->insert("g"),
  211. StringTable->insert("b"),
  212. StringTable->insert("a")
  213. };
  214. // Insert the value into the specified
  215. // component of the string.
  216. if (subField == xyzw[0] || subField == rgba[0])
  217. dStrcpy(val, StringUnit::setUnit(prevVal, 0, strValue, " \t\n"), 128);
  218. else if (subField == xyzw[1] || subField == rgba[1])
  219. dStrcpy(val, StringUnit::setUnit(prevVal, 1, strValue, " \t\n"), 128);
  220. else if (subField == xyzw[2] || subField == rgba[2])
  221. dStrcpy(val, StringUnit::setUnit(prevVal, 2, strValue, " \t\n"), 128);
  222. else if (subField == xyzw[3] || subField == rgba[3])
  223. dStrcpy(val, StringUnit::setUnit(prevVal, 3, strValue, " \t\n"), 128);
  224. if (val[0] != 0)
  225. {
  226. // Update the field or variable.
  227. if (object && field)
  228. object->setDataField(field, 0, val);
  229. else if (gEvalState.currentVariable)
  230. gEvalState.setStringVariable(val);
  231. }
  232. }
  233. //------------------------------------------------------------
  234. F64 consoleStringToNumber(const char *str, StringTableEntry file, U32 line)
  235. {
  236. F64 val = dAtof(str);
  237. if (val != 0)
  238. return val;
  239. else if (!dStricmp(str, "true"))
  240. return 1;
  241. else if (!dStricmp(str, "false"))
  242. return 0;
  243. else if (file)
  244. {
  245. Con::warnf(ConsoleLogEntry::General, "%s (%d): string always evaluates to 0.", file, line);
  246. return 0;
  247. }
  248. return 0;
  249. }
  250. //------------------------------------------------------------
  251. namespace Con
  252. {
  253. ReturnBuffer retBuffer;
  254. char *getReturnBuffer(U32 bufferSize)
  255. {
  256. return retBuffer.getBuffer(bufferSize);
  257. }
  258. char *getReturnBuffer(const char *stringToCopy)
  259. {
  260. U32 len = dStrlen(stringToCopy) + 1;
  261. char *ret = retBuffer.getBuffer(len);
  262. dMemcpy(ret, stringToCopy, len);
  263. return ret;
  264. }
  265. char* getReturnBuffer(const String& str)
  266. {
  267. const U32 size = str.size();
  268. char* ret = retBuffer.getBuffer(size);
  269. dMemcpy(ret, str.c_str(), size);
  270. return ret;
  271. }
  272. char* getReturnBuffer(const StringBuilder& str)
  273. {
  274. char* buffer = Con::getReturnBuffer(str.length() + 1);
  275. str.copy(buffer);
  276. buffer[str.length()] = '\0';
  277. return buffer;
  278. }
  279. char *getArgBuffer(U32 bufferSize)
  280. {
  281. return STR.getArgBuffer(bufferSize);
  282. }
  283. char *getFloatArg(F64 arg)
  284. {
  285. char *ret = STR.getArgBuffer(32);
  286. dSprintf(ret, 32, "%g", arg);
  287. return ret;
  288. }
  289. char *getIntArg(S32 arg)
  290. {
  291. char *ret = STR.getArgBuffer(32);
  292. dSprintf(ret, 32, "%d", arg);
  293. return ret;
  294. }
  295. char* getBoolArg(bool arg)
  296. {
  297. char *ret = STR.getArgBuffer(32);
  298. dSprintf(ret, 32, "%d", arg);
  299. return ret;
  300. }
  301. char *getStringArg(const char *arg)
  302. {
  303. U32 len = dStrlen(arg) + 1;
  304. char *ret = STR.getArgBuffer(len);
  305. dMemcpy(ret, arg, len);
  306. return ret;
  307. }
  308. char* getStringArg(const String& arg)
  309. {
  310. const U32 size = arg.size();
  311. char* ret = STR.getArgBuffer(size);
  312. dMemcpy(ret, arg.c_str(), size);
  313. return ret;
  314. }
  315. }
  316. //------------------------------------------------------------
  317. void ExprEvalState::setCurVarName(StringTableEntry name)
  318. {
  319. if (name[0] == '$')
  320. currentVariable = globalVars.lookup(name);
  321. else if (getStackDepth() > 0)
  322. currentVariable = getCurrentFrame().lookup(name);
  323. if (!currentVariable && gWarnUndefinedScriptVariables)
  324. Con::warnf(ConsoleLogEntry::Script, "Variable referenced before assignment: %s", name);
  325. }
  326. void ExprEvalState::setCurVarNameCreate(StringTableEntry name)
  327. {
  328. if (name[0] == '$')
  329. currentVariable = globalVars.add(name);
  330. else if (getStackDepth() > 0)
  331. currentVariable = getCurrentFrame().add(name);
  332. else
  333. {
  334. currentVariable = NULL;
  335. Con::warnf(ConsoleLogEntry::Script, "Accessing local variable in global scope... failed: %s", name);
  336. }
  337. }
  338. //------------------------------------------------------------
  339. S32 ExprEvalState::getIntVariable()
  340. {
  341. return currentVariable ? currentVariable->getIntValue() : 0;
  342. }
  343. F64 ExprEvalState::getFloatVariable()
  344. {
  345. return currentVariable ? currentVariable->getFloatValue() : 0;
  346. }
  347. const char *ExprEvalState::getStringVariable()
  348. {
  349. return currentVariable ? currentVariable->getStringValue() : "";
  350. }
  351. //------------------------------------------------------------
  352. void ExprEvalState::setIntVariable(S32 val)
  353. {
  354. AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!");
  355. currentVariable->setIntValue(val);
  356. }
  357. void ExprEvalState::setFloatVariable(F64 val)
  358. {
  359. AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!");
  360. currentVariable->setFloatValue(val);
  361. }
  362. void ExprEvalState::setStringVariable(const char *val)
  363. {
  364. AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!");
  365. currentVariable->setStringValue(val);
  366. }
  367. //-----------------------------------------------------------------------------
  368. U32 gExecCount = 0;
  369. ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNamespace, U32 argc, ConsoleValue* argv, bool noCalls, StringTableEntry packageName, S32 setFrame)
  370. {
  371. #ifdef TORQUE_DEBUG
  372. U32 stackStart = _STK;
  373. gExecCount++;
  374. #endif
  375. const dsize_t TRACE_BUFFER_SIZE = 1024;
  376. static char traceBuffer[TRACE_BUFFER_SIZE];
  377. U32 i;
  378. U32 iterDepth = 0;
  379. ConsoleValue returnValue;
  380. incRefCount();
  381. F64* curFloatTable;
  382. char* curStringTable;
  383. S32 curStringTableLen = 0; //clint to ensure we dont overwrite it
  384. StringTableEntry thisFunctionName = NULL;
  385. bool popFrame = false;
  386. if (argv)
  387. {
  388. // assume this points into a function decl:
  389. U32 fnArgc = code[ip + 2 + 6];
  390. U32 regCount = code[ip + 2 + 7];
  391. thisFunctionName = CodeToSTE(code, ip);
  392. S32 wantedArgc = getMin(argc - 1, fnArgc); // argv[0] is func name
  393. if (gEvalState.traceOn)
  394. {
  395. traceBuffer[0] = 0;
  396. dStrcat(traceBuffer, "Entering ", TRACE_BUFFER_SIZE);
  397. if (packageName)
  398. {
  399. dStrcat(traceBuffer, "[", TRACE_BUFFER_SIZE);
  400. dStrcat(traceBuffer, packageName, TRACE_BUFFER_SIZE);
  401. dStrcat(traceBuffer, "]", TRACE_BUFFER_SIZE);
  402. }
  403. if (thisNamespace && thisNamespace->mName)
  404. {
  405. dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
  406. "%s::%s(", thisNamespace->mName, thisFunctionName);
  407. }
  408. else
  409. {
  410. dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
  411. "%s(", thisFunctionName);
  412. }
  413. for (i = 0; i < wantedArgc; i++)
  414. {
  415. dStrcat(traceBuffer, argv[i + 1].getString(), TRACE_BUFFER_SIZE);
  416. if (i != wantedArgc - 1)
  417. dStrcat(traceBuffer, ", ", TRACE_BUFFER_SIZE);
  418. }
  419. dStrcat(traceBuffer, ")", TRACE_BUFFER_SIZE);
  420. Con::printf("%s", traceBuffer);
  421. }
  422. gEvalState.pushFrame(thisFunctionName, thisNamespace, regCount);
  423. popFrame = true;
  424. for (i = 0; i < wantedArgc; i++)
  425. {
  426. S32 reg = code[ip + (2 + 6 + 1 + 1) + i];
  427. ConsoleValue& value = argv[i + 1];
  428. gEvalState.moveConsoleValue(reg, std::move(value));
  429. }
  430. ip = ip + fnArgc + (2 + 6 + 1 + 1);
  431. curFloatTable = functionFloats;
  432. curStringTable = functionStrings;
  433. curStringTableLen = functionStringsMaxLen;
  434. }
  435. else
  436. {
  437. curFloatTable = globalFloats;
  438. curStringTable = globalStrings;
  439. curStringTableLen = globalStringsMaxLen;
  440. // If requested stack frame isn't available, request a new one
  441. // (this prevents assert failures when creating local
  442. // variables without a stack frame)
  443. if (gEvalState.getStackDepth() <= setFrame)
  444. setFrame = -1;
  445. // Do we want this code to execute using a new stack frame?
  446. if (setFrame < 0)
  447. {
  448. gEvalState.pushFrame(NULL, NULL, 0);
  449. gCallStack.pushFrame(0);
  450. popFrame = true;
  451. }
  452. else
  453. {
  454. // We want to copy a reference to an existing stack frame
  455. // on to the top of the stack. Any change that occurs to
  456. // the locals during this new frame will also occur in the
  457. // original frame.
  458. S32 stackIndex = gEvalState.getTopOfStack() - setFrame - 1;
  459. gEvalState.pushFrameRef(stackIndex);
  460. popFrame = true;
  461. }
  462. }
  463. // Grab the state of the telenet debugger here once
  464. // so that the push and pop frames are always balanced.
  465. const bool telDebuggerOn = TelDebugger && TelDebugger->isConnected();
  466. if (telDebuggerOn && setFrame < 0)
  467. TelDebugger->pushStackFrame();
  468. StringTableEntry var, objParent;
  469. U32 failJump;
  470. StringTableEntry fnName;
  471. StringTableEntry fnNamespace, fnPackage;
  472. static const U32 objectCreationStackSize = 32;
  473. U32 objectCreationStackIndex = 0;
  474. struct {
  475. SimObject* newObject;
  476. U32 failJump;
  477. } objectCreationStack[objectCreationStackSize];
  478. SimObject* currentNewObject = 0;
  479. StringTableEntry prevField = NULL;
  480. StringTableEntry curField = NULL;
  481. SimObject* prevObject = NULL;
  482. SimObject* curObject = NULL;
  483. SimObject* saveObject = NULL;
  484. Namespace::Entry* nsEntry;
  485. Namespace* ns;
  486. const char* curFNDocBlock = NULL;
  487. const char* curNSDocBlock = NULL;
  488. const S32 nsDocLength = 128;
  489. char nsDocBlockClass[nsDocLength];
  490. S32 callArgc;
  491. ConsoleValue* callArgv;
  492. static char curFieldArray[256];
  493. static char prevFieldArray[256];
  494. CodeBlock* saveCodeBlock = smCurrentCodeBlock;
  495. smCurrentCodeBlock = this;
  496. if (this->name)
  497. {
  498. Con::gCurrentFile = this->name;
  499. Con::gCurrentRoot = this->modPath;
  500. }
  501. const char* val;
  502. S32 reg;
  503. // The frame temp is used by the variable accessor ops (OP_SAVEFIELD_* and
  504. // OP_LOADFIELD_*) to store temporary values for the fields.
  505. static S32 VAL_BUFFER_SIZE = 1024;
  506. FrameTemp<char> valBuffer(VAL_BUFFER_SIZE);
  507. for (;;)
  508. {
  509. U32 instruction = code[ip++];
  510. breakContinue:
  511. switch (instruction)
  512. {
  513. case OP_FUNC_DECL:
  514. if (!noCalls)
  515. {
  516. fnName = CodeToSTE(code, ip);
  517. fnNamespace = CodeToSTE(code, ip + 2);
  518. fnPackage = CodeToSTE(code, ip + 4);
  519. bool hasBody = (code[ip + 6] & 0x01) != 0;
  520. U32 lineNumber = code[ip + 6] >> 1;
  521. Namespace::unlinkPackages();
  522. if (fnNamespace == NULL && fnPackage == NULL)
  523. ns = Namespace::global();
  524. else
  525. ns = Namespace::find(fnNamespace, fnPackage);
  526. ns->addFunction(fnName, this, hasBody ? ip : 0);// if no body, set the IP to 0
  527. if (curNSDocBlock)
  528. {
  529. if (fnNamespace == StringTable->lookup(nsDocBlockClass))
  530. {
  531. char* usageStr = dStrdup(curNSDocBlock);
  532. usageStr[dStrlen(usageStr)] = '\0';
  533. ns->mUsage = usageStr;
  534. ns->mCleanUpUsage = true;
  535. curNSDocBlock = NULL;
  536. }
  537. }
  538. Namespace::relinkPackages();
  539. // If we had a docblock, it's definitely not valid anymore, so clear it out.
  540. curFNDocBlock = NULL;
  541. //Con::printf("Adding function %s::%s (%d)", fnNamespace, fnName, ip);
  542. }
  543. ip = code[ip + 7];
  544. break;
  545. case OP_CREATE_OBJECT:
  546. {
  547. // Read some useful info.
  548. objParent = CodeToSTE(code, ip);
  549. bool isDataBlock = code[ip + 2];
  550. bool isInternal = code[ip + 3];
  551. bool isSingleton = code[ip + 4];
  552. U32 lineNumber = code[ip + 5];
  553. failJump = code[ip + 6];
  554. // If we don't allow calls, we certainly don't allow creating objects!
  555. // Moved this to after failJump is set. Engine was crashing when
  556. // noCalls = true and an object was being created at the beginning of
  557. // a file. ADL.
  558. if (noCalls)
  559. {
  560. ip = failJump;
  561. break;
  562. }
  563. // Push the old info to the stack
  564. //Assert( objectCreationStackIndex < objectCreationStackSize );
  565. objectCreationStack[objectCreationStackIndex].newObject = currentNewObject;
  566. objectCreationStack[objectCreationStackIndex++].failJump = failJump;
  567. // Get the constructor information off the stack.
  568. gCallStack.argvc(NULL, callArgc, &callArgv);
  569. AssertFatal(callArgc - 3 >= 0, avar("Call Arg needs at least 3, only has %d", callArgc));
  570. const char* objectName = callArgv[2].getString();
  571. // Con::printf("Creating object...");
  572. // objectName = argv[1]...
  573. currentNewObject = NULL;
  574. // Are we creating a datablock? If so, deal with case where we override
  575. // an old one.
  576. if (isDataBlock)
  577. {
  578. // Con::printf(" - is a datablock");
  579. // Find the old one if any.
  580. SimObject* db = Sim::getDataBlockGroup()->findObject(objectName);
  581. // Make sure we're not changing types on ourselves...
  582. if (db && dStricmp(db->getClassName(), callArgv[1].getString()))
  583. {
  584. Con::errorf(ConsoleLogEntry::General, "Cannot re-declare data block %s with a different class.", objectName);
  585. ip = failJump;
  586. gCallStack.popFrame();
  587. break;
  588. }
  589. // If there was one, set the currentNewObject and move on.
  590. if (db)
  591. currentNewObject = db;
  592. }
  593. else if (!isInternal)
  594. {
  595. AbstractClassRep* rep = AbstractClassRep::findClassRep(objectName);
  596. if (rep != NULL)
  597. {
  598. Con::errorf(ConsoleLogEntry::General, "%s: Cannot name object [%s] the same name as a script class.",
  599. getFileLine(ip), objectName);
  600. ip = failJump;
  601. gCallStack.popFrame();
  602. break;
  603. }
  604. SimObject* obj = Sim::findObject((const char*)objectName);
  605. if (obj)
  606. {
  607. if (isSingleton)
  608. {
  609. // Make sure we're not trying to change types
  610. if (dStricmp(obj->getClassName(), callArgv[1].getString()) != 0)
  611. {
  612. Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare object [%s] with a different class [%s] - was [%s].",
  613. getFileLine(ip), objectName, callArgv[1].getString(), obj->getClassName());
  614. ip = failJump;
  615. gCallStack.popFrame();
  616. break;
  617. }
  618. // We're creating a singleton, so use the found object instead of creating a new object.
  619. currentNewObject = obj;
  620. Con::warnf("%s: Singleton Object was already created with name %s. Using existing object.",
  621. getFileLine(ip), objectName);
  622. }
  623. }
  624. }
  625. gCallStack.popFrame();
  626. if (!currentNewObject)
  627. {
  628. // Well, looks like we have to create a new object.
  629. ConsoleObject* object = ConsoleObject::create(callArgv[1].getString());
  630. // Deal with failure!
  631. if (!object)
  632. {
  633. Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-conobject class %s.", getFileLine(ip - 1), callArgv[1].getString());
  634. ip = failJump;
  635. break;
  636. }
  637. // Do special datablock init if appropros
  638. if (isDataBlock)
  639. {
  640. SimDataBlock* dataBlock = dynamic_cast<SimDataBlock*>(object);
  641. if (dataBlock)
  642. {
  643. dataBlock->assignId();
  644. }
  645. else
  646. {
  647. // They tried to make a non-datablock with a datablock keyword!
  648. Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-datablock class %s.", getFileLine(ip - 1), callArgv[1].getString());
  649. // Clean up...
  650. delete object;
  651. currentNewObject = NULL;
  652. ip = failJump;
  653. break;
  654. }
  655. }
  656. // Finally, set currentNewObject to point to the new one.
  657. currentNewObject = dynamic_cast<SimObject*>(object);
  658. // Deal with the case of a non-SimObject.
  659. if (!currentNewObject)
  660. {
  661. Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-SimObject class %s.", getFileLine(ip - 1), callArgv[1].getString());
  662. delete object;
  663. ip = failJump;
  664. break;
  665. }
  666. // Set the declaration line
  667. currentNewObject->setDeclarationLine(lineNumber);
  668. // Set the file that this object was created in
  669. currentNewObject->setFilename(this->name);
  670. // Does it have a parent object? (ie, the copy constructor : syntax, not inheriance)
  671. if (*objParent)
  672. {
  673. // Find it!
  674. SimObject* parent;
  675. if (Sim::findObject(objParent, parent))
  676. {
  677. // Con::printf(" - Parent object found: %s", parent->getClassName());
  678. currentNewObject->setCopySource(parent);
  679. currentNewObject->assignFieldsFrom(parent);
  680. // copy any substitution statements
  681. SimDataBlock* parent_db = dynamic_cast<SimDataBlock*>(parent);
  682. if (parent_db)
  683. {
  684. SimDataBlock* currentNewObject_db = dynamic_cast<SimDataBlock*>(currentNewObject);
  685. if (currentNewObject_db)
  686. currentNewObject_db->copySubstitutionsFrom(parent_db);
  687. }
  688. }
  689. else
  690. {
  691. Con::errorf(ConsoleLogEntry::General, "%s: Unable to find parent object %s for %s.", getFileLine(ip - 1), objParent, callArgv[1].getString());
  692. delete object;
  693. currentNewObject = NULL;
  694. ip = failJump;
  695. break;
  696. }
  697. }
  698. // If a name was passed, assign it.
  699. if (objectName[0])
  700. {
  701. if (!isInternal)
  702. currentNewObject->assignName(objectName);
  703. else
  704. currentNewObject->setInternalName(objectName);
  705. // Set the original name
  706. currentNewObject->setOriginalName( objectName );
  707. }
  708. // Do the constructor parameters.
  709. if (!currentNewObject->processArguments(callArgc - 3, callArgv + 3))
  710. {
  711. delete currentNewObject;
  712. currentNewObject = NULL;
  713. ip = failJump;
  714. break;
  715. }
  716. // If it's not a datablock, allow people to modify bits of it.
  717. if (!isDataBlock)
  718. {
  719. currentNewObject->setModStaticFields(true);
  720. currentNewObject->setModDynamicFields(true);
  721. }
  722. }
  723. else
  724. {
  725. currentNewObject->reloadReset(); // AFX (reload-reset)
  726. // Does it have a parent object? (ie, the copy constructor : syntax, not inheriance)
  727. if (*objParent)
  728. {
  729. // Find it!
  730. SimObject* parent;
  731. if (Sim::findObject(objParent, parent))
  732. {
  733. // Con::printf(" - Parent object found: %s", parent->getClassName());
  734. // temporarily block name change
  735. SimObject::preventNameChanging = true;
  736. currentNewObject->setCopySource(parent);
  737. currentNewObject->assignFieldsFrom(parent);
  738. // restore name changing
  739. SimObject::preventNameChanging = false;
  740. // copy any substitution statements
  741. SimDataBlock* parent_db = dynamic_cast<SimDataBlock*>(parent);
  742. if (parent_db)
  743. {
  744. SimDataBlock* currentNewObject_db = dynamic_cast<SimDataBlock*>(currentNewObject);
  745. if (currentNewObject_db)
  746. currentNewObject_db->copySubstitutionsFrom(parent_db);
  747. }
  748. }
  749. else
  750. {
  751. Con::errorf(ConsoleLogEntry::General, "%d: Unable to find parent object %s for %s.", lineNumber, objParent, callArgv[1].getString());
  752. }
  753. }
  754. }
  755. // Advance the IP past the create info...
  756. ip += 7;
  757. break;
  758. }
  759. case OP_ADD_OBJECT:
  760. {
  761. // See OP_SETCURVAR for why we do this.
  762. curFNDocBlock = NULL;
  763. curNSDocBlock = NULL;
  764. // Do we place this object at the root?
  765. bool placeAtRoot = code[ip++];
  766. // Con::printf("Adding object %s", currentNewObject->getName());
  767. // Make sure it wasn't already added, then add it.
  768. if (currentNewObject == NULL)
  769. {
  770. break;
  771. }
  772. bool isMessage = dynamic_cast<Message*>(currentNewObject) != NULL;
  773. if (currentNewObject->isProperlyAdded() == false)
  774. {
  775. bool ret = false;
  776. if (isMessage)
  777. {
  778. SimObjectId id = Message::getNextMessageID();
  779. if (id != 0xffffffff)
  780. ret = currentNewObject->registerObject(id);
  781. else
  782. Con::errorf("%s: No more object IDs available for messages", getFileLine(ip));
  783. }
  784. else
  785. ret = currentNewObject->registerObject();
  786. if (!ret)
  787. {
  788. // This error is usually caused by failing to call Parent::initPersistFields in the class' initPersistFields().
  789. Con::warnf(ConsoleLogEntry::General, "%s: Register object failed for object %s of class %s.", getFileLine(ip - 2), currentNewObject->getName(), currentNewObject->getClassName());
  790. delete currentNewObject;
  791. ip = failJump;
  792. break;
  793. }
  794. }
  795. // Are we dealing with a datablock?
  796. SimDataBlock* dataBlock = dynamic_cast<SimDataBlock*>(currentNewObject);
  797. String errorStr;
  798. // If so, preload it.
  799. if (dataBlock && !dataBlock->preload(true, errorStr))
  800. {
  801. Con::errorf(ConsoleLogEntry::General, "%s: preload failed for %s: %s.", getFileLine(ip - 2),
  802. currentNewObject->getName(), errorStr.c_str());
  803. dataBlock->deleteObject();
  804. ip = failJump;
  805. break;
  806. }
  807. // What group will we be added to, if any?
  808. U32 groupAddId = (U32)stack[_STK].getInt();
  809. SimGroup* grp = NULL;
  810. SimSet* set = NULL;
  811. if (!placeAtRoot || !currentNewObject->getGroup())
  812. {
  813. if (!isMessage)
  814. {
  815. if (!placeAtRoot)
  816. {
  817. // Otherwise just add to the requested group or set.
  818. if (!Sim::findObject(groupAddId, grp))
  819. Sim::findObject(groupAddId, set);
  820. }
  821. if (placeAtRoot)
  822. {
  823. // Deal with the instantGroup if we're being put at the root or we're adding to a component.
  824. if (Con::gInstantGroup.isEmpty() || !Sim::findObject(Con::gInstantGroup, grp))
  825. grp = Sim::getRootGroup();
  826. }
  827. }
  828. // If we didn't get a group, then make sure we have a pointer to
  829. // the rootgroup.
  830. if (!grp)
  831. grp = Sim::getRootGroup();
  832. // add to the parent group
  833. grp->addObject(currentNewObject);
  834. // If for some reason the add failed, add the object to the
  835. // root group so it won't leak.
  836. if (currentNewObject->getGroup() == NULL)
  837. Sim::getRootGroup()->addObject(currentNewObject);
  838. // add to any set we might be in
  839. if (set)
  840. set->addObject(currentNewObject);
  841. }
  842. // store the new object's ID on the stack (overwriting the group/set
  843. // id, if one was given, otherwise getting pushed)
  844. S32 id = currentNewObject->getId();
  845. if (placeAtRoot)
  846. stack[_STK].setInt(id);
  847. else
  848. stack[++_STK].setInt(id);
  849. break;
  850. }
  851. case OP_END_OBJECT:
  852. {
  853. // If we're not to be placed at the root, make sure we clean up
  854. // our group reference.
  855. bool placeAtRoot = code[ip++];
  856. if (!placeAtRoot)
  857. _STK--;
  858. break;
  859. }
  860. case OP_FINISH_OBJECT:
  861. {
  862. if (currentNewObject)
  863. currentNewObject->onPostAdd();
  864. AssertFatal( objectCreationStackIndex >= 0, "Object Stack is empty." );
  865. // Restore the object info from the stack [7/9/2007 Black]
  866. currentNewObject = objectCreationStack[--objectCreationStackIndex].newObject;
  867. failJump = objectCreationStack[objectCreationStackIndex].failJump;
  868. break;
  869. }
  870. case OP_JMPIFFNOT:
  871. if (stack[_STK--].getFloat())
  872. {
  873. ip++;
  874. break;
  875. }
  876. ip = code[ip];
  877. break;
  878. case OP_JMPIFNOT:
  879. if (stack[_STK--].getInt())
  880. {
  881. ip++;
  882. break;
  883. }
  884. ip = code[ip];
  885. break;
  886. case OP_JMPIFF:
  887. if (!stack[_STK--].getFloat())
  888. {
  889. ip++;
  890. break;
  891. }
  892. ip = code[ip];
  893. break;
  894. case OP_JMPIF:
  895. if (!stack[_STK--].getFloat())
  896. {
  897. ip++;
  898. break;
  899. }
  900. ip = code[ip];
  901. break;
  902. case OP_JMPIFNOT_NP:
  903. if (stack[_STK].getInt())
  904. {
  905. _STK--;
  906. ip++;
  907. break;
  908. }
  909. ip = code[ip];
  910. break;
  911. case OP_JMPIF_NP:
  912. if (!stack[_STK].getInt())
  913. {
  914. _STK--;
  915. ip++;
  916. break;
  917. }
  918. ip = code[ip];
  919. break;
  920. case OP_JMP:
  921. ip = code[ip];
  922. break;
  923. case OP_RETURN_VOID:
  924. {
  925. if (iterDepth > 0)
  926. {
  927. // Clear iterator state.
  928. while (iterDepth > 0)
  929. {
  930. iterStack[--_ITER].mIsStringIter = false;
  931. --iterDepth;
  932. }
  933. _STK--; // this is a pop from foreach()
  934. }
  935. returnValue.setEmptyString();
  936. goto execFinished;
  937. }
  938. case OP_RETURN:
  939. {
  940. if (iterDepth > 0)
  941. {
  942. // Clear iterator state.
  943. while (iterDepth > 0)
  944. {
  945. iterStack[--_ITER].mIsStringIter = false;
  946. --iterDepth;
  947. }
  948. const char* retVal = stack[_STK].getString();
  949. _STK--;
  950. _STK--;
  951. stack[_STK + 1].setString(retVal);
  952. _STK++; // Not nice but works.
  953. }
  954. returnValue.setString(stack[_STK].getString());
  955. _STK--;
  956. goto execFinished;
  957. }
  958. case OP_RETURN_FLT:
  959. if (iterDepth > 0)
  960. {
  961. // Clear iterator state.
  962. while (iterDepth > 0)
  963. {
  964. iterStack[--_ITER].mIsStringIter = false;
  965. --iterDepth;
  966. }
  967. }
  968. returnValue.setFloat(stack[_STK].getFloat());
  969. _STK--;
  970. goto execFinished;
  971. case OP_RETURN_UINT:
  972. if (iterDepth > 0)
  973. {
  974. // Clear iterator state.
  975. while (iterDepth > 0)
  976. {
  977. iterStack[--_ITER].mIsStringIter = false;
  978. --iterDepth;
  979. }
  980. }
  981. returnValue.setInt(stack[_STK].getInt());
  982. _STK--;
  983. goto execFinished;
  984. case OP_CMPEQ:
  985. stack[_STK - 1].setInt(stack[_STK].getFloat() == stack[_STK - 1].getFloat());
  986. _STK--;
  987. break;
  988. case OP_CMPGR:
  989. stack[_STK - 1].setInt(stack[_STK].getFloat() > stack[_STK - 1].getFloat());
  990. _STK--;
  991. break;
  992. case OP_CMPGE:
  993. stack[_STK - 1].setInt(stack[_STK].getFloat() >= stack[_STK - 1].getFloat());
  994. _STK--;
  995. break;
  996. case OP_CMPLT:
  997. stack[_STK - 1].setInt(stack[_STK].getFloat() < stack[_STK - 1].getFloat());
  998. _STK--;
  999. break;
  1000. case OP_CMPLE:
  1001. stack[_STK - 1].setInt(stack[_STK].getFloat() <= stack[_STK - 1].getFloat());
  1002. _STK--;
  1003. break;
  1004. case OP_CMPNE:
  1005. stack[_STK - 1].setInt(stack[_STK].getFloat() != stack[_STK - 1].getFloat());
  1006. _STK--;
  1007. break;
  1008. case OP_XOR:
  1009. stack[_STK - 1].setInt(stack[_STK].getInt() ^ stack[_STK - 1].getInt());
  1010. _STK--;
  1011. break;
  1012. case OP_MOD:
  1013. if (stack[_STK - 1].getInt() != 0)
  1014. stack[_STK - 1].setInt(stack[_STK].getInt() % stack[_STK - 1].getInt());
  1015. else
  1016. stack[_STK - 1].setInt(0);
  1017. _STK--;
  1018. break;
  1019. case OP_BITAND:
  1020. stack[_STK - 1].setInt(stack[_STK].getInt() & stack[_STK - 1].getInt());
  1021. _STK--;
  1022. break;
  1023. case OP_BITOR:
  1024. stack[_STK - 1].setInt(stack[_STK].getInt() | stack[_STK - 1].getInt());
  1025. _STK--;
  1026. break;
  1027. case OP_NOT:
  1028. stack[_STK].setInt(!stack[_STK].getInt());
  1029. break;
  1030. case OP_NOTF:
  1031. stack[_STK].setInt(!stack[_STK].getFloat());
  1032. break;
  1033. case OP_ONESCOMPLEMENT:
  1034. stack[_STK].setInt(~stack[_STK].getInt());
  1035. break;
  1036. case OP_SHR:
  1037. stack[_STK - 1].setInt(stack[_STK].getInt() >> stack[_STK - 1].getInt());
  1038. _STK--;
  1039. break;
  1040. case OP_SHL:
  1041. stack[_STK - 1].setInt(stack[_STK].getInt() << stack[_STK - 1].getInt());
  1042. _STK--;
  1043. break;
  1044. case OP_AND:
  1045. stack[_STK - 1].setInt(stack[_STK].getInt() && stack[_STK - 1].getInt());
  1046. _STK--;
  1047. break;
  1048. case OP_OR:
  1049. stack[_STK - 1].setInt(stack[_STK].getInt() || stack[_STK - 1].getInt());
  1050. _STK--;
  1051. break;
  1052. case OP_ADD:
  1053. stack[_STK - 1].setFloat(stack[_STK].getFloat() + stack[_STK - 1].getFloat());
  1054. _STK--;
  1055. break;
  1056. case OP_SUB:
  1057. stack[_STK - 1].setFloat(stack[_STK].getFloat() - stack[_STK - 1].getFloat());
  1058. _STK--;
  1059. break;
  1060. case OP_MUL:
  1061. stack[_STK - 1].setFloat(stack[_STK].getFloat() * stack[_STK - 1].getFloat());
  1062. _STK--;
  1063. break;
  1064. case OP_DIV:
  1065. stack[_STK - 1].setFloat(stack[_STK].getFloat() / stack[_STK - 1].getFloat());
  1066. _STK--;
  1067. break;
  1068. case OP_NEG:
  1069. stack[_STK].setFloat(-stack[_STK].getFloat());
  1070. break;
  1071. case OP_INC:
  1072. reg = code[ip++];
  1073. gEvalState.setLocalFloatVariable(reg, gEvalState.getLocalFloatVariable(reg) + 1.0);
  1074. break;
  1075. case OP_SETCURVAR:
  1076. var = CodeToSTE(code, ip);
  1077. ip += 2;
  1078. // If a variable is set, then these must be NULL. It is necessary
  1079. // to set this here so that the vector parser can appropriately
  1080. // identify whether it's dealing with a vector.
  1081. prevField = NULL;
  1082. prevObject = NULL;
  1083. curObject = NULL;
  1084. gEvalState.setCurVarName(var);
  1085. // In order to let docblocks work properly with variables, we have
  1086. // clear the current docblock when we do an assign. This way it
  1087. // won't inappropriately carry forward to following function decls.
  1088. curFNDocBlock = NULL;
  1089. curNSDocBlock = NULL;
  1090. break;
  1091. case OP_SETCURVAR_CREATE:
  1092. var = CodeToSTE(code, ip);
  1093. ip += 2;
  1094. // See OP_SETCURVAR
  1095. prevField = NULL;
  1096. prevObject = NULL;
  1097. curObject = NULL;
  1098. gEvalState.setCurVarNameCreate(var);
  1099. // See OP_SETCURVAR for why we do this.
  1100. curFNDocBlock = NULL;
  1101. curNSDocBlock = NULL;
  1102. break;
  1103. case OP_SETCURVAR_ARRAY:
  1104. var = StringTable->insert(stack[_STK].getString());
  1105. // See OP_SETCURVAR
  1106. prevField = NULL;
  1107. prevObject = NULL;
  1108. curObject = NULL;
  1109. gEvalState.setCurVarName(var);
  1110. // See OP_SETCURVAR for why we do this.
  1111. curFNDocBlock = NULL;
  1112. curNSDocBlock = NULL;
  1113. break;
  1114. case OP_SETCURVAR_ARRAY_CREATE:
  1115. var = StringTable->insert(stack[_STK].getString());
  1116. // See OP_SETCURVAR
  1117. prevField = NULL;
  1118. prevObject = NULL;
  1119. curObject = NULL;
  1120. gEvalState.setCurVarNameCreate(var);
  1121. // See OP_SETCURVAR for why we do this.
  1122. curFNDocBlock = NULL;
  1123. curNSDocBlock = NULL;
  1124. break;
  1125. case OP_LOADVAR_UINT:
  1126. stack[_STK + 1].setInt(gEvalState.getIntVariable());
  1127. _STK++;
  1128. break;
  1129. case OP_LOADVAR_FLT:
  1130. stack[_STK + 1].setFloat(gEvalState.getFloatVariable());
  1131. _STK++;
  1132. break;
  1133. case OP_LOADVAR_STR:
  1134. stack[_STK + 1].setString(gEvalState.getStringVariable());
  1135. _STK++;
  1136. break;
  1137. case OP_SAVEVAR_UINT:
  1138. gEvalState.setIntVariable(stack[_STK].getInt());
  1139. break;
  1140. case OP_SAVEVAR_FLT:
  1141. gEvalState.setFloatVariable(stack[_STK].getFloat());
  1142. break;
  1143. case OP_SAVEVAR_STR:
  1144. gEvalState.setStringVariable(stack[_STK].getString());
  1145. break;
  1146. case OP_LOAD_LOCAL_VAR_UINT:
  1147. reg = code[ip++];
  1148. stack[_STK + 1].setInt(gEvalState.getLocalIntVariable(reg));
  1149. _STK++;
  1150. break;
  1151. case OP_LOAD_LOCAL_VAR_FLT:
  1152. reg = code[ip++];
  1153. stack[_STK + 1].setFloat(gEvalState.getLocalFloatVariable(reg));
  1154. _STK++;
  1155. break;
  1156. case OP_LOAD_LOCAL_VAR_STR:
  1157. reg = code[ip++];
  1158. val = gEvalState.getLocalStringVariable(reg);
  1159. stack[_STK + 1].setString(val);
  1160. _STK++;
  1161. break;
  1162. case OP_SAVE_LOCAL_VAR_UINT:
  1163. reg = code[ip++];
  1164. gEvalState.setLocalIntVariable(reg, stack[_STK].getInt());
  1165. break;
  1166. case OP_SAVE_LOCAL_VAR_FLT:
  1167. reg = code[ip++];
  1168. gEvalState.setLocalFloatVariable(reg, stack[_STK].getFloat());
  1169. break;
  1170. case OP_SAVE_LOCAL_VAR_STR:
  1171. reg = code[ip++];
  1172. val = stack[_STK].getString();
  1173. gEvalState.setLocalStringVariable(reg, val, (S32)dStrlen(val));
  1174. break;
  1175. case OP_SETCUROBJECT:
  1176. // Save the previous object for parsing vector fields.
  1177. prevObject = curObject;
  1178. val = stack[_STK].getString();
  1179. _STK--;
  1180. // Sim::findObject will sometimes find valid objects from
  1181. // multi-component strings. This makes sure that doesn't
  1182. // happen.
  1183. for (const char* check = val; *check; check++)
  1184. {
  1185. if (*check == ' ')
  1186. {
  1187. val = "";
  1188. break;
  1189. }
  1190. }
  1191. curObject = Sim::findObject(val);
  1192. break;
  1193. case OP_SETCUROBJECT_INTERNAL:
  1194. ++ip; // To skip the recurse flag if the object wasnt found
  1195. if (curObject)
  1196. {
  1197. SimGroup* group = dynamic_cast<SimGroup*>(curObject);
  1198. if (group)
  1199. {
  1200. StringTableEntry intName = StringTable->insert(stack[_STK].getString());
  1201. bool recurse = code[ip - 1];
  1202. SimObject* obj = group->findObjectByInternalName(intName, recurse);
  1203. stack[_STK].setInt(obj ? obj->getId() : 0);
  1204. }
  1205. else
  1206. {
  1207. Con::errorf(ConsoleLogEntry::Script, "%s: Attempt to use -> on non-group %s of class %s.", getFileLine(ip - 2), curObject->getName(), curObject->getClassName());
  1208. stack[_STK].setInt(0);
  1209. }
  1210. }
  1211. break;
  1212. case OP_SETCUROBJECT_NEW:
  1213. curObject = currentNewObject;
  1214. break;
  1215. case OP_SETCURFIELD:
  1216. // Save the previous field for parsing vector fields.
  1217. prevField = curField;
  1218. dStrcpy(prevFieldArray, curFieldArray, 256);
  1219. curField = CodeToSTE(code, ip);
  1220. curFieldArray[0] = 0;
  1221. ip += 2;
  1222. break;
  1223. case OP_SETCURFIELD_ARRAY:
  1224. dStrcpy(curFieldArray, stack[_STK].getString(), 256);
  1225. break;
  1226. case OP_SETCURFIELD_TYPE:
  1227. if(curObject)
  1228. curObject->setDataFieldType(code[ip], curField, curFieldArray);
  1229. ip++;
  1230. break;
  1231. case OP_LOADFIELD_UINT:
  1232. if (curObject)
  1233. stack[_STK + 1].setInt(dAtol(curObject->getDataField(curField, curFieldArray)));
  1234. else
  1235. {
  1236. // The field is not being retrieved from an object. Maybe it's
  1237. // a special accessor?
  1238. char buff[FieldBufferSizeNumeric];
  1239. memset(buff, 0, sizeof(buff));
  1240. getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff);
  1241. stack[_STK + 1].setInt(dAtol(buff));
  1242. }
  1243. _STK++;
  1244. break;
  1245. case OP_LOADFIELD_FLT:
  1246. if (curObject)
  1247. stack[_STK + 1].setFloat(dAtod(curObject->getDataField(curField, curFieldArray)));
  1248. else
  1249. {
  1250. // The field is not being retrieved from an object. Maybe it's
  1251. // a special accessor?
  1252. char buff[FieldBufferSizeNumeric];
  1253. memset(buff, 0, sizeof(buff));
  1254. getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff);
  1255. stack[_STK + 1].setFloat(dAtod(buff));
  1256. }
  1257. _STK++;
  1258. break;
  1259. case OP_LOADFIELD_STR:
  1260. if (curObject)
  1261. {
  1262. val = curObject->getDataField(curField, curFieldArray);
  1263. stack[_STK + 1].setString(val);
  1264. }
  1265. else
  1266. {
  1267. // The field is not being retrieved from an object. Maybe it's
  1268. // a special accessor?
  1269. char buff[FieldBufferSizeString];
  1270. memset(buff, 0, sizeof(buff));
  1271. getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff);
  1272. stack[_STK + 1].setString(buff);
  1273. }
  1274. _STK++;
  1275. break;
  1276. case OP_SAVEFIELD_UINT:
  1277. if (curObject)
  1278. curObject->setDataField(curField, curFieldArray, stack[_STK].getString());
  1279. else
  1280. {
  1281. // The field is not being set on an object. Maybe it's
  1282. // a special accessor?
  1283. setFieldComponent( prevObject, prevField, prevFieldArray, curField );
  1284. prevObject = NULL;
  1285. }
  1286. break;
  1287. case OP_SAVEFIELD_FLT:
  1288. if (curObject)
  1289. curObject->setDataField(curField, curFieldArray, stack[_STK].getString());
  1290. else
  1291. {
  1292. // The field is not being set on an object. Maybe it's
  1293. // a special accessor?
  1294. setFieldComponent( prevObject, prevField, prevFieldArray, curField );
  1295. prevObject = NULL;
  1296. }
  1297. break;
  1298. case OP_SAVEFIELD_STR:
  1299. if (curObject)
  1300. curObject->setDataField(curField, curFieldArray, stack[_STK].getString());
  1301. else
  1302. {
  1303. // The field is not being set on an object. Maybe it's
  1304. // a special accessor?
  1305. setFieldComponent( prevObject, prevField, prevFieldArray, curField );
  1306. prevObject = NULL;
  1307. }
  1308. break;
  1309. case OP_POP_STK:
  1310. _STK--;
  1311. break;
  1312. case OP_LOADIMMED_UINT:
  1313. stack[_STK + 1].setInt(code[ip++]);
  1314. _STK++;
  1315. break;
  1316. case OP_LOADIMMED_FLT:
  1317. stack[_STK + 1].setFloat(curFloatTable[code[ip++]]);
  1318. _STK++;
  1319. break;
  1320. case OP_TAG_TO_STR:
  1321. code[ip - 1] = OP_LOADIMMED_STR;
  1322. // it's possible the string has already been converted
  1323. if (U8(curStringTable[code[ip]]) != StringTagPrefixByte)
  1324. {
  1325. U32 id = GameAddTaggedString(curStringTable + code[ip]);
  1326. dSprintf(curStringTable + code[ip] + 1, 7, "%d", id);
  1327. *(curStringTable + code[ip]) = StringTagPrefixByte;
  1328. }
  1329. TORQUE_CASE_FALLTHROUGH;
  1330. case OP_LOADIMMED_STR:
  1331. stack[_STK + 1].setString(curStringTable + code[ip++]);
  1332. _STK ++;
  1333. break;
  1334. case OP_DOCBLOCK_STR:
  1335. {
  1336. // If the first word of the doc is '\class' or '@class', then this
  1337. // is a namespace doc block, otherwise it is a function doc block.
  1338. const char* docblock = curStringTable + code[ip++];
  1339. const char* sansClass = dStrstr(docblock, "@class");
  1340. if (!sansClass)
  1341. sansClass = dStrstr(docblock, "\\class");
  1342. if (sansClass)
  1343. {
  1344. // Don't save the class declaration. Scan past the 'class'
  1345. // keyword and up to the first whitespace.
  1346. sansClass += 7;
  1347. S32 index = 0;
  1348. while ((*sansClass != ' ') && (*sansClass != '\n') && *sansClass && (index < (nsDocLength - 1)))
  1349. {
  1350. nsDocBlockClass[index++] = *sansClass;
  1351. sansClass++;
  1352. }
  1353. nsDocBlockClass[index] = '\0';
  1354. curNSDocBlock = sansClass + 1;
  1355. }
  1356. else
  1357. curFNDocBlock = docblock;
  1358. }
  1359. break;
  1360. case OP_LOADIMMED_IDENT:
  1361. stack[_STK + 1].setString(CodeToSTE(code, ip));
  1362. _STK++;
  1363. ip += 2;
  1364. break;
  1365. case OP_CALLFUNC:
  1366. {
  1367. // This routingId is set when we query the object as to whether
  1368. // it handles this method. It is set to an enum from the table
  1369. // above indicating whether it handles it on a component it owns
  1370. // or just on the object.
  1371. S32 routingId = 0;
  1372. fnName = CodeToSTE(code, ip);
  1373. fnNamespace = CodeToSTE(code, ip + 2);
  1374. U32 callType = code[ip + 4];
  1375. //if this is called from inside a function, append the ip and codeptr
  1376. if (!gEvalState.stack.empty())
  1377. {
  1378. gEvalState.stack.last()->code = this;
  1379. gEvalState.stack.last()->ip = ip - 1;
  1380. }
  1381. ip += 5;
  1382. gCallStack.argvc(fnName, callArgc, &callArgv);
  1383. if (callType == FuncCallExprNode::FunctionCall)
  1384. {
  1385. // Note: This works even if the function was in a package. Reason being is when
  1386. // activatePackage() is called, it swaps the namespaceEntry into the global namespace
  1387. // (and reverts it when deactivatePackage is called). Method or Static related ones work
  1388. // as expected, as the namespace is resolved on the fly.
  1389. nsEntry = Namespace::global()->lookup(fnName);
  1390. if (!nsEntry)
  1391. {
  1392. Con::warnf(ConsoleLogEntry::General,
  1393. "%s: Unable to find function %s",
  1394. getFileLine(ip - 4), fnName);
  1395. gCallStack.popFrame();
  1396. stack[_STK + 1].setEmptyString();
  1397. _STK++;
  1398. break;
  1399. }
  1400. }
  1401. else if (callType == FuncCallExprNode::StaticCall)
  1402. {
  1403. // Try to look it up.
  1404. ns = Namespace::find(fnNamespace);
  1405. nsEntry = ns->lookup(fnName);
  1406. if (!nsEntry)
  1407. {
  1408. Con::warnf(ConsoleLogEntry::General,
  1409. "%s: Unable to find function %s%s%s",
  1410. getFileLine(ip - 4), fnNamespace ? fnNamespace : "",
  1411. fnNamespace ? "::" : "", fnName);
  1412. gCallStack.popFrame();
  1413. stack[_STK + 1].setEmptyString();
  1414. _STK++;
  1415. break;
  1416. }
  1417. }
  1418. else if (callType == FuncCallExprNode::MethodCall)
  1419. {
  1420. saveObject = gEvalState.thisObject;
  1421. // Optimization: If we're an integer, we can lookup the value by SimObjectId
  1422. const ConsoleValue& simObjectLookupValue = callArgv[1];
  1423. if (simObjectLookupValue.getType() == ConsoleValueType::cvInteger)
  1424. gEvalState.thisObject = Sim::findObject(static_cast<SimObjectId>(simObjectLookupValue.getInt()));
  1425. else
  1426. {
  1427. SimObject *foundObject = Sim::findObject(simObjectLookupValue.getString());
  1428. // Optimization: If we're not an integer, let's make it so that the fast path exists
  1429. // on the first argument of the method call (speeds up future usage of %this, for example)
  1430. if (foundObject != NULL)
  1431. callArgv[1].setInt(static_cast<S64>(foundObject->getId()));
  1432. gEvalState.thisObject = foundObject;
  1433. }
  1434. if (gEvalState.thisObject == NULL)
  1435. {
  1436. Con::warnf(
  1437. ConsoleLogEntry::General,
  1438. "%s: Unable to find object: '%s' attempting to call function '%s'",
  1439. getFileLine(ip - 6),
  1440. simObjectLookupValue.getString(),
  1441. fnName
  1442. );
  1443. gCallStack.popFrame();
  1444. stack[_STK + 1].setEmptyString();
  1445. _STK++;
  1446. break;
  1447. }
  1448. ns = gEvalState.thisObject->getNamespace();
  1449. if (ns)
  1450. nsEntry = ns->lookup(fnName);
  1451. else
  1452. nsEntry = NULL;
  1453. }
  1454. else // it's a ParentCall
  1455. {
  1456. if (thisNamespace)
  1457. {
  1458. ns = thisNamespace->mParent;
  1459. if (ns)
  1460. nsEntry = ns->lookup(fnName);
  1461. else
  1462. nsEntry = NULL;
  1463. }
  1464. else
  1465. {
  1466. ns = NULL;
  1467. nsEntry = NULL;
  1468. }
  1469. }
  1470. if (!nsEntry || noCalls)
  1471. {
  1472. if (!noCalls)
  1473. {
  1474. Con::warnf(ConsoleLogEntry::General, "%s: Unknown command %s.", getFileLine(ip - 4), fnName);
  1475. if (callType == FuncCallExprNode::MethodCall)
  1476. {
  1477. Con::warnf(ConsoleLogEntry::General, " Object %s(%d) %s",
  1478. gEvalState.thisObject->getName() ? gEvalState.thisObject->getName() : "",
  1479. gEvalState.thisObject->getId(), Con::getNamespaceList(ns));
  1480. }
  1481. }
  1482. gCallStack.popFrame();
  1483. stack[_STK + 1].setEmptyString();
  1484. _STK++;
  1485. break;
  1486. }
  1487. if (nsEntry->mType == Namespace::Entry::ConsoleFunctionType)
  1488. {
  1489. if (nsEntry->mFunctionOffset)
  1490. {
  1491. ConsoleValue returnFromFn = nsEntry->mCode->exec(nsEntry->mFunctionOffset, fnName, nsEntry->mNamespace, callArgc, callArgv, false, nsEntry->mPackage);
  1492. stack[_STK + 1] = std::move(returnFromFn);
  1493. }
  1494. else // no body
  1495. stack[_STK + 1].setEmptyString();
  1496. _STK++;
  1497. gCallStack.popFrame();
  1498. }
  1499. else
  1500. {
  1501. if ((nsEntry->mMinArgs && S32(callArgc) < nsEntry->mMinArgs) || (nsEntry->mMaxArgs && S32(callArgc) > nsEntry->mMaxArgs))
  1502. {
  1503. const char* nsName = ns ? ns->mName : "";
  1504. Con::warnf(ConsoleLogEntry::Script, "%s: %s::%s - wrong number of arguments.", getFileLine(ip - 4), nsName, fnName);
  1505. Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", getFileLine(ip - 4), nsEntry->mUsage);
  1506. gCallStack.popFrame();
  1507. stack[_STK + 1].setEmptyString();
  1508. _STK++;
  1509. }
  1510. else
  1511. {
  1512. switch (nsEntry->mType)
  1513. {
  1514. case Namespace::Entry::StringCallbackType:
  1515. {
  1516. const char* result = nsEntry->cb.mStringCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
  1517. gCallStack.popFrame();
  1518. stack[_STK + 1].setString(result);
  1519. _STK++;
  1520. break;
  1521. }
  1522. case Namespace::Entry::IntCallbackType:
  1523. {
  1524. S64 result = nsEntry->cb.mIntCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
  1525. gCallStack.popFrame();
  1526. if (code[ip] == OP_POP_STK)
  1527. {
  1528. ip++;
  1529. break;
  1530. }
  1531. stack[_STK + 1].setInt(result);
  1532. _STK++;
  1533. break;
  1534. }
  1535. case Namespace::Entry::FloatCallbackType:
  1536. {
  1537. F64 result = nsEntry->cb.mFloatCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
  1538. gCallStack.popFrame();
  1539. if (code[ip] == OP_POP_STK)
  1540. {
  1541. ip++;
  1542. break;
  1543. }
  1544. stack[_STK + 1].setInt(result);
  1545. _STK++;
  1546. break;
  1547. }
  1548. case Namespace::Entry::VoidCallbackType:
  1549. {
  1550. nsEntry->cb.mVoidCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
  1551. gCallStack.popFrame();
  1552. if (code[ip] == OP_POP_STK)
  1553. {
  1554. ip++;
  1555. break;
  1556. }
  1557. Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", getFileLine(ip - 4), fnName, functionName);
  1558. stack[_STK + 1].setEmptyString();
  1559. _STK++;
  1560. break;
  1561. }
  1562. case Namespace::Entry::BoolCallbackType:
  1563. {
  1564. bool result = nsEntry->cb.mBoolCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
  1565. gCallStack.popFrame();
  1566. if (code[ip] == OP_POP_STK)
  1567. {
  1568. ip++;
  1569. break;
  1570. }
  1571. stack[_STK + 1].setBool(result);
  1572. _STK++;
  1573. break;
  1574. }
  1575. }
  1576. }
  1577. }
  1578. if (callType == FuncCallExprNode::MethodCall)
  1579. gEvalState.thisObject = saveObject;
  1580. break;
  1581. }
  1582. case OP_ADVANCE_STR_APPENDCHAR:
  1583. {
  1584. char buff[2];
  1585. buff[0] = (char)code[ip++];
  1586. buff[1] = '\0';
  1587. S32 len;
  1588. const char* concat = tsconcat(stack[_STK].getString(), buff, len);
  1589. stack[_STK].setStringRef(concat, len);
  1590. break;
  1591. }
  1592. case OP_REWIND_STR:
  1593. TORQUE_CASE_FALLTHROUGH;
  1594. case OP_TERMINATE_REWIND_STR:
  1595. {
  1596. S32 len;
  1597. const char* concat = tsconcat(stack[_STK - 1].getString(), stack[_STK].getString(), len);
  1598. stack[_STK - 1].setStringRef(concat, len);
  1599. _STK--;
  1600. break;
  1601. }
  1602. case OP_COMPARE_STR:
  1603. stack[_STK - 1].setBool(!dStricmp(stack[_STK].getString(), stack[_STK - 1].getString()));
  1604. _STK--;
  1605. break;
  1606. case OP_PUSH:
  1607. gCallStack.push(std::move(stack[_STK--]));
  1608. break;
  1609. case OP_PUSH_FRAME:
  1610. gCallStack.pushFrame(code[ip++]);
  1611. break;
  1612. case OP_ASSERT:
  1613. {
  1614. if (!stack[_STK--].getBool())
  1615. {
  1616. const char* message = curStringTable + code[ip];
  1617. U32 breakLine, inst;
  1618. findBreakLine(ip - 1, breakLine, inst);
  1619. if (PlatformAssert::processAssert(PlatformAssert::Fatal,
  1620. name ? name : "eval",
  1621. breakLine,
  1622. message))
  1623. {
  1624. if (TelDebugger && TelDebugger->isConnected() && breakLine > 0)
  1625. {
  1626. TelDebugger->breakProcess();
  1627. }
  1628. else
  1629. Platform::debugBreak();
  1630. }
  1631. }
  1632. ip++;
  1633. break;
  1634. }
  1635. case OP_BREAK:
  1636. {
  1637. //append the ip and codeptr before managing the breakpoint!
  1638. AssertFatal(!gEvalState.stack.empty(), "Empty eval stack on break!");
  1639. gEvalState.stack.last()->code = this;
  1640. gEvalState.stack.last()->ip = ip - 1;
  1641. U32 breakLine;
  1642. findBreakLine(ip - 1, breakLine, instruction);
  1643. if (!breakLine)
  1644. goto breakContinue;
  1645. TelDebugger->executionStopped(this, breakLine);
  1646. goto breakContinue;
  1647. }
  1648. case OP_ITER_BEGIN_STR:
  1649. {
  1650. iterStack[_ITER].mIsStringIter = true;
  1651. TORQUE_CASE_FALLTHROUGH;
  1652. }
  1653. case OP_ITER_BEGIN:
  1654. {
  1655. bool isGlobal = code[ip];
  1656. U32 failIp = code[ip + isGlobal ? 3 : 2];
  1657. IterStackRecord& iter = iterStack[_ITER];
  1658. iter.mIsGlobalVariable = isGlobal;
  1659. if (isGlobal)
  1660. {
  1661. StringTableEntry varName = CodeToSTE(code, ip + 1);
  1662. iter.mVar.mVariable = gEvalState.globalVars.add(varName);
  1663. }
  1664. else
  1665. {
  1666. iter.mVar.mRegister = code[ip + 1];
  1667. }
  1668. if (iter.mIsStringIter)
  1669. {
  1670. iter.mData.mStr.mString = stack[_STK].getString();
  1671. iter.mData.mStr.mIndex = 0;
  1672. }
  1673. else
  1674. {
  1675. // Look up the object.
  1676. SimSet* set;
  1677. if (!Sim::findObject(stack[_STK].getString(), set))
  1678. {
  1679. Con::errorf(ConsoleLogEntry::General, "No SimSet object '%s'", stack[_STK].getString());
  1680. Con::errorf(ConsoleLogEntry::General, "Did you mean to use 'foreach$' instead of 'foreach'?");
  1681. ip = failIp;
  1682. continue;
  1683. }
  1684. // Set up.
  1685. iter.mData.mObj.mSet = set;
  1686. iter.mData.mObj.mIndex = 0;
  1687. }
  1688. _ITER++;
  1689. iterDepth++;
  1690. ip += isGlobal ? 4 : 3;
  1691. break;
  1692. }
  1693. case OP_ITER:
  1694. {
  1695. U32 breakIp = code[ip];
  1696. IterStackRecord& iter = iterStack[_ITER - 1];
  1697. if (iter.mIsStringIter)
  1698. {
  1699. const char* str = iter.mData.mStr.mString;
  1700. U32 startIndex = iter.mData.mStr.mIndex;
  1701. U32 endIndex = startIndex;
  1702. // Break if at end.
  1703. if (!str[startIndex])
  1704. {
  1705. ip = breakIp;
  1706. continue;
  1707. }
  1708. // Find right end of current component.
  1709. if (!dIsspace(str[endIndex]))
  1710. do ++endIndex;
  1711. while (str[endIndex] && !dIsspace(str[endIndex]));
  1712. // Extract component.
  1713. if (endIndex != startIndex)
  1714. {
  1715. char savedChar = str[endIndex];
  1716. const_cast<char*>(str)[endIndex] = '\0'; // We are on the string stack so this is okay.
  1717. if (iter.mIsGlobalVariable)
  1718. iter.mVar.mVariable->setStringValue(&str[startIndex]);
  1719. else
  1720. gEvalState.setLocalStringVariable(iter.mVar.mRegister, &str[startIndex], endIndex - startIndex);
  1721. const_cast<char*>(str)[endIndex] = savedChar;
  1722. }
  1723. else
  1724. {
  1725. if (iter.mIsGlobalVariable)
  1726. iter.mVar.mVariable->setStringValue("");
  1727. else
  1728. gEvalState.setLocalStringVariable(iter.mVar.mRegister, "", 0);
  1729. }
  1730. // Skip separator.
  1731. if (str[endIndex] != '\0')
  1732. ++endIndex;
  1733. iter.mData.mStr.mIndex = endIndex;
  1734. }
  1735. else
  1736. {
  1737. U32 index = iter.mData.mObj.mIndex;
  1738. SimSet* set = iter.mData.mObj.mSet;
  1739. if (index >= set->size())
  1740. {
  1741. ip = breakIp;
  1742. continue;
  1743. }
  1744. SimObjectId id = set->at(index)->getId();
  1745. if (iter.mIsGlobalVariable)
  1746. iter.mVar.mVariable->setIntValue(id);
  1747. else
  1748. gEvalState.setLocalIntVariable(iter.mVar.mRegister, id);
  1749. iter.mData.mObj.mIndex = index + 1;
  1750. }
  1751. ++ip;
  1752. break;
  1753. }
  1754. case OP_ITER_END:
  1755. {
  1756. --_ITER;
  1757. --iterDepth;
  1758. _STK--;
  1759. iterStack[_ITER].mIsStringIter = false;
  1760. break;
  1761. }
  1762. case OP_INVALID:
  1763. TORQUE_CASE_FALLTHROUGH;
  1764. default:
  1765. // error!
  1766. AssertISV(false, "Invalid OPCode Processed!");
  1767. goto execFinished;
  1768. }
  1769. }
  1770. execFinished:
  1771. if (telDebuggerOn && setFrame < 0)
  1772. TelDebugger->popStackFrame();
  1773. if (popFrame)
  1774. {
  1775. gEvalState.popFrame();
  1776. }
  1777. if (argv)
  1778. {
  1779. if (gEvalState.traceOn)
  1780. {
  1781. traceBuffer[0] = 0;
  1782. dStrcat(traceBuffer, "Leaving ", TRACE_BUFFER_SIZE);
  1783. if (packageName)
  1784. {
  1785. dStrcat(traceBuffer, "[", TRACE_BUFFER_SIZE);
  1786. dStrcat(traceBuffer, packageName, TRACE_BUFFER_SIZE);
  1787. dStrcat(traceBuffer, "]", TRACE_BUFFER_SIZE);
  1788. }
  1789. if (thisNamespace && thisNamespace->mName)
  1790. {
  1791. dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
  1792. "%s::%s() - return %s", thisNamespace->mName, thisFunctionName, returnValue.getString());
  1793. }
  1794. else
  1795. {
  1796. dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
  1797. "%s() - return %s", thisFunctionName, returnValue.getString());
  1798. }
  1799. Con::printf("%s", traceBuffer);
  1800. }
  1801. }
  1802. else
  1803. {
  1804. delete[] const_cast<char*>(globalStrings);
  1805. delete[] globalFloats;
  1806. globalStrings = NULL;
  1807. globalFloats = NULL;
  1808. }
  1809. smCurrentCodeBlock = saveCodeBlock;
  1810. if (saveCodeBlock && saveCodeBlock->name)
  1811. {
  1812. Con::gCurrentFile = saveCodeBlock->name;
  1813. Con::gCurrentRoot = saveCodeBlock->modPath;
  1814. }
  1815. decRefCount();
  1816. #ifdef TORQUE_DEBUG
  1817. AssertFatal(!(_STK > stackStart), "String stack not popped enough in script exec");
  1818. AssertFatal(!(_STK < stackStart), "String stack popped too much in script exec");
  1819. #endif
  1820. return std::move(returnValue);
  1821. }
  1822. //------------------------------------------------------------