astNodes.cpp 39 KB

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