astNodes.cpp 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574
  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. default: break;
  806. }
  807. }
  808. else
  809. {
  810. switch (subType)
  811. {
  812. case TypeReqUInt: codeStream.emit(OP_SAVE_LOCAL_VAR_UINT); break;
  813. case TypeReqFloat: codeStream.emit(OP_SAVE_LOCAL_VAR_FLT); break;
  814. default: codeStream.emit(OP_SAVE_LOCAL_VAR_STR);
  815. }
  816. codeStream.emit(getFuncVars(dbgLineNumber)->assign(varName, subType == TypeReqNone ? TypeReqString : subType, dbgLineNumber));
  817. }
  818. if (type == TypeReqNone)
  819. codeStream.emit(OP_POP_STK);
  820. return ip;
  821. }
  822. TypeReq AssignExprNode::getPreferredType()
  823. {
  824. return expr->getPreferredType();
  825. }
  826. //------------------------------------------------------------
  827. static void getAssignOpTypeOp(S32 op, TypeReq& type, U32& operand)
  828. {
  829. switch (op)
  830. {
  831. case opPLUSPLUS:
  832. TORQUE_CASE_FALLTHROUGH;
  833. case '+':
  834. type = TypeReqFloat;
  835. operand = OP_ADD;
  836. break;
  837. case opMINUSMINUS:
  838. TORQUE_CASE_FALLTHROUGH;
  839. case '-':
  840. type = TypeReqFloat;
  841. operand = OP_SUB;
  842. break;
  843. case '*':
  844. type = TypeReqFloat;
  845. operand = OP_MUL;
  846. break;
  847. case '/':
  848. type = TypeReqFloat;
  849. operand = OP_DIV;
  850. break;
  851. case '%':
  852. type = TypeReqUInt;
  853. operand = OP_MOD;
  854. break;
  855. case '&':
  856. type = TypeReqUInt;
  857. operand = OP_BITAND;
  858. break;
  859. case '^':
  860. type = TypeReqUInt;
  861. operand = OP_XOR;
  862. break;
  863. case '|':
  864. type = TypeReqUInt;
  865. operand = OP_BITOR;
  866. break;
  867. case opSHL:
  868. type = TypeReqUInt;
  869. operand = OP_SHL;
  870. break;
  871. case opSHR:
  872. type = TypeReqUInt;
  873. operand = OP_SHR;
  874. break;
  875. default:
  876. AssertFatal(false, "Invalid opcode on operation expression");
  877. }
  878. }
  879. U32 AssignOpExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  880. {
  881. // goes like this...
  882. // eval expr as float or int
  883. // if there's an arrayIndex
  884. // OP_LOADIMMED_IDENT
  885. // varName
  886. // OP_ADVANCE_STR
  887. // eval arrayIndex stringwise
  888. // OP_REWIND_STR
  889. // OP_SETCURVAR_ARRAY_CREATE
  890. // else
  891. // OP_SETCURVAR_CREATE
  892. // varName
  893. // OP_LOADVAR_FLT or UINT
  894. // operand
  895. // OP_SAVEVAR_FLT or UINT
  896. // conversion OP if necessary.
  897. getAssignOpTypeOp(op, subType, operand);
  898. precompileIdent(varName);
  899. bool oldVariables = arrayIndex || varName[0] == '$';
  900. if (op == opPLUSPLUS && !oldVariables && type == TypeReqNone)
  901. {
  902. const S32 varIdx = getFuncVars(dbgLineNumber)->assign(varName, TypeReqFloat, dbgLineNumber);
  903. codeStream.emit(OP_INC);
  904. codeStream.emit(varIdx);
  905. }
  906. else
  907. {
  908. ip = expr->compile(codeStream, ip, subType);
  909. if (oldVariables)
  910. {
  911. if (!arrayIndex)
  912. {
  913. codeStream.emit(OP_SETCURVAR_CREATE);
  914. codeStream.emitSTE(varName);
  915. }
  916. else
  917. {
  918. codeStream.emit(OP_LOADIMMED_IDENT);
  919. codeStream.emitSTE(varName);
  920. //codeStream.emit(OP_ADVANCE_STR);
  921. ip = arrayIndex->compile(codeStream, ip, TypeReqString);
  922. codeStream.emit(OP_REWIND_STR);
  923. codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
  924. if (type == TypeReqNone)
  925. codeStream.emit(OP_POP_STK);
  926. }
  927. codeStream.emit((subType == TypeReqFloat) ? OP_LOADVAR_FLT : OP_LOADVAR_UINT);
  928. codeStream.emit(operand);
  929. codeStream.emit((subType == TypeReqFloat) ? OP_SAVEVAR_FLT : OP_SAVEVAR_UINT);
  930. }
  931. else
  932. {
  933. const bool isFloat = subType == TypeReqFloat;
  934. const S32 varIdx = getFuncVars(dbgLineNumber)->assign(varName, subType == TypeReqNone ? TypeReqString : subType, dbgLineNumber);
  935. codeStream.emit(isFloat ? OP_LOAD_LOCAL_VAR_FLT : OP_LOAD_LOCAL_VAR_UINT);
  936. codeStream.emit(varIdx);
  937. codeStream.emit(operand);
  938. codeStream.emit(isFloat ? OP_SAVE_LOCAL_VAR_FLT : OP_SAVE_LOCAL_VAR_UINT);
  939. codeStream.emit(varIdx);
  940. }
  941. if (type == TypeReqNone)
  942. codeStream.emit(OP_POP_STK);
  943. }
  944. return codeStream.tell();
  945. }
  946. TypeReq AssignOpExprNode::getPreferredType()
  947. {
  948. getAssignOpTypeOp(op, subType, operand);
  949. return subType;
  950. }
  951. //------------------------------------------------------------
  952. U32 TTagSetStmtNode::compileStmt(CodeStream&, U32 ip)
  953. {
  954. return ip;
  955. }
  956. //------------------------------------------------------------
  957. U32 TTagDerefNode::compile(CodeStream&, U32 ip, TypeReq)
  958. {
  959. return ip;
  960. }
  961. TypeReq TTagDerefNode::getPreferredType()
  962. {
  963. return TypeReqNone;
  964. }
  965. //------------------------------------------------------------
  966. U32 TTagExprNode::compile(CodeStream&, U32 ip, TypeReq)
  967. {
  968. return ip;
  969. }
  970. TypeReq TTagExprNode::getPreferredType()
  971. {
  972. return TypeReqNone;
  973. }
  974. //------------------------------------------------------------
  975. U32 FuncCallExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  976. {
  977. // OP_PUSH_FRAME
  978. // arg OP_PUSH arg OP_PUSH arg OP_PUSH
  979. // eval all the args, then call the function.
  980. // OP_CALLFUNC
  981. // function
  982. // namespace
  983. // isDot
  984. precompileIdent(funcName);
  985. precompileIdent(nameSpace);
  986. S32 count = 0;
  987. for (ExprNode* walk = args; walk; walk = static_cast<ExprNode*>(walk->getNext()))
  988. count++;
  989. codeStream.emit(OP_PUSH_FRAME);
  990. codeStream.emit(count);
  991. for (ExprNode* walk = args; walk; walk = static_cast<ExprNode*>(walk->getNext()))
  992. {
  993. TypeReq walkType = walk->getPreferredType();
  994. if (walkType == TypeReqNone)
  995. walkType = TypeReqString;
  996. ip = walk->compile(codeStream, ip, walkType);
  997. codeStream.emit(OP_PUSH);
  998. }
  999. codeStream.emit(OP_CALLFUNC);
  1000. codeStream.emitSTE(funcName);
  1001. codeStream.emitSTE(nameSpace);
  1002. codeStream.emit(callType);
  1003. if (type == TypeReqNone)
  1004. codeStream.emit(OP_POP_STK);
  1005. return codeStream.tell();
  1006. }
  1007. TypeReq FuncCallExprNode::getPreferredType()
  1008. {
  1009. return TypeReqString;
  1010. }
  1011. //------------------------------------------------------------
  1012. U32 AssertCallExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  1013. {
  1014. #ifdef TORQUE_ENABLE_SCRIPTASSERTS
  1015. messageIndex = getCurrentStringTable()->add(message, true, false);
  1016. ip = testExpr->compile(codeStream, ip, TypeReqUInt);
  1017. codeStream.emit(OP_ASSERT);
  1018. codeStream.emit(messageIndex);
  1019. #endif
  1020. return codeStream.tell();
  1021. }
  1022. TypeReq AssertCallExprNode::getPreferredType()
  1023. {
  1024. return TypeReqNone;
  1025. }
  1026. //------------------------------------------------------------
  1027. U32 SlotAccessNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  1028. {
  1029. if (type == TypeReqNone)
  1030. return ip;
  1031. precompileIdent(slotName);
  1032. if (arrayExpr)
  1033. {
  1034. ip = arrayExpr->compile(codeStream, ip, TypeReqString);
  1035. }
  1036. ip = objectExpr->compile(codeStream, ip, TypeReqString);
  1037. codeStream.emit(OP_SETCUROBJECT);
  1038. codeStream.emit(OP_SETCURFIELD);
  1039. codeStream.emitSTE(slotName);
  1040. codeStream.emit(OP_POP_STK);
  1041. if (arrayExpr)
  1042. {
  1043. codeStream.emit(OP_SETCURFIELD_ARRAY);
  1044. codeStream.emit(OP_POP_STK);
  1045. }
  1046. switch (type)
  1047. {
  1048. case TypeReqUInt:
  1049. codeStream.emit(OP_LOADFIELD_UINT);
  1050. break;
  1051. case TypeReqFloat:
  1052. codeStream.emit(OP_LOADFIELD_FLT);
  1053. break;
  1054. case TypeReqString:
  1055. codeStream.emit(OP_LOADFIELD_STR);
  1056. break;
  1057. case TypeReqNone:
  1058. break;
  1059. }
  1060. return codeStream.tell();
  1061. }
  1062. TypeReq SlotAccessNode::getPreferredType()
  1063. {
  1064. return TypeReqNone;
  1065. }
  1066. //-----------------------------------------------------------------------------
  1067. U32 InternalSlotAccessNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  1068. {
  1069. if (type == TypeReqNone)
  1070. return ip;
  1071. ip = objectExpr->compile(codeStream, ip, TypeReqString);
  1072. codeStream.emit(OP_SETCUROBJECT);
  1073. // we pop the stack as we will override the current object with the internal object
  1074. codeStream.emit(OP_POP_STK);
  1075. ip = slotExpr->compile(codeStream, ip, TypeReqString);
  1076. codeStream.emit(OP_SETCUROBJECT_INTERNAL);
  1077. codeStream.emit(recurse);
  1078. return codeStream.tell();
  1079. }
  1080. TypeReq InternalSlotAccessNode::getPreferredType()
  1081. {
  1082. return TypeReqUInt;
  1083. }
  1084. //-----------------------------------------------------------------------------
  1085. U32 SlotAssignNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  1086. {
  1087. precompileIdent(slotName);
  1088. ip = valueExpr->compile(codeStream, ip, TypeReqString);
  1089. if (arrayExpr)
  1090. {
  1091. ip = arrayExpr->compile(codeStream, ip, TypeReqString);
  1092. }
  1093. if (objectExpr)
  1094. {
  1095. ip = objectExpr->compile(codeStream, ip, TypeReqString);
  1096. codeStream.emit(OP_SETCUROBJECT);
  1097. }
  1098. else
  1099. codeStream.emit(OP_SETCUROBJECT_NEW);
  1100. codeStream.emit(OP_SETCURFIELD);
  1101. codeStream.emitSTE(slotName);
  1102. if (objectExpr)
  1103. {
  1104. // Don't pop unless we are assigning a field to an object
  1105. // (For initializer fields, we don't wanna pop)
  1106. codeStream.emit(OP_POP_STK);
  1107. }
  1108. if (arrayExpr)
  1109. {
  1110. codeStream.emit(OP_SETCURFIELD_ARRAY);
  1111. codeStream.emit(OP_POP_STK);
  1112. }
  1113. codeStream.emit(OP_SAVEFIELD_STR);
  1114. if (typeID != -1)
  1115. {
  1116. codeStream.emit(OP_SETCURFIELD_TYPE);
  1117. codeStream.emit(typeID);
  1118. }
  1119. if (type == TypeReqNone)
  1120. codeStream.emit(OP_POP_STK);
  1121. return codeStream.tell();
  1122. }
  1123. TypeReq SlotAssignNode::getPreferredType()
  1124. {
  1125. return TypeReqString;
  1126. }
  1127. //------------------------------------------------------------
  1128. U32 SlotAssignOpNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  1129. {
  1130. // first eval the expression as its type
  1131. // if it's an array:
  1132. // eval array
  1133. // OP_ADVANCE_STR
  1134. // evaluate object expr
  1135. // OP_SETCUROBJECT
  1136. // OP_SETCURFIELD
  1137. // fieldName
  1138. // OP_TERMINATE_REWIND_STR
  1139. // OP_SETCURFIELDARRAY
  1140. // else
  1141. // evaluate object expr
  1142. // OP_SETCUROBJECT
  1143. // OP_SETCURFIELD
  1144. // fieldName
  1145. // OP_LOADFIELD of appropriate type
  1146. // operand
  1147. // OP_SAVEFIELD of appropriate type
  1148. // convert to return type if necessary.
  1149. getAssignOpTypeOp(op, subType, operand);
  1150. precompileIdent(slotName);
  1151. ip = valueExpr->compile(codeStream, ip, subType);
  1152. if (arrayExpr)
  1153. {
  1154. ip = arrayExpr->compile(codeStream, ip, TypeReqString);
  1155. }
  1156. ip = objectExpr->compile(codeStream, ip, TypeReqString);
  1157. codeStream.emit(OP_SETCUROBJECT);
  1158. codeStream.emit(OP_SETCURFIELD);
  1159. codeStream.emitSTE(slotName);
  1160. codeStream.emit(OP_POP_STK);
  1161. if (arrayExpr)
  1162. {
  1163. codeStream.emit(OP_SETCURFIELD_ARRAY);
  1164. if (subType == TypeReqNone || type == TypeReqNone)
  1165. codeStream.emit(OP_POP_STK);
  1166. }
  1167. codeStream.emit((subType == TypeReqFloat) ? OP_LOADFIELD_FLT : OP_LOADFIELD_UINT);
  1168. codeStream.emit(operand);
  1169. codeStream.emit((subType == TypeReqFloat) ? OP_SAVEFIELD_FLT : OP_SAVEFIELD_UINT);
  1170. if (type == TypeReqNone)
  1171. codeStream.emit(OP_POP_STK);
  1172. return codeStream.tell();
  1173. }
  1174. TypeReq SlotAssignOpNode::getPreferredType()
  1175. {
  1176. getAssignOpTypeOp(op, subType, operand);
  1177. return subType;
  1178. }
  1179. //------------------------------------------------------------
  1180. U32 ObjectDeclNode::compileSubObject(CodeStream& codeStream, U32 ip, bool root)
  1181. {
  1182. // goes
  1183. // OP_PUSHFRAME 1
  1184. // name expr
  1185. // OP_PUSH 1
  1186. // args... PUSH
  1187. // OP_CREATE_OBJECT 1
  1188. // parentObject 1
  1189. // isDatablock 1
  1190. // internalName 1
  1191. // isSingleton 1
  1192. // lineNumber 1
  1193. // fail point 1
  1194. // for each field, eval
  1195. // OP_ADD_OBJECT (to UINT[0]) 1
  1196. // root? 1
  1197. // add all the sub objects.
  1198. // OP_END_OBJECT 1
  1199. // root? 1
  1200. // To fix the stack issue [7/9/2007 Black]
  1201. // OP_FINISH_OBJECT <-- fail point jumps to this opcode
  1202. S32 count = 2; // 2 OP_PUSH's
  1203. for (ExprNode* exprWalk = argList; exprWalk; exprWalk = (ExprNode*)exprWalk->getNext())
  1204. count++;
  1205. codeStream.emit(OP_PUSH_FRAME);
  1206. codeStream.emit(count);
  1207. ip = classNameExpr->compile(codeStream, ip, TypeReqString);
  1208. codeStream.emit(OP_PUSH);
  1209. ip = objectNameExpr->compile(codeStream, ip, TypeReqString);
  1210. codeStream.emit(OP_PUSH);
  1211. for (ExprNode* exprWalk = argList; exprWalk; exprWalk = (ExprNode*)exprWalk->getNext())
  1212. {
  1213. TypeReq walkType = exprWalk->getPreferredType();
  1214. if (walkType == TypeReqNone) walkType = TypeReqString;
  1215. ip = exprWalk->compile(codeStream, ip, walkType);
  1216. codeStream.emit(OP_PUSH);
  1217. }
  1218. codeStream.emit(OP_CREATE_OBJECT);
  1219. codeStream.emitSTE(parentObject);
  1220. codeStream.emit(isDatablock);
  1221. codeStream.emit(isClassNameInternal);
  1222. codeStream.emit(isSingleton);
  1223. codeStream.emit(dbgLineNumber);
  1224. const U32 failIp = codeStream.emit(0);
  1225. for (SlotAssignNode* slotWalk = slotDecls; slotWalk; slotWalk = (SlotAssignNode*)slotWalk->getNext())
  1226. ip = slotWalk->compile(codeStream, ip, TypeReqNone);
  1227. codeStream.emit(OP_ADD_OBJECT);
  1228. codeStream.emit(root);
  1229. for (ObjectDeclNode* objectWalk = subObjects; objectWalk; objectWalk = (ObjectDeclNode*)objectWalk->getNext())
  1230. ip = objectWalk->compileSubObject(codeStream, ip, false);
  1231. codeStream.emit(OP_END_OBJECT);
  1232. codeStream.emit(root || isDatablock);
  1233. // Added to fix the object creation issue [7/9/2007 Black]
  1234. failOffset = codeStream.emit(OP_FINISH_OBJECT);
  1235. codeStream.patch(failIp, failOffset);
  1236. return codeStream.tell();
  1237. }
  1238. U32 ObjectDeclNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
  1239. {
  1240. // root object decl does:
  1241. // push 0 onto the UINT stack OP_LOADIMMED_UINT
  1242. // precompiles the subObject(true)
  1243. // UINT stack now has object id
  1244. // type conv to type
  1245. codeStream.emit(OP_LOADIMMED_UINT);
  1246. codeStream.emit(0);
  1247. ip = compileSubObject(codeStream, ip, true);
  1248. if (type == TypeReqNone)
  1249. codeStream.emit(OP_POP_STK);
  1250. return codeStream.tell();
  1251. }
  1252. TypeReq ObjectDeclNode::getPreferredType()
  1253. {
  1254. return TypeReqUInt;
  1255. }
  1256. //------------------------------------------------------------
  1257. U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
  1258. {
  1259. // OP_FUNC_DECL
  1260. // func name
  1261. // namespace
  1262. // package
  1263. // hasBody?
  1264. // func end ip
  1265. // argc
  1266. // ident array[argc]
  1267. // code
  1268. // OP_RETURN_VOID
  1269. setCurrentStringTable(&getFunctionStringTable());
  1270. setCurrentFloatTable(&getFunctionFloatTable());
  1271. FuncVars vars;
  1272. gFuncVars = &vars;
  1273. argc = 0;
  1274. for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext())
  1275. {
  1276. precompileIdent(walk->varName);
  1277. getFuncVars(dbgLineNumber)->assign(walk->varName, TypeReqNone, dbgLineNumber);
  1278. argc++;
  1279. }
  1280. CodeBlock::smInFunction = true;
  1281. precompileIdent(fnName);
  1282. precompileIdent(nameSpace);
  1283. precompileIdent(package);
  1284. CodeBlock::smInFunction = false;
  1285. codeStream.emit(OP_FUNC_DECL);
  1286. codeStream.emitSTE(fnName);
  1287. codeStream.emitSTE(nameSpace);
  1288. codeStream.emitSTE(package);
  1289. codeStream.emit(U32(bool(stmts != NULL) ? 1 : 0) + U32(dbgLineNumber << 1));
  1290. const U32 endIp = codeStream.emit(0);
  1291. codeStream.emit(argc);
  1292. const U32 localNumVarsIP = codeStream.emit(0);
  1293. for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext())
  1294. {
  1295. StringTableEntry name = walk->varName;
  1296. codeStream.emit(getFuncVars(dbgLineNumber)->lookup(name, dbgLineNumber));
  1297. }
  1298. CodeBlock::smInFunction = true;
  1299. ip = compileBlock(stmts, codeStream, ip);
  1300. // Add break so breakpoint can be set at closing brace or
  1301. // in empty function.
  1302. addBreakLine(codeStream);
  1303. CodeBlock::smInFunction = false;
  1304. codeStream.emit(OP_RETURN_VOID);
  1305. codeStream.patch(localNumVarsIP, getFuncVars(dbgLineNumber)->count());
  1306. codeStream.patch(endIp, codeStream.tell());
  1307. setCurrentStringTable(&getGlobalStringTable());
  1308. setCurrentFloatTable(&getGlobalFloatTable());
  1309. // map local variables to registers for this function.
  1310. // Note we have to map these in order because the table itself is ordered by the register id.
  1311. CompilerLocalVariableToRegisterMappingTable* tbl = &getFunctionVariableMappingTable();
  1312. for (S32 i = 0; i < gFuncVars->variableNameMap.size(); ++i)
  1313. {
  1314. StringTableEntry varName = gFuncVars->variableNameMap[i];
  1315. tbl->add(fnName, nameSpace, varName);
  1316. }
  1317. gFuncVars = gIsEvalCompile ? &gEvalFuncVars : &gGlobalScopeFuncVars;
  1318. return ip;
  1319. }