astNodes.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 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 "ast.h"
  25. #include "compiler.h"
  26. #include "console/simBase.h"
  27. template< typename T >
  28. struct Token
  29. {
  30. T value;
  31. S32 lineNumber;
  32. };
  33. #include "CMDgram.h"
  34. namespace Compiler
  35. {
  36. U32 compileBlock(StmtNode* block, CodeStream& codeStream, U32 ip)
  37. {
  38. for (StmtNode* walk = block; walk; walk = walk->getNext())
  39. {
  40. ip = walk->compileStmt(codeStream, ip);
  41. }
  42. return codeStream.tell();
  43. }
  44. }
  45. using namespace Compiler;
  46. FuncVars gEvalFuncVars;
  47. FuncVars gGlobalScopeFuncVars;
  48. FuncVars* gFuncVars = NULL;
  49. inline FuncVars* getFuncVars(S32 lineNumber)
  50. {
  51. if (gFuncVars == &gGlobalScopeFuncVars)
  52. {
  53. const char* str = avar("Attemping to use local variable in global scope. File: %s Line: %d", CodeBlock::smCurrentParser->getCurrentFile(), lineNumber);
  54. scriptErrorHandler(str);
  55. }
  56. return gFuncVars;
  57. }
  58. //-----------------------------------------------------------------------------
  59. void StmtNode::addBreakLine(CodeStream& code)
  60. {
  61. code.addBreakLine(dbgLineNumber, code.tell());
  62. }
  63. //------------------------------------------------------------
  64. StmtNode::StmtNode() : dbgLineNumber(0)
  65. {
  66. next = NULL;
  67. dbgFileName = CodeBlock::smCurrentParser->getCurrentFile();
  68. }
  69. void StmtNode::setPackage(StringTableEntry)
  70. {
  71. }
  72. void StmtNode::append(StmtNode* appended)
  73. {
  74. StmtNode* walk = this;
  75. while (walk->next)
  76. walk = walk->next;
  77. walk->next = appended;
  78. }
  79. void FunctionDeclStmtNode::setPackage(StringTableEntry packageName)
  80. {
  81. package = packageName;
  82. }
  83. //------------------------------------------------------------
  84. //
  85. // Console language compilers
  86. //
  87. //------------------------------------------------------------
  88. U32 BreakStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
  89. {
  90. if (codeStream.inLoop())
  91. {
  92. addBreakLine(codeStream);
  93. codeStream.emit(OP_JMP);
  94. codeStream.emitFix(CodeStream::FIXTYPE_BREAK);
  95. }
  96. else
  97. {
  98. Con::warnf(ConsoleLogEntry::General, "%s (%d): break outside of loop... ignoring.", dbgFileName, dbgLineNumber);
  99. }
  100. return codeStream.tell();
  101. }
  102. //------------------------------------------------------------
  103. U32 ContinueStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
  104. {
  105. if (codeStream.inLoop())
  106. {
  107. addBreakLine(codeStream);
  108. codeStream.emit(OP_JMP);
  109. codeStream.emitFix(CodeStream::FIXTYPE_CONTINUE);
  110. }
  111. else
  112. {
  113. Con::warnf(ConsoleLogEntry::General, "%s (%d): continue outside of loop... ignoring.", dbgFileName, dbgLineNumber);
  114. }
  115. return codeStream.tell();
  116. }
  117. //------------------------------------------------------------
  118. U32 ExprNode::compileStmt(CodeStream& codeStream, U32 ip)
  119. {
  120. addBreakLine(codeStream);
  121. return compile(codeStream, ip, TypeReqNone);
  122. }
  123. //------------------------------------------------------------
  124. U32 ReturnStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
  125. {
  126. addBreakLine(codeStream);
  127. if (!expr)
  128. codeStream.emit(OP_RETURN_VOID);
  129. else
  130. {
  131. TypeReq walkType = expr->getPreferredType();
  132. if (walkType == TypeReqNone) walkType = TypeReqString;
  133. ip = expr->compile(codeStream, ip, walkType);
  134. // Return the correct type
  135. switch (walkType) {
  136. case TypeReqUInt:
  137. codeStream.emit(OP_RETURN_UINT);
  138. break;
  139. case TypeReqFloat:
  140. codeStream.emit(OP_RETURN_FLT);
  141. break;
  142. default:
  143. codeStream.emit(OP_RETURN);
  144. break;
  145. }
  146. }
  147. return codeStream.tell();
  148. }
  149. //------------------------------------------------------------
  150. ExprNode* IfStmtNode::getSwitchOR(ExprNode* left, ExprNode* list, bool string)
  151. {
  152. ExprNode* nextExpr = (ExprNode*)list->getNext();
  153. ExprNode* test;
  154. if (string)
  155. test = StreqExprNode::alloc(left->dbgLineNumber, left, list, true);
  156. else
  157. test = IntBinaryExprNode::alloc(left->dbgLineNumber, opEQ, left, list);
  158. if (!nextExpr)
  159. return test;
  160. return IntBinaryExprNode::alloc(test->dbgLineNumber, opOR, test, getSwitchOR(left, nextExpr, string));
  161. }
  162. void IfStmtNode::propagateSwitchExpr(ExprNode* left, bool string)
  163. {
  164. testExpr = getSwitchOR(left, testExpr, string);
  165. if (propagate && elseBlock)
  166. ((IfStmtNode*)elseBlock)->propagateSwitchExpr(left, string);
  167. }
  168. U32 IfStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
  169. {
  170. U32 endifIp, elseIp;
  171. addBreakLine(codeStream);
  172. TypeReq testType = testExpr->getPreferredType();
  173. if (testType == TypeReqUInt)
  174. {
  175. integer = true;
  176. }
  177. else
  178. {
  179. integer = false;
  180. }
  181. if (testType == TypeReqString || testType == TypeReqNone)
  182. {
  183. ip = testExpr->compile(codeStream, ip, TypeReqString);
  184. codeStream.emit(OP_JMPNOTSTRING);
  185. }
  186. else
  187. {
  188. ip = testExpr->compile(codeStream, ip, integer ? TypeReqUInt : TypeReqFloat);
  189. codeStream.emit(integer ? OP_JMPIFNOT : OP_JMPIFFNOT);
  190. }
  191. if (elseBlock)
  192. {
  193. elseIp = codeStream.emit(0);
  194. elseOffset = compileBlock(ifBlock, codeStream, ip) + 2;
  195. codeStream.emit(OP_JMP);
  196. endifIp = codeStream.emit(0);
  197. endifOffset = compileBlock(elseBlock, codeStream, ip);
  198. codeStream.patch(endifIp, endifOffset);
  199. codeStream.patch(elseIp, elseOffset);
  200. }
  201. else
  202. {
  203. endifIp = codeStream.emit(0);
  204. endifOffset = compileBlock(ifBlock, codeStream, ip);
  205. codeStream.patch(endifIp, endifOffset);
  206. }
  207. // Resolve fixes
  208. return codeStream.tell();
  209. }
  210. //------------------------------------------------------------
  211. U32 LoopStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
  212. {
  213. if (testExpr->getPreferredType() == TypeReqUInt)
  214. {
  215. integer = true;
  216. }
  217. else
  218. {
  219. integer = false;
  220. }
  221. // if it's a for loop or a while loop it goes:
  222. // initExpr
  223. // testExpr
  224. // OP_JMPIFNOT to break point
  225. // loopStartPoint:
  226. // loopBlock
  227. // continuePoint:
  228. // endLoopExpr
  229. // testExpr
  230. // OP_JMPIF loopStartPoint
  231. // breakPoint:
  232. // otherwise if it's a do ... while() it goes:
  233. // initExpr
  234. // loopStartPoint:
  235. // loopBlock
  236. // continuePoint:
  237. // endLoopExpr
  238. // testExpr
  239. // OP_JMPIF loopStartPoint
  240. // breakPoint:
  241. // loopBlockStart == start of loop block
  242. // continue == skip to end
  243. // break == exit loop
  244. addBreakLine(codeStream);
  245. codeStream.pushFixScope(true);
  246. if (initExpr)
  247. ip = initExpr->compile(codeStream, ip, TypeReqNone);
  248. if (!isDoLoop)
  249. {
  250. ip = testExpr->compile(codeStream, ip, integer ? TypeReqUInt : TypeReqFloat);
  251. codeStream.emit(integer ? OP_JMPIFNOT : OP_JMPIFFNOT);
  252. codeStream.emitFix(CodeStream::FIXTYPE_BREAK);
  253. }
  254. // Compile internals of loop.
  255. loopBlockStartOffset = codeStream.tell();
  256. continueOffset = compileBlock(loopBlock, codeStream, ip);
  257. if (endLoopExpr)
  258. ip = endLoopExpr->compile(codeStream, ip, TypeReqNone);
  259. ip = testExpr->compile(codeStream, ip, integer ? TypeReqUInt : TypeReqFloat);
  260. codeStream.emit(integer ? OP_JMPIF : OP_JMPIFF);
  261. codeStream.emitFix(CodeStream::FIXTYPE_LOOPBLOCKSTART);
  262. breakOffset = codeStream.tell(); // exit loop
  263. codeStream.fixLoop(loopBlockStartOffset, breakOffset, continueOffset);
  264. codeStream.popFixScope();
  265. return codeStream.tell();
  266. }
  267. //------------------------------------------------------------
  268. U32 IterStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
  269. {
  270. // Instruction sequence:
  271. //
  272. // containerExpr
  273. // OP_ITER_BEGIN varName .fail
  274. // .continue:
  275. // OP_ITER .break
  276. // body
  277. // OP_JMP .continue
  278. // .break:
  279. // OP_ITER_END
  280. // .fail:
  281. addBreakLine(codeStream);
  282. codeStream.pushFixScope(true);
  283. bool isGlobal = varName[0] == '$';
  284. TypeReq varType = isStringIter ? TypeReqString : TypeReqUInt;
  285. const U32 startIp = ip;
  286. containerExpr->compile(codeStream, startIp, TypeReqString);
  287. codeStream.emit(isStringIter ? OP_ITER_BEGIN_STR : OP_ITER_BEGIN);
  288. codeStream.emit(isGlobal);
  289. if (isGlobal)
  290. codeStream.emitSTE(varName);
  291. else
  292. codeStream.emit(getFuncVars(dbgLineNumber)->assign(varName, varType, dbgLineNumber));
  293. const U32 finalFix = codeStream.emit(0);
  294. const U32 continueIp = codeStream.emit(OP_ITER);
  295. codeStream.emitFix(CodeStream::FIXTYPE_BREAK);
  296. const U32 bodyIp = codeStream.tell();
  297. const U32 jmpIp = compileBlock(body, codeStream, bodyIp);
  298. const U32 breakIp = jmpIp + 2;
  299. const U32 finalIp = breakIp + 1;
  300. codeStream.emit(OP_JMP);
  301. codeStream.emitFix(CodeStream::FIXTYPE_CONTINUE);
  302. codeStream.emit(OP_ITER_END);
  303. codeStream.patch(finalFix, finalIp);
  304. codeStream.fixLoop(bodyIp, breakIp, continueIp);
  305. codeStream.popFixScope();
  306. return codeStream.tell();
  307. }
  308. //------------------------------------------------------------
  309. U32 ConditionalExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  310. {
  311. // code is testExpr
  312. // JMPIFNOT falseStart
  313. // trueExpr
  314. // JMP end
  315. // falseExpr
  316. if (testExpr->getPreferredType() == TypeReqUInt)
  317. {
  318. integer = true;
  319. }
  320. else
  321. {
  322. integer = false;
  323. }
  324. ip = testExpr->compile(codeStream, ip, integer ? TypeReqUInt : TypeReqFloat);
  325. codeStream.emit(integer ? OP_JMPIFNOT : OP_JMPIFFNOT);
  326. U32 jumpElseIp = codeStream.emit(0);
  327. ip = trueExpr->compile(codeStream, ip, type);
  328. codeStream.emit(OP_JMP);
  329. U32 jumpEndIp = codeStream.emit(0);
  330. codeStream.patch(jumpElseIp, codeStream.tell());
  331. ip = falseExpr->compile(codeStream, ip, type);
  332. codeStream.patch(jumpEndIp, codeStream.tell());
  333. return codeStream.tell();
  334. }
  335. TypeReq ConditionalExprNode::getPreferredType()
  336. {
  337. // We can't make it calculate a type based on subsequent expressions as the expression
  338. // could be a string, or just numbers. To play it safe, stringify anything that deals with
  339. // a conditional, and let the interpreter cast as needed to other types safely.
  340. //
  341. // See: Regression Test 7 in ScriptTest. It has a string result in the else portion of the ?: ternary.
  342. return TypeReqString;
  343. }
  344. //------------------------------------------------------------
  345. U32 FloatBinaryExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  346. {
  347. if (optimize())
  348. {
  349. ip = optimizedNode->compile(codeStream, ip, type);
  350. return codeStream.tell();
  351. }
  352. ip = right->compile(codeStream, ip, TypeReqFloat);
  353. ip = left->compile(codeStream, ip, TypeReqFloat);
  354. U32 operand = OP_INVALID;
  355. switch (op)
  356. {
  357. case '+':
  358. operand = OP_ADD;
  359. break;
  360. case '-':
  361. operand = OP_SUB;
  362. break;
  363. case '/':
  364. operand = OP_DIV;
  365. break;
  366. case '*':
  367. operand = OP_MUL;
  368. break;
  369. }
  370. codeStream.emit(operand);
  371. return codeStream.tell();
  372. }
  373. TypeReq FloatBinaryExprNode::getPreferredType()
  374. {
  375. return TypeReqFloat;
  376. }
  377. //------------------------------------------------------------
  378. void IntBinaryExprNode::getSubTypeOperand()
  379. {
  380. subType = TypeReqUInt;
  381. switch (op)
  382. {
  383. case '^':
  384. operand = OP_XOR;
  385. break;
  386. case '%':
  387. operand = OP_MOD;
  388. break;
  389. case '&':
  390. operand = OP_BITAND;
  391. break;
  392. case '|':
  393. operand = OP_BITOR;
  394. break;
  395. case '<':
  396. operand = OP_CMPLT;
  397. subType = TypeReqFloat;
  398. break;
  399. case '>':
  400. operand = OP_CMPGR;
  401. subType = TypeReqFloat;
  402. break;
  403. case opGE:
  404. operand = OP_CMPGE;
  405. subType = TypeReqFloat;
  406. break;
  407. case opLE:
  408. operand = OP_CMPLE;
  409. subType = TypeReqFloat;
  410. break;
  411. case opEQ:
  412. operand = OP_CMPEQ;
  413. subType = TypeReqFloat;
  414. break;
  415. case opNE:
  416. operand = OP_CMPNE;
  417. subType = TypeReqFloat;
  418. break;
  419. case opOR:
  420. operand = OP_OR;
  421. break;
  422. case opAND:
  423. operand = OP_AND;
  424. break;
  425. case opSHR:
  426. operand = OP_SHR;
  427. break;
  428. case opSHL:
  429. operand = OP_SHL;
  430. break;
  431. }
  432. }
  433. U32 IntBinaryExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  434. {
  435. if (optimize())
  436. right = optimizedNode;
  437. getSubTypeOperand();
  438. if (operand == OP_OR || operand == OP_AND)
  439. {
  440. ip = left->compile(codeStream, ip, subType);
  441. codeStream.emit(operand == OP_OR ? OP_JMPIF_NP : OP_JMPIFNOT_NP);
  442. U32 jmpIp = codeStream.emit(0);
  443. ip = right->compile(codeStream, ip, subType);
  444. codeStream.patch(jmpIp, ip);
  445. }
  446. else
  447. {
  448. ip = right->compile(codeStream, ip, subType);
  449. ip = left->compile(codeStream, ip, subType);
  450. codeStream.emit(operand);
  451. }
  452. return codeStream.tell();
  453. }
  454. TypeReq IntBinaryExprNode::getPreferredType()
  455. {
  456. return TypeReqUInt;
  457. }
  458. //------------------------------------------------------------
  459. U32 StreqExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  460. {
  461. // eval str left
  462. // OP_ADVANCE_STR_NUL
  463. // eval str right
  464. // OP_COMPARE_STR
  465. // optional conversion
  466. ip = left->compile(codeStream, ip, TypeReqString);
  467. ip = right->compile(codeStream, ip, TypeReqString);
  468. codeStream.emit(OP_COMPARE_STR);
  469. if (!eq)
  470. codeStream.emit(OP_NOT);
  471. return codeStream.tell();
  472. }
  473. TypeReq StreqExprNode::getPreferredType()
  474. {
  475. return TypeReqUInt;
  476. }
  477. //------------------------------------------------------------
  478. U32 StrcatExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  479. {
  480. ip = left->compile(codeStream, ip, TypeReqString);
  481. if (appendChar)
  482. {
  483. codeStream.emit(OP_ADVANCE_STR_APPENDCHAR);
  484. codeStream.emit(appendChar);
  485. }
  486. ip = right->compile(codeStream, ip, TypeReqString);
  487. codeStream.emit(OP_REWIND_STR);
  488. return codeStream.tell();
  489. }
  490. TypeReq StrcatExprNode::getPreferredType()
  491. {
  492. return TypeReqString;
  493. }
  494. //------------------------------------------------------------
  495. U32 CommaCatExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  496. {
  497. ip = left->compile(codeStream, ip, TypeReqString);
  498. codeStream.emit(OP_ADVANCE_STR_APPENDCHAR);
  499. codeStream.emit('_');
  500. ip = right->compile(codeStream, ip, TypeReqString);
  501. codeStream.emit(OP_REWIND_STR);
  502. // At this point the stack has the concatenated string.
  503. // But we're paranoid, so accept (but whine) if we get an oddity...
  504. if (type == TypeReqUInt || type == TypeReqFloat)
  505. Con::warnf(ConsoleLogEntry::General, "%s (%d): converting comma string to a number... probably wrong.", dbgFileName, dbgLineNumber);
  506. return codeStream.tell();
  507. }
  508. TypeReq CommaCatExprNode::getPreferredType()
  509. {
  510. return TypeReqString;
  511. }
  512. //------------------------------------------------------------
  513. U32 IntUnaryExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  514. {
  515. integer = true;
  516. TypeReq prefType = expr->getPreferredType();
  517. if (op == '!' && (prefType == TypeReqFloat || prefType == TypeReqString))
  518. integer = false;
  519. ip = expr->compile(codeStream, ip, integer ? TypeReqUInt : TypeReqFloat);
  520. if (op == '!')
  521. codeStream.emit(integer ? OP_NOT : OP_NOTF);
  522. else if (op == '~')
  523. codeStream.emit(OP_ONESCOMPLEMENT);
  524. return codeStream.tell();
  525. }
  526. TypeReq IntUnaryExprNode::getPreferredType()
  527. {
  528. return TypeReqUInt;
  529. }
  530. //------------------------------------------------------------
  531. U32 FloatUnaryExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  532. {
  533. ip = expr->compile(codeStream, ip, TypeReqFloat);
  534. codeStream.emit(OP_NEG);
  535. return codeStream.tell();
  536. }
  537. TypeReq FloatUnaryExprNode::getPreferredType()
  538. {
  539. return TypeReqFloat;
  540. }
  541. //------------------------------------------------------------
  542. U32 VarNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  543. {
  544. // if this has an arrayIndex...
  545. // OP_LOADIMMED_IDENT
  546. // varName
  547. // OP_ADVANCE_STR
  548. // evaluate arrayIndex TypeReqString
  549. // OP_REWIND_STR
  550. // OP_SETCURVAR_ARRAY
  551. // OP_LOADVAR (type)
  552. // else
  553. // OP_SETCURVAR
  554. // varName
  555. // OP_LOADVAR (type)
  556. if (type == TypeReqNone)
  557. return codeStream.tell();
  558. precompileIdent(varName);
  559. bool oldVariables = arrayIndex || varName[0] == '$';
  560. if (oldVariables)
  561. {
  562. codeStream.emit(arrayIndex ? OP_LOADIMMED_IDENT : OP_SETCURVAR);
  563. codeStream.emitSTE(varName);
  564. if (arrayIndex)
  565. {
  566. //codeStream.emit(OP_ADVANCE_STR);
  567. ip = arrayIndex->compile(codeStream, ip, TypeReqString);
  568. codeStream.emit(OP_REWIND_STR);
  569. codeStream.emit(OP_SETCURVAR_ARRAY);
  570. codeStream.emit(OP_POP_STK);
  571. }
  572. switch (type)
  573. {
  574. case TypeReqUInt:
  575. codeStream.emit(OP_LOADVAR_UINT);
  576. break;
  577. case TypeReqFloat:
  578. codeStream.emit(OP_LOADVAR_FLT);
  579. break;
  580. case TypeReqString:
  581. codeStream.emit(OP_LOADVAR_STR);
  582. break;
  583. case TypeReqNone:
  584. break;
  585. default:
  586. break;
  587. }
  588. }
  589. else
  590. {
  591. switch (type)
  592. {
  593. case TypeReqUInt: codeStream.emit(OP_LOAD_LOCAL_VAR_UINT); break;
  594. case TypeReqFloat: codeStream.emit(OP_LOAD_LOCAL_VAR_FLT); break;
  595. default: codeStream.emit(OP_LOAD_LOCAL_VAR_STR);
  596. }
  597. codeStream.emit(getFuncVars(dbgLineNumber)->lookup(varName, dbgLineNumber));
  598. }
  599. return codeStream.tell();
  600. }
  601. TypeReq VarNode::getPreferredType()
  602. {
  603. bool oldVariables = arrayIndex || varName[0] == '$';
  604. return oldVariables ? TypeReqNone : getFuncVars(dbgLineNumber)->lookupType(varName, dbgLineNumber);
  605. }
  606. //------------------------------------------------------------
  607. U32 IntNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  608. {
  609. if (type == TypeReqString)
  610. index = getCurrentStringTable()->addIntString(value);
  611. else if (type == TypeReqFloat)
  612. index = getCurrentFloatTable()->add(value);
  613. switch (type)
  614. {
  615. case TypeReqUInt:
  616. codeStream.emit(OP_LOADIMMED_UINT);
  617. codeStream.emit(value);
  618. break;
  619. case TypeReqString:
  620. codeStream.emit(OP_LOADIMMED_STR);
  621. codeStream.emit(index);
  622. break;
  623. case TypeReqFloat:
  624. codeStream.emit(OP_LOADIMMED_FLT);
  625. codeStream.emit(index);
  626. break;
  627. case TypeReqNone:
  628. break;
  629. }
  630. return codeStream.tell();
  631. }
  632. TypeReq IntNode::getPreferredType()
  633. {
  634. return TypeReqUInt;
  635. }
  636. //------------------------------------------------------------
  637. U32 FloatNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  638. {
  639. if (type == TypeReqString)
  640. index = getCurrentStringTable()->addFloatString(value);
  641. else if (type == TypeReqFloat)
  642. index = getCurrentFloatTable()->add(value);
  643. switch (type)
  644. {
  645. case TypeReqUInt:
  646. codeStream.emit(OP_LOADIMMED_UINT);
  647. codeStream.emit(U32(value));
  648. break;
  649. case TypeReqString:
  650. codeStream.emit(OP_LOADIMMED_STR);
  651. codeStream.emit(index);
  652. break;
  653. case TypeReqFloat:
  654. codeStream.emit(OP_LOADIMMED_FLT);
  655. codeStream.emit(index);
  656. break;
  657. case TypeReqNone:
  658. break;
  659. }
  660. return codeStream.tell();
  661. }
  662. TypeReq FloatNode::getPreferredType()
  663. {
  664. return TypeReqFloat;
  665. }
  666. //------------------------------------------------------------
  667. U32 StrConstNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  668. {
  669. // Early out for documentation block.
  670. if (doc)
  671. {
  672. index = getCurrentStringTable()->add(str, true, tag);
  673. }
  674. else if (type == TypeReqString)
  675. {
  676. index = getCurrentStringTable()->add(str, true, tag);
  677. }
  678. else if (type != TypeReqNone)
  679. {
  680. fVal = consoleStringToNumber(str, dbgFileName, dbgLineNumber);
  681. if (type == TypeReqFloat)
  682. {
  683. index = getCurrentFloatTable()->add(fVal);
  684. }
  685. }
  686. // If this is a DOCBLOCK, then process w/ appropriate op...
  687. if (doc)
  688. {
  689. codeStream.emit(OP_DOCBLOCK_STR);
  690. codeStream.emit(index);
  691. return ip;
  692. }
  693. // Otherwise, deal with it normally as a string literal case.
  694. switch (type)
  695. {
  696. case TypeReqString:
  697. codeStream.emit(tag ? OP_TAG_TO_STR : OP_LOADIMMED_STR);
  698. codeStream.emit(index);
  699. break;
  700. case TypeReqUInt:
  701. codeStream.emit(OP_LOADIMMED_UINT);
  702. codeStream.emit(U32(fVal));
  703. break;
  704. case TypeReqFloat:
  705. codeStream.emit(OP_LOADIMMED_FLT);
  706. codeStream.emit(index);
  707. break;
  708. case TypeReqNone:
  709. break;
  710. }
  711. return codeStream.tell();
  712. }
  713. TypeReq StrConstNode::getPreferredType()
  714. {
  715. return TypeReqString;
  716. }
  717. //------------------------------------------------------------
  718. U32 ConstantNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  719. {
  720. if (type == TypeReqString)
  721. {
  722. precompileIdent(value);
  723. }
  724. else if (type != TypeReqNone)
  725. {
  726. fVal = consoleStringToNumber(value, dbgFileName, dbgLineNumber);
  727. if (type == TypeReqFloat)
  728. index = getCurrentFloatTable()->add(fVal);
  729. }
  730. switch (type)
  731. {
  732. case TypeReqString:
  733. codeStream.emit(OP_LOADIMMED_IDENT);
  734. codeStream.emitSTE(value);
  735. break;
  736. case TypeReqUInt:
  737. codeStream.emit(OP_LOADIMMED_UINT);
  738. codeStream.emit(U32(fVal));
  739. break;
  740. case TypeReqFloat:
  741. codeStream.emit(OP_LOADIMMED_FLT);
  742. codeStream.emit(index);
  743. break;
  744. case TypeReqNone:
  745. break;
  746. }
  747. return ip;
  748. }
  749. TypeReq ConstantNode::getPreferredType()
  750. {
  751. return TypeReqString;
  752. }
  753. //------------------------------------------------------------
  754. U32 AssignExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  755. {
  756. subType = expr->getPreferredType();
  757. if (subType == TypeReqNone)
  758. subType = type;
  759. if (subType == TypeReqNone)
  760. subType = TypeReqString;
  761. // if it's an array expr, the formula is:
  762. // eval expr
  763. // (push and pop if it's TypeReqString) OP_ADVANCE_STR
  764. // OP_LOADIMMED_IDENT
  765. // varName
  766. // OP_ADVANCE_STR
  767. // eval array
  768. // OP_REWIND_STR
  769. // OP_SETCURVAR_ARRAY_CREATE
  770. // OP_TERMINATE_REWIND_STR
  771. // OP_SAVEVAR
  772. //else
  773. // eval expr
  774. // OP_SETCURVAR_CREATE
  775. // varname
  776. // OP_SAVEVAR
  777. precompileIdent(varName);
  778. ip = expr->compile(codeStream, ip, subType);
  779. bool oldVariables = arrayIndex || varName[0] == '$';
  780. if (oldVariables)
  781. {
  782. if (arrayIndex)
  783. {
  784. //if (subType == TypeReqString)
  785. // codeStream.emit(OP_ADVANCE_STR);
  786. codeStream.emit(OP_LOADIMMED_IDENT);
  787. codeStream.emitSTE(varName);
  788. //codeStream.emit(OP_ADVANCE_STR);
  789. ip = arrayIndex->compile(codeStream, ip, TypeReqString);
  790. codeStream.emit(OP_REWIND_STR);
  791. codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
  792. if (type == TypeReqNone)
  793. codeStream.emit(OP_POP_STK);
  794. }
  795. else
  796. {
  797. codeStream.emit(OP_SETCURVAR_CREATE);
  798. codeStream.emitSTE(varName);
  799. }
  800. switch (subType)
  801. {
  802. case TypeReqString: codeStream.emit(OP_SAVEVAR_STR); break;
  803. case TypeReqUInt: codeStream.emit(OP_SAVEVAR_UINT); break;
  804. case TypeReqFloat: codeStream.emit(OP_SAVEVAR_FLT); break;
  805. }
  806. }
  807. else
  808. {
  809. switch (subType)
  810. {
  811. case TypeReqUInt: codeStream.emit(OP_SAVE_LOCAL_VAR_UINT); break;
  812. case TypeReqFloat: codeStream.emit(OP_SAVE_LOCAL_VAR_FLT); break;
  813. default: codeStream.emit(OP_SAVE_LOCAL_VAR_STR);
  814. }
  815. codeStream.emit(getFuncVars(dbgLineNumber)->assign(varName, subType == TypeReqNone ? TypeReqString : subType, dbgLineNumber));
  816. }
  817. if (type == TypeReqNone)
  818. codeStream.emit(OP_POP_STK);
  819. return ip;
  820. }
  821. TypeReq AssignExprNode::getPreferredType()
  822. {
  823. return expr->getPreferredType();
  824. }
  825. //------------------------------------------------------------
  826. static void getAssignOpTypeOp(S32 op, TypeReq& type, U32& operand)
  827. {
  828. switch (op)
  829. {
  830. case opPLUSPLUS:
  831. TORQUE_CASE_FALLTHROUGH;
  832. case '+':
  833. type = TypeReqFloat;
  834. operand = OP_ADD;
  835. break;
  836. case opMINUSMINUS:
  837. TORQUE_CASE_FALLTHROUGH;
  838. case '-':
  839. type = TypeReqFloat;
  840. operand = OP_SUB;
  841. break;
  842. case '*':
  843. type = TypeReqFloat;
  844. operand = OP_MUL;
  845. break;
  846. case '/':
  847. type = TypeReqFloat;
  848. operand = OP_DIV;
  849. break;
  850. case '%':
  851. type = TypeReqUInt;
  852. operand = OP_MOD;
  853. break;
  854. case '&':
  855. type = TypeReqUInt;
  856. operand = OP_BITAND;
  857. break;
  858. case '^':
  859. type = TypeReqUInt;
  860. operand = OP_XOR;
  861. break;
  862. case '|':
  863. type = TypeReqUInt;
  864. operand = OP_BITOR;
  865. break;
  866. case opSHL:
  867. type = TypeReqUInt;
  868. operand = OP_SHL;
  869. break;
  870. case opSHR:
  871. type = TypeReqUInt;
  872. operand = OP_SHR;
  873. break;
  874. default:
  875. AssertFatal(false, "Invalid opcode on operation expression");
  876. }
  877. }
  878. U32 AssignOpExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  879. {
  880. // goes like this...
  881. // eval expr as float or int
  882. // if there's an arrayIndex
  883. // OP_LOADIMMED_IDENT
  884. // varName
  885. // OP_ADVANCE_STR
  886. // eval arrayIndex stringwise
  887. // OP_REWIND_STR
  888. // OP_SETCURVAR_ARRAY_CREATE
  889. // else
  890. // OP_SETCURVAR_CREATE
  891. // varName
  892. // OP_LOADVAR_FLT or UINT
  893. // operand
  894. // OP_SAVEVAR_FLT or UINT
  895. // conversion OP if necessary.
  896. getAssignOpTypeOp(op, subType, operand);
  897. precompileIdent(varName);
  898. bool oldVariables = arrayIndex || varName[0] == '$';
  899. if (op == opPLUSPLUS && !oldVariables && type == TypeReqNone)
  900. {
  901. const S32 varIdx = getFuncVars(dbgLineNumber)->assign(varName, TypeReqFloat, dbgLineNumber);
  902. codeStream.emit(OP_INC);
  903. codeStream.emit(varIdx);
  904. }
  905. else
  906. {
  907. ip = expr->compile(codeStream, ip, subType);
  908. if (oldVariables)
  909. {
  910. if (!arrayIndex)
  911. {
  912. codeStream.emit(OP_SETCURVAR_CREATE);
  913. codeStream.emitSTE(varName);
  914. }
  915. else
  916. {
  917. codeStream.emit(OP_LOADIMMED_IDENT);
  918. codeStream.emitSTE(varName);
  919. //codeStream.emit(OP_ADVANCE_STR);
  920. ip = arrayIndex->compile(codeStream, ip, TypeReqString);
  921. codeStream.emit(OP_REWIND_STR);
  922. codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
  923. if (type == TypeReqNone)
  924. codeStream.emit(OP_POP_STK);
  925. }
  926. codeStream.emit((subType == TypeReqFloat) ? OP_LOADVAR_FLT : OP_LOADVAR_UINT);
  927. codeStream.emit(operand);
  928. codeStream.emit((subType == TypeReqFloat) ? OP_SAVEVAR_FLT : OP_SAVEVAR_UINT);
  929. }
  930. else
  931. {
  932. const bool isFloat = subType == TypeReqFloat;
  933. const S32 varIdx = getFuncVars(dbgLineNumber)->assign(varName, subType == TypeReqNone ? TypeReqString : subType, dbgLineNumber);
  934. codeStream.emit(isFloat ? OP_LOAD_LOCAL_VAR_FLT : OP_LOAD_LOCAL_VAR_UINT);
  935. codeStream.emit(varIdx);
  936. codeStream.emit(operand);
  937. codeStream.emit(isFloat ? OP_SAVE_LOCAL_VAR_FLT : OP_SAVE_LOCAL_VAR_UINT);
  938. codeStream.emit(varIdx);
  939. }
  940. if (type == TypeReqNone)
  941. codeStream.emit(OP_POP_STK);
  942. }
  943. return codeStream.tell();
  944. }
  945. TypeReq AssignOpExprNode::getPreferredType()
  946. {
  947. getAssignOpTypeOp(op, subType, operand);
  948. return subType;
  949. }
  950. //------------------------------------------------------------
  951. U32 TTagSetStmtNode::compileStmt(CodeStream&, U32 ip)
  952. {
  953. return ip;
  954. }
  955. //------------------------------------------------------------
  956. U32 TTagDerefNode::compile(CodeStream&, U32 ip, TypeReq)
  957. {
  958. return ip;
  959. }
  960. TypeReq TTagDerefNode::getPreferredType()
  961. {
  962. return TypeReqNone;
  963. }
  964. //------------------------------------------------------------
  965. U32 TTagExprNode::compile(CodeStream&, U32 ip, TypeReq)
  966. {
  967. return ip;
  968. }
  969. TypeReq TTagExprNode::getPreferredType()
  970. {
  971. return TypeReqNone;
  972. }
  973. //------------------------------------------------------------
  974. U32 FuncCallExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  975. {
  976. // OP_PUSH_FRAME
  977. // arg OP_PUSH arg OP_PUSH arg OP_PUSH
  978. // eval all the args, then call the function.
  979. // OP_CALLFUNC
  980. // function
  981. // namespace
  982. // isDot
  983. precompileIdent(funcName);
  984. precompileIdent(nameSpace);
  985. S32 count = 0;
  986. for (ExprNode* walk = args; walk; walk = static_cast<ExprNode*>(walk->getNext()))
  987. count++;
  988. codeStream.emit(OP_PUSH_FRAME);
  989. codeStream.emit(count);
  990. for (ExprNode* walk = args; walk; walk = static_cast<ExprNode*>(walk->getNext()))
  991. {
  992. TypeReq walkType = walk->getPreferredType();
  993. if (walkType == TypeReqNone)
  994. walkType = TypeReqString;
  995. ip = walk->compile(codeStream, ip, walkType);
  996. codeStream.emit(OP_PUSH);
  997. }
  998. codeStream.emit(OP_CALLFUNC);
  999. codeStream.emitSTE(funcName);
  1000. codeStream.emitSTE(nameSpace);
  1001. codeStream.emit(callType);
  1002. if (type == TypeReqNone)
  1003. codeStream.emit(OP_POP_STK);
  1004. return codeStream.tell();
  1005. }
  1006. TypeReq FuncCallExprNode::getPreferredType()
  1007. {
  1008. return TypeReqString;
  1009. }
  1010. //------------------------------------------------------------
  1011. U32 AssertCallExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  1012. {
  1013. #ifdef TORQUE_ENABLE_SCRIPTASSERTS
  1014. messageIndex = getCurrentStringTable()->add(message, true, false);
  1015. ip = testExpr->compile(codeStream, ip, TypeReqUInt);
  1016. codeStream.emit(OP_ASSERT);
  1017. codeStream.emit(messageIndex);
  1018. #endif
  1019. return codeStream.tell();
  1020. }
  1021. TypeReq AssertCallExprNode::getPreferredType()
  1022. {
  1023. return TypeReqNone;
  1024. }
  1025. //------------------------------------------------------------
  1026. U32 SlotAccessNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  1027. {
  1028. if (type == TypeReqNone)
  1029. return ip;
  1030. precompileIdent(slotName);
  1031. if (arrayExpr)
  1032. {
  1033. ip = arrayExpr->compile(codeStream, ip, TypeReqString);
  1034. }
  1035. ip = objectExpr->compile(codeStream, ip, TypeReqString);
  1036. codeStream.emit(OP_SETCUROBJECT);
  1037. codeStream.emit(OP_SETCURFIELD);
  1038. codeStream.emitSTE(slotName);
  1039. codeStream.emit(OP_POP_STK);
  1040. if (arrayExpr)
  1041. {
  1042. codeStream.emit(OP_SETCURFIELD_ARRAY);
  1043. codeStream.emit(OP_POP_STK);
  1044. }
  1045. switch (type)
  1046. {
  1047. case TypeReqUInt:
  1048. codeStream.emit(OP_LOADFIELD_UINT);
  1049. break;
  1050. case TypeReqFloat:
  1051. codeStream.emit(OP_LOADFIELD_FLT);
  1052. break;
  1053. case TypeReqString:
  1054. codeStream.emit(OP_LOADFIELD_STR);
  1055. break;
  1056. case TypeReqNone:
  1057. break;
  1058. }
  1059. return codeStream.tell();
  1060. }
  1061. TypeReq SlotAccessNode::getPreferredType()
  1062. {
  1063. return TypeReqNone;
  1064. }
  1065. //-----------------------------------------------------------------------------
  1066. U32 InternalSlotAccessNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  1067. {
  1068. if (type == TypeReqNone)
  1069. return ip;
  1070. ip = objectExpr->compile(codeStream, ip, TypeReqString);
  1071. codeStream.emit(OP_SETCUROBJECT);
  1072. // we pop the stack as we will override the current object with the internal object
  1073. codeStream.emit(OP_POP_STK);
  1074. ip = slotExpr->compile(codeStream, ip, TypeReqString);
  1075. codeStream.emit(OP_SETCUROBJECT_INTERNAL);
  1076. codeStream.emit(recurse);
  1077. return codeStream.tell();
  1078. }
  1079. TypeReq InternalSlotAccessNode::getPreferredType()
  1080. {
  1081. return TypeReqUInt;
  1082. }
  1083. //-----------------------------------------------------------------------------
  1084. U32 SlotAssignNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  1085. {
  1086. precompileIdent(slotName);
  1087. ip = valueExpr->compile(codeStream, ip, TypeReqString);
  1088. if (arrayExpr)
  1089. {
  1090. ip = arrayExpr->compile(codeStream, ip, TypeReqString);
  1091. }
  1092. if (objectExpr)
  1093. {
  1094. ip = objectExpr->compile(codeStream, ip, TypeReqString);
  1095. codeStream.emit(OP_SETCUROBJECT);
  1096. }
  1097. else
  1098. codeStream.emit(OP_SETCUROBJECT_NEW);
  1099. codeStream.emit(OP_SETCURFIELD);
  1100. codeStream.emitSTE(slotName);
  1101. if (objectExpr)
  1102. {
  1103. // Don't pop unless we are assigning a field to an object
  1104. // (For initializer fields, we don't wanna pop)
  1105. codeStream.emit(OP_POP_STK);
  1106. }
  1107. if (arrayExpr)
  1108. {
  1109. codeStream.emit(OP_SETCURFIELD_ARRAY);
  1110. codeStream.emit(OP_POP_STK);
  1111. }
  1112. codeStream.emit(OP_SAVEFIELD_STR);
  1113. if (typeID != -1)
  1114. {
  1115. codeStream.emit(OP_SETCURFIELD_TYPE);
  1116. codeStream.emit(typeID);
  1117. }
  1118. if (type == TypeReqNone)
  1119. codeStream.emit(OP_POP_STK);
  1120. return codeStream.tell();
  1121. }
  1122. TypeReq SlotAssignNode::getPreferredType()
  1123. {
  1124. return TypeReqString;
  1125. }
  1126. //------------------------------------------------------------
  1127. U32 SlotAssignOpNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  1128. {
  1129. // first eval the expression as its type
  1130. // if it's an array:
  1131. // eval array
  1132. // OP_ADVANCE_STR
  1133. // evaluate object expr
  1134. // OP_SETCUROBJECT
  1135. // OP_SETCURFIELD
  1136. // fieldName
  1137. // OP_TERMINATE_REWIND_STR
  1138. // OP_SETCURFIELDARRAY
  1139. // else
  1140. // evaluate object expr
  1141. // OP_SETCUROBJECT
  1142. // OP_SETCURFIELD
  1143. // fieldName
  1144. // OP_LOADFIELD of appropriate type
  1145. // operand
  1146. // OP_SAVEFIELD of appropriate type
  1147. // convert to return type if necessary.
  1148. getAssignOpTypeOp(op, subType, operand);
  1149. precompileIdent(slotName);
  1150. ip = valueExpr->compile(codeStream, ip, subType);
  1151. if (arrayExpr)
  1152. {
  1153. ip = arrayExpr->compile(codeStream, ip, TypeReqString);
  1154. }
  1155. ip = objectExpr->compile(codeStream, ip, TypeReqString);
  1156. codeStream.emit(OP_SETCUROBJECT);
  1157. codeStream.emit(OP_SETCURFIELD);
  1158. codeStream.emitSTE(slotName);
  1159. codeStream.emit(OP_POP_STK);
  1160. if (arrayExpr)
  1161. {
  1162. codeStream.emit(OP_SETCURFIELD_ARRAY);
  1163. if (subType == TypeReqNone || type == TypeReqNone)
  1164. codeStream.emit(OP_POP_STK);
  1165. }
  1166. codeStream.emit((subType == TypeReqFloat) ? OP_LOADFIELD_FLT : OP_LOADFIELD_UINT);
  1167. codeStream.emit(operand);
  1168. codeStream.emit((subType == TypeReqFloat) ? OP_SAVEFIELD_FLT : OP_SAVEFIELD_UINT);
  1169. if (type == TypeReqNone)
  1170. codeStream.emit(OP_POP_STK);
  1171. return codeStream.tell();
  1172. }
  1173. TypeReq SlotAssignOpNode::getPreferredType()
  1174. {
  1175. getAssignOpTypeOp(op, subType, operand);
  1176. return subType;
  1177. }
  1178. //------------------------------------------------------------
  1179. U32 ObjectDeclNode::compileSubObject(CodeStream& codeStream, U32 ip, bool root)
  1180. {
  1181. // goes
  1182. // OP_PUSHFRAME 1
  1183. // name expr
  1184. // OP_PUSH 1
  1185. // args... PUSH
  1186. // OP_CREATE_OBJECT 1
  1187. // parentObject 1
  1188. // isDatablock 1
  1189. // internalName 1
  1190. // isSingleton 1
  1191. // lineNumber 1
  1192. // fail point 1
  1193. // for each field, eval
  1194. // OP_ADD_OBJECT (to UINT[0]) 1
  1195. // root? 1
  1196. // add all the sub objects.
  1197. // OP_END_OBJECT 1
  1198. // root? 1
  1199. // To fix the stack issue [7/9/2007 Black]
  1200. // OP_FINISH_OBJECT <-- fail point jumps to this opcode
  1201. S32 count = 2; // 2 OP_PUSH's
  1202. for (ExprNode* exprWalk = argList; exprWalk; exprWalk = (ExprNode*)exprWalk->getNext())
  1203. count++;
  1204. codeStream.emit(OP_PUSH_FRAME);
  1205. codeStream.emit(count);
  1206. ip = classNameExpr->compile(codeStream, ip, TypeReqString);
  1207. codeStream.emit(OP_PUSH);
  1208. ip = objectNameExpr->compile(codeStream, ip, TypeReqString);
  1209. codeStream.emit(OP_PUSH);
  1210. for (ExprNode* exprWalk = argList; exprWalk; exprWalk = (ExprNode*)exprWalk->getNext())
  1211. {
  1212. TypeReq walkType = exprWalk->getPreferredType();
  1213. if (walkType == TypeReqNone) walkType = TypeReqString;
  1214. ip = exprWalk->compile(codeStream, ip, walkType);
  1215. codeStream.emit(OP_PUSH);
  1216. }
  1217. codeStream.emit(OP_CREATE_OBJECT);
  1218. codeStream.emitSTE(parentObject);
  1219. codeStream.emit(isDatablock);
  1220. codeStream.emit(isClassNameInternal);
  1221. codeStream.emit(isSingleton);
  1222. codeStream.emit(dbgLineNumber);
  1223. const U32 failIp = codeStream.emit(0);
  1224. for (SlotAssignNode* slotWalk = slotDecls; slotWalk; slotWalk = (SlotAssignNode*)slotWalk->getNext())
  1225. ip = slotWalk->compile(codeStream, ip, TypeReqNone);
  1226. codeStream.emit(OP_ADD_OBJECT);
  1227. codeStream.emit(root);
  1228. for (ObjectDeclNode* objectWalk = subObjects; objectWalk; objectWalk = (ObjectDeclNode*)objectWalk->getNext())
  1229. ip = objectWalk->compileSubObject(codeStream, ip, false);
  1230. codeStream.emit(OP_END_OBJECT);
  1231. codeStream.emit(root || isDatablock);
  1232. // Added to fix the object creation issue [7/9/2007 Black]
  1233. failOffset = codeStream.emit(OP_FINISH_OBJECT);
  1234. codeStream.patch(failIp, failOffset);
  1235. return codeStream.tell();
  1236. }
  1237. U32 ObjectDeclNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  1238. {
  1239. // root object decl does:
  1240. // push 0 onto the UINT stack OP_LOADIMMED_UINT
  1241. // precompiles the subObject(true)
  1242. // UINT stack now has object id
  1243. // type conv to type
  1244. codeStream.emit(OP_LOADIMMED_UINT);
  1245. codeStream.emit(0);
  1246. ip = compileSubObject(codeStream, ip, true);
  1247. if (type == TypeReqNone)
  1248. codeStream.emit(OP_POP_STK);
  1249. return codeStream.tell();
  1250. }
  1251. TypeReq ObjectDeclNode::getPreferredType()
  1252. {
  1253. return TypeReqUInt;
  1254. }
  1255. //------------------------------------------------------------
  1256. U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
  1257. {
  1258. // OP_FUNC_DECL
  1259. // func name
  1260. // namespace
  1261. // package
  1262. // hasBody?
  1263. // func end ip
  1264. // argc
  1265. // ident array[argc]
  1266. // code
  1267. // OP_RETURN_VOID
  1268. setCurrentStringTable(&getFunctionStringTable());
  1269. setCurrentFloatTable(&getFunctionFloatTable());
  1270. FuncVars vars;
  1271. gFuncVars = &vars;
  1272. argc = 0;
  1273. for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext())
  1274. {
  1275. precompileIdent(walk->varName);
  1276. getFuncVars(dbgLineNumber)->assign(walk->varName, TypeReqNone, dbgLineNumber);
  1277. argc++;
  1278. }
  1279. CodeBlock::smInFunction = true;
  1280. precompileIdent(fnName);
  1281. precompileIdent(nameSpace);
  1282. precompileIdent(package);
  1283. CodeBlock::smInFunction = false;
  1284. codeStream.emit(OP_FUNC_DECL);
  1285. codeStream.emitSTE(fnName);
  1286. codeStream.emitSTE(nameSpace);
  1287. codeStream.emitSTE(package);
  1288. codeStream.emit(U32(bool(stmts != NULL) ? 1 : 0) + U32(dbgLineNumber << 1));
  1289. const U32 endIp = codeStream.emit(0);
  1290. codeStream.emit(argc);
  1291. const U32 localNumVarsIP = codeStream.emit(0);
  1292. for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext())
  1293. {
  1294. StringTableEntry name = walk->varName;
  1295. codeStream.emit(getFuncVars(dbgLineNumber)->lookup(name, dbgLineNumber));
  1296. }
  1297. CodeBlock::smInFunction = true;
  1298. ip = compileBlock(stmts, codeStream, ip);
  1299. // Add break so breakpoint can be set at closing brace or
  1300. // in empty function.
  1301. addBreakLine(codeStream);
  1302. CodeBlock::smInFunction = false;
  1303. codeStream.emit(OP_RETURN_VOID);
  1304. codeStream.patch(localNumVarsIP, getFuncVars(dbgLineNumber)->count());
  1305. codeStream.patch(endIp, codeStream.tell());
  1306. setCurrentStringTable(&getGlobalStringTable());
  1307. setCurrentFloatTable(&getGlobalFloatTable());
  1308. // map local variables to registers for this function.
  1309. // Note we have to map these in order because the table itself is ordered by the register id.
  1310. CompilerLocalVariableToRegisterMappingTable* tbl = &getFunctionVariableMappingTable();
  1311. for (S32 i = 0; i < gFuncVars->variableNameMap.size(); ++i)
  1312. {
  1313. StringTableEntry varName = gFuncVars->variableNameMap[i];
  1314. tbl->add(fnName, nameSpace, varName);
  1315. }
  1316. gFuncVars = gIsEvalCompile ? &gEvalFuncVars : &gGlobalScopeFuncVars;
  1317. return ip;
  1318. }