astNodes.cpp 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941
  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. ip = walk->compileStmt(codeStream, ip);
  45. return codeStream.tell();
  46. }
  47. inline bool isSimpleVarLookup(ExprNode *arrayExpr, StringTableEntry &varName)
  48. {
  49. if (arrayExpr == nullptr)
  50. {
  51. varName = StringTable->insert("");
  52. return false;
  53. }
  54. // No double arrays allowed for optimization.
  55. VarNode *var = dynamic_cast<VarNode*>(arrayExpr);
  56. if (var && !var->arrayIndex)
  57. {
  58. StringTableEntry arrayVar = StringTable->insert(var->varName);
  59. precompileIdent(arrayVar);
  60. varName = arrayVar;
  61. return true;
  62. }
  63. return false;
  64. }
  65. // Do not allow 'recursive' %this optimizations. It can lead to weird bytecode
  66. // generation since we can only optimize one expression at a time.
  67. static bool OnlyOneThisOptimization = false;
  68. inline bool isThisVar(ExprNode *objectExpr)
  69. {
  70. // If we are currently optimizing a this var, don't allow extra optimization.
  71. if (objectExpr == nullptr || OnlyOneThisOptimization)
  72. return false;
  73. VarNode *thisVar = dynamic_cast<VarNode*>(objectExpr);
  74. if (thisVar && thisVar->varName == StringTable->insert("%this"))
  75. return true;
  76. return false;
  77. }
  78. inline void optimizeThisPointer(CodeStream &codeStream, ExprNode *arrayExpr, U32 &ip, StringTableEntry slotName)
  79. {
  80. OnlyOneThisOptimization = true;
  81. // Is the array a simple variable? If so, we can optimize that.
  82. StringTableEntry varName = nullptr;
  83. bool simple = false;
  84. if (arrayExpr)
  85. {
  86. simple = isSimpleVarLookup(arrayExpr, varName);
  87. if (!simple)
  88. {
  89. // Less optimized array setting.
  90. codeStream.emit(OP_ADVANCE_STR);
  91. ip = arrayExpr->compile(codeStream, ip, TypeReqString);
  92. }
  93. }
  94. codeStream.emit(OP_SETCURFIELD_THIS);
  95. codeStream.emitSTE(slotName);
  96. if (arrayExpr)
  97. {
  98. if (simple)
  99. {
  100. codeStream.emit(OP_SETCURFIELD_ARRAY_VAR);
  101. codeStream.emitSTE(varName);
  102. }
  103. else
  104. {
  105. codeStream.emit(OP_SETCURFIELD_ARRAY);
  106. codeStream.emit(OP_TERMINATE_REWIND_STR);
  107. }
  108. }
  109. OnlyOneThisOptimization = false;
  110. }
  111. }
  112. using namespace Compiler;
  113. //-----------------------------------------------------------------------------
  114. void StmtNode::addBreakLine(CodeStream &code)
  115. {
  116. code.addBreakLine(dbgLineNumber, code.tell());
  117. }
  118. //------------------------------------------------------------
  119. StmtNode::StmtNode()
  120. {
  121. next = NULL;
  122. dbgFileName = CodeBlock::smCurrentParser->getCurrentFile();
  123. }
  124. void StmtNode::setPackage(StringTableEntry)
  125. {
  126. }
  127. void StmtNode::append(StmtNode *next)
  128. {
  129. StmtNode *walk = this;
  130. while (walk->next)
  131. walk = walk->next;
  132. walk->next = next;
  133. }
  134. void FunctionDeclStmtNode::setPackage(StringTableEntry packageName)
  135. {
  136. package = packageName;
  137. }
  138. //------------------------------------------------------------
  139. //
  140. // Console language compilers
  141. //
  142. //------------------------------------------------------------
  143. static U32 conversionOp(TypeReq src, TypeReq dst)
  144. {
  145. if (src == TypeReqString)
  146. {
  147. switch (dst)
  148. {
  149. case TypeReqUInt:
  150. return OP_STR_TO_UINT;
  151. case TypeReqFloat:
  152. return OP_STR_TO_FLT;
  153. case TypeReqNone:
  154. return OP_STR_TO_NONE;
  155. case TypeReqVar:
  156. return OP_SAVEVAR_STR;
  157. default:
  158. break;
  159. }
  160. }
  161. else if (src == TypeReqFloat)
  162. {
  163. switch (dst)
  164. {
  165. case TypeReqUInt:
  166. return OP_FLT_TO_UINT;
  167. case TypeReqString:
  168. return OP_FLT_TO_STR;
  169. case TypeReqNone:
  170. return OP_FLT_TO_NONE;
  171. case TypeReqVar:
  172. return OP_SAVEVAR_FLT;
  173. default:
  174. break;
  175. }
  176. }
  177. else if (src == TypeReqUInt)
  178. {
  179. switch (dst)
  180. {
  181. case TypeReqFloat:
  182. return OP_UINT_TO_FLT;
  183. case TypeReqString:
  184. return OP_UINT_TO_STR;
  185. case TypeReqNone:
  186. return OP_UINT_TO_NONE;
  187. case TypeReqVar:
  188. return OP_SAVEVAR_UINT;
  189. default:
  190. break;
  191. }
  192. }
  193. else if (src == TypeReqVar)
  194. {
  195. switch (dst)
  196. {
  197. case TypeReqUInt:
  198. return OP_LOADVAR_UINT;
  199. case TypeReqFloat:
  200. return OP_LOADVAR_FLT;
  201. case TypeReqString:
  202. return OP_LOADVAR_STR;
  203. case TypeReqNone:
  204. return OP_COPYVAR_TO_NONE;
  205. default:
  206. break;
  207. }
  208. }
  209. return OP_INVALID;
  210. }
  211. //------------------------------------------------------------
  212. U32 BreakStmtNode::compileStmt(CodeStream &codeStream, U32 ip)
  213. {
  214. if (codeStream.inLoop())
  215. {
  216. addBreakLine(codeStream);
  217. codeStream.emit(OP_JMP);
  218. codeStream.emitFix(CodeStream::FIXTYPE_BREAK);
  219. }
  220. else
  221. {
  222. Con::warnf(ConsoleLogEntry::General, "%s (%d): break outside of loop... ignoring.", dbgFileName, dbgLineNumber);
  223. }
  224. return codeStream.tell();
  225. }
  226. //------------------------------------------------------------
  227. U32 ContinueStmtNode::compileStmt(CodeStream &codeStream, U32 ip)
  228. {
  229. if (codeStream.inLoop())
  230. {
  231. addBreakLine(codeStream);
  232. codeStream.emit(OP_JMP);
  233. codeStream.emitFix(CodeStream::FIXTYPE_CONTINUE);
  234. }
  235. else
  236. {
  237. Con::warnf(ConsoleLogEntry::General, "%s (%d): continue outside of loop... ignoring.", dbgFileName, dbgLineNumber);
  238. }
  239. return codeStream.tell();
  240. }
  241. //------------------------------------------------------------
  242. U32 ExprNode::compileStmt(CodeStream &codeStream, U32 ip)
  243. {
  244. addBreakLine(codeStream);
  245. return compile(codeStream, ip, TypeReqNone);
  246. }
  247. //------------------------------------------------------------
  248. U32 ReturnStmtNode::compileStmt(CodeStream &codeStream, U32 ip)
  249. {
  250. addBreakLine(codeStream);
  251. if (!expr)
  252. codeStream.emit(OP_RETURN_VOID);
  253. else
  254. {
  255. TypeReq walkType = expr->getPreferredType();
  256. if (walkType == TypeReqNone) walkType = TypeReqString;
  257. ip = expr->compile(codeStream, ip, walkType);
  258. // Return the correct type
  259. switch (walkType) {
  260. case TypeReqUInt:
  261. codeStream.emit(OP_RETURN_UINT);
  262. break;
  263. case TypeReqFloat:
  264. codeStream.emit(OP_RETURN_FLT);
  265. break;
  266. default:
  267. codeStream.emit(OP_RETURN);
  268. break;
  269. }
  270. }
  271. return codeStream.tell();
  272. }
  273. //------------------------------------------------------------
  274. ExprNode *IfStmtNode::getSwitchOR(ExprNode *left, ExprNode *list, bool string)
  275. {
  276. ExprNode *nextExpr = (ExprNode *)list->getNext();
  277. ExprNode *test;
  278. if (string)
  279. test = StreqExprNode::alloc(left->dbgLineNumber, left, list, true);
  280. else
  281. test = IntBinaryExprNode::alloc(left->dbgLineNumber, opEQ, left, list);
  282. if (!nextExpr)
  283. return test;
  284. return IntBinaryExprNode::alloc(test->dbgLineNumber, opOR, test, getSwitchOR(left, nextExpr, string));
  285. }
  286. void IfStmtNode::propagateSwitchExpr(ExprNode *left, bool string)
  287. {
  288. testExpr = getSwitchOR(left, testExpr, string);
  289. if (propagate && elseBlock)
  290. ((IfStmtNode *)elseBlock)->propagateSwitchExpr(left, string);
  291. }
  292. U32 IfStmtNode::compileStmt(CodeStream &codeStream, U32 ip)
  293. {
  294. U32 endifIp, elseIp;
  295. addBreakLine(codeStream);
  296. if (testExpr->getPreferredType() == TypeReqUInt)
  297. {
  298. integer = true;
  299. }
  300. else
  301. {
  302. integer = false;
  303. }
  304. ip = testExpr->compile(codeStream, ip, integer ? TypeReqUInt : TypeReqFloat);
  305. codeStream.emit(integer ? OP_JMPIFNOT : OP_JMPIFFNOT);
  306. if (elseBlock)
  307. {
  308. elseIp = codeStream.emit(0);
  309. elseOffset = compileBlock(ifBlock, codeStream, ip) + 2;
  310. codeStream.emit(OP_JMP);
  311. endifIp = codeStream.emit(0);
  312. endifOffset = compileBlock(elseBlock, codeStream, ip);
  313. codeStream.patch(endifIp, endifOffset);
  314. codeStream.patch(elseIp, elseOffset);
  315. }
  316. else
  317. {
  318. endifIp = codeStream.emit(0);
  319. endifOffset = compileBlock(ifBlock, codeStream, ip);
  320. codeStream.patch(endifIp, endifOffset);
  321. }
  322. // Resolve fixes
  323. return codeStream.tell();
  324. }
  325. //------------------------------------------------------------
  326. U32 LoopStmtNode::compileStmt(CodeStream &codeStream, U32 ip)
  327. {
  328. if (testExpr->getPreferredType() == TypeReqUInt)
  329. {
  330. integer = true;
  331. }
  332. else
  333. {
  334. integer = false;
  335. }
  336. // if it's a for loop or a while loop it goes:
  337. // initExpr
  338. // testExpr
  339. // OP_JMPIFNOT to break point
  340. // loopStartPoint:
  341. // loopBlock
  342. // continuePoint:
  343. // endLoopExpr
  344. // testExpr
  345. // OP_JMPIF loopStartPoint
  346. // breakPoint:
  347. // otherwise if it's a do ... while() it goes:
  348. // initExpr
  349. // loopStartPoint:
  350. // loopBlock
  351. // continuePoint:
  352. // endLoopExpr
  353. // testExpr
  354. // OP_JMPIF loopStartPoint
  355. // breakPoint:
  356. // loopBlockStart == start of loop block
  357. // continue == skip to end
  358. // break == exit loop
  359. addBreakLine(codeStream);
  360. codeStream.pushFixScope(true);
  361. if (initExpr)
  362. ip = initExpr->compile(codeStream, ip, TypeReqNone);
  363. if (!isDoLoop)
  364. {
  365. ip = testExpr->compile(codeStream, ip, integer ? TypeReqUInt : TypeReqFloat);
  366. codeStream.emit(integer ? OP_JMPIFNOT : OP_JMPIFFNOT);
  367. codeStream.emitFix(CodeStream::FIXTYPE_BREAK);
  368. }
  369. // Compile internals of loop.
  370. loopBlockStartOffset = codeStream.tell();
  371. continueOffset = compileBlock(loopBlock, codeStream, ip);
  372. if (endLoopExpr)
  373. ip = endLoopExpr->compile(codeStream, ip, TypeReqNone);
  374. ip = testExpr->compile(codeStream, ip, integer ? TypeReqUInt : TypeReqFloat);
  375. codeStream.emit(integer ? OP_JMPIF : OP_JMPIFF);
  376. codeStream.emitFix(CodeStream::FIXTYPE_LOOPBLOCKSTART);
  377. breakOffset = codeStream.tell(); // exit loop
  378. codeStream.fixLoop(loopBlockStartOffset, breakOffset, continueOffset);
  379. codeStream.popFixScope();
  380. return codeStream.tell();
  381. }
  382. //------------------------------------------------------------
  383. U32 IterStmtNode::compileStmt(CodeStream &codeStream, U32 ip)
  384. {
  385. // Instruction sequence:
  386. //
  387. // containerExpr
  388. // OP_ITER_BEGIN varName .fail
  389. // .continue:
  390. // OP_ITER .break
  391. // body
  392. // OP_JMP .continue
  393. // .break:
  394. // OP_ITER_END
  395. // .fail:
  396. addBreakLine(codeStream);
  397. codeStream.pushFixScope(true);
  398. const U32 startIp = ip;
  399. containerExpr->compile(codeStream, startIp, TypeReqString);
  400. codeStream.emit(isStringIter ? OP_ITER_BEGIN_STR : OP_ITER_BEGIN);
  401. codeStream.emitSTE(varName);
  402. const U32 finalFix = codeStream.emit(0);
  403. const U32 continueIp = codeStream.emit(OP_ITER);
  404. codeStream.emitFix(CodeStream::FIXTYPE_BREAK);
  405. const U32 bodyIp = codeStream.tell();
  406. const U32 jmpIp = compileBlock(body, codeStream, bodyIp);
  407. const U32 breakIp = jmpIp + 2;
  408. const U32 finalIp = breakIp + 1;
  409. codeStream.emit(OP_JMP);
  410. codeStream.emitFix(CodeStream::FIXTYPE_CONTINUE);
  411. codeStream.emit(OP_ITER_END);
  412. codeStream.patch(finalFix, finalIp);
  413. codeStream.fixLoop(bodyIp, breakIp, continueIp);
  414. codeStream.popFixScope();
  415. return codeStream.tell();
  416. }
  417. //------------------------------------------------------------
  418. U32 ConditionalExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  419. {
  420. // code is testExpr
  421. // JMPIFNOT falseStart
  422. // trueExpr
  423. // JMP end
  424. // falseExpr
  425. if (testExpr->getPreferredType() == TypeReqUInt)
  426. {
  427. integer = true;
  428. }
  429. else
  430. {
  431. integer = false;
  432. }
  433. ip = testExpr->compile(codeStream, ip, integer ? TypeReqUInt : TypeReqFloat);
  434. codeStream.emit(integer ? OP_JMPIFNOT : OP_JMPIFFNOT);
  435. U32 jumpElseIp = codeStream.emit(0);
  436. ip = trueExpr->compile(codeStream, ip, type);
  437. codeStream.emit(OP_JMP);
  438. U32 jumpEndIp = codeStream.emit(0);
  439. codeStream.patch(jumpElseIp, codeStream.tell());
  440. ip = falseExpr->compile(codeStream, ip, type);
  441. codeStream.patch(jumpEndIp, codeStream.tell());
  442. return codeStream.tell();
  443. }
  444. TypeReq ConditionalExprNode::getPreferredType()
  445. {
  446. return trueExpr->getPreferredType();
  447. }
  448. //------------------------------------------------------------
  449. U32 FloatBinaryExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  450. {
  451. ip = right->compile(codeStream, ip, TypeReqFloat);
  452. ip = left->compile(codeStream, ip, TypeReqFloat);
  453. U32 operand = OP_INVALID;
  454. switch (op)
  455. {
  456. case '+':
  457. operand = OP_ADD;
  458. break;
  459. case '-':
  460. operand = OP_SUB;
  461. break;
  462. case '/':
  463. operand = OP_DIV;
  464. break;
  465. case '*':
  466. operand = OP_MUL;
  467. break;
  468. }
  469. codeStream.emit(operand);
  470. if (type != TypeReqFloat)
  471. codeStream.emit(conversionOp(TypeReqFloat, type));
  472. return codeStream.tell();
  473. }
  474. TypeReq FloatBinaryExprNode::getPreferredType()
  475. {
  476. return TypeReqFloat;
  477. }
  478. //------------------------------------------------------------
  479. void IntBinaryExprNode::getSubTypeOperand()
  480. {
  481. subType = TypeReqUInt;
  482. switch (op)
  483. {
  484. case '^':
  485. operand = OP_XOR;
  486. break;
  487. case '%':
  488. operand = OP_MOD;
  489. break;
  490. case '&':
  491. operand = OP_BITAND;
  492. break;
  493. case '|':
  494. operand = OP_BITOR;
  495. break;
  496. case '<':
  497. operand = OP_CMPLT;
  498. subType = TypeReqFloat;
  499. break;
  500. case '>':
  501. operand = OP_CMPGR;
  502. subType = TypeReqFloat;
  503. break;
  504. case opGE:
  505. operand = OP_CMPGE;
  506. subType = TypeReqFloat;
  507. break;
  508. case opLE:
  509. operand = OP_CMPLE;
  510. subType = TypeReqFloat;
  511. break;
  512. case opEQ:
  513. operand = OP_CMPEQ;
  514. subType = TypeReqFloat;
  515. break;
  516. case opNE:
  517. operand = OP_CMPNE;
  518. subType = TypeReqFloat;
  519. break;
  520. case opOR:
  521. operand = OP_OR;
  522. break;
  523. case opAND:
  524. operand = OP_AND;
  525. break;
  526. case opSHR:
  527. operand = OP_SHR;
  528. break;
  529. case opSHL:
  530. operand = OP_SHL;
  531. break;
  532. }
  533. }
  534. U32 IntBinaryExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  535. {
  536. getSubTypeOperand();
  537. if (operand == OP_OR || operand == OP_AND)
  538. {
  539. ip = left->compile(codeStream, ip, subType);
  540. codeStream.emit(operand == OP_OR ? OP_JMPIF_NP : OP_JMPIFNOT_NP);
  541. U32 jmpIp = codeStream.emit(0);
  542. ip = right->compile(codeStream, ip, subType);
  543. codeStream.patch(jmpIp, ip);
  544. }
  545. else
  546. {
  547. ip = right->compile(codeStream, ip, subType);
  548. ip = left->compile(codeStream, ip, subType);
  549. codeStream.emit(operand);
  550. }
  551. if (type != TypeReqUInt)
  552. codeStream.emit(conversionOp(TypeReqUInt, type));
  553. return codeStream.tell();
  554. }
  555. TypeReq IntBinaryExprNode::getPreferredType()
  556. {
  557. return TypeReqUInt;
  558. }
  559. //------------------------------------------------------------
  560. U32 StreqExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  561. {
  562. // eval str left
  563. // OP_ADVANCE_STR_NUL
  564. // eval str right
  565. // OP_COMPARE_STR
  566. // optional conversion
  567. ip = left->compile(codeStream, ip, TypeReqString);
  568. codeStream.emit(OP_ADVANCE_STR_NUL);
  569. ip = right->compile(codeStream, ip, TypeReqString);
  570. codeStream.emit(OP_COMPARE_STR);
  571. if (!eq)
  572. codeStream.emit(OP_NOT);
  573. if (type != TypeReqUInt)
  574. codeStream.emit(conversionOp(TypeReqUInt, type));
  575. return codeStream.tell();
  576. }
  577. TypeReq StreqExprNode::getPreferredType()
  578. {
  579. return TypeReqUInt;
  580. }
  581. //------------------------------------------------------------
  582. U32 StrcatExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  583. {
  584. ip = left->compile(codeStream, ip, TypeReqString);
  585. if (!appendChar)
  586. codeStream.emit(OP_ADVANCE_STR);
  587. else
  588. {
  589. codeStream.emit(OP_ADVANCE_STR_APPENDCHAR);
  590. codeStream.emit(appendChar);
  591. }
  592. ip = right->compile(codeStream, ip, TypeReqString);
  593. codeStream.emit(OP_REWIND_STR);
  594. if (type == TypeReqUInt)
  595. codeStream.emit(OP_STR_TO_UINT);
  596. else if (type == TypeReqFloat)
  597. codeStream.emit(OP_STR_TO_FLT);
  598. return codeStream.tell();
  599. }
  600. TypeReq StrcatExprNode::getPreferredType()
  601. {
  602. return TypeReqString;
  603. }
  604. //------------------------------------------------------------
  605. U32 CommaCatExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  606. {
  607. ip = left->compile(codeStream, ip, TypeReqString);
  608. codeStream.emit(OP_ADVANCE_STR_COMMA);
  609. ip = right->compile(codeStream, ip, TypeReqString);
  610. codeStream.emit(OP_REWIND_STR);
  611. // At this point the stack has the concatenated string.
  612. // But we're paranoid, so accept (but whine) if we get an oddity...
  613. if (type == TypeReqUInt || type == TypeReqFloat)
  614. Con::warnf(ConsoleLogEntry::General, "%s (%d): converting comma string to a number... probably wrong.", dbgFileName, dbgLineNumber);
  615. if (type == TypeReqUInt)
  616. codeStream.emit(OP_STR_TO_UINT);
  617. else if (type == TypeReqFloat)
  618. codeStream.emit(OP_STR_TO_FLT);
  619. return codeStream.tell();
  620. }
  621. TypeReq CommaCatExprNode::getPreferredType()
  622. {
  623. return TypeReqString;
  624. }
  625. //------------------------------------------------------------
  626. U32 IntUnaryExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  627. {
  628. integer = true;
  629. TypeReq prefType = expr->getPreferredType();
  630. if (op == '!' && (prefType == TypeReqFloat || prefType == TypeReqString))
  631. integer = false;
  632. ip = expr->compile(codeStream, ip, integer ? TypeReqUInt : TypeReqFloat);
  633. if (op == '!')
  634. codeStream.emit(integer ? OP_NOT : OP_NOTF);
  635. else if (op == '~')
  636. codeStream.emit(OP_ONESCOMPLEMENT);
  637. if (type != TypeReqUInt)
  638. codeStream.emit(conversionOp(TypeReqUInt, type));
  639. return codeStream.tell();
  640. }
  641. TypeReq IntUnaryExprNode::getPreferredType()
  642. {
  643. return TypeReqUInt;
  644. }
  645. //------------------------------------------------------------
  646. U32 FloatUnaryExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  647. {
  648. ip = expr->compile(codeStream, ip, TypeReqFloat);
  649. codeStream.emit(OP_NEG);
  650. if (type != TypeReqFloat)
  651. codeStream.emit(conversionOp(TypeReqFloat, type));
  652. return codeStream.tell();
  653. }
  654. TypeReq FloatUnaryExprNode::getPreferredType()
  655. {
  656. return TypeReqFloat;
  657. }
  658. //------------------------------------------------------------
  659. U32 VarNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  660. {
  661. // if this has an arrayIndex and we are not short circuiting from a constant.
  662. // if we are a var node
  663. // OP_SETCURVAR_ARRAY_VARLOOKUP
  664. // varName
  665. // varNodeVarName
  666. // else
  667. // OP_LOADIMMED_IDENT
  668. // varName
  669. // OP_ADVANCE_STR
  670. // evaluate arrayIndex TypeReqString
  671. // OP_REWIND_STR
  672. // OP_SETCURVAR_ARRAY
  673. // OP_LOADVAR (type)
  674. // else
  675. // OP_SETCURVAR
  676. // varName
  677. // OP_LOADVAR (type)
  678. if (type == TypeReqNone)
  679. return codeStream.tell();
  680. bool shortCircuit = false;
  681. if (arrayIndex)
  682. {
  683. // If we have a constant, shortcircuit the array logic.
  684. IntNode *intNode = dynamic_cast<IntNode*>(arrayIndex);
  685. StrConstNode *strNode = dynamic_cast<StrConstNode*>(arrayIndex);
  686. if (intNode)
  687. {
  688. varName = StringTable->insert(avar("%s%d", varName, intNode->value));
  689. shortCircuit = true;
  690. }
  691. else if (strNode)
  692. {
  693. varName = StringTable->insert(avar("%s%s", varName, strNode->str));
  694. shortCircuit = true;
  695. }
  696. }
  697. precompileIdent(varName);
  698. if (arrayIndex && !shortCircuit)
  699. {
  700. // Ok, lets try to optimize %var[%someothervar] as this is
  701. // a common case for array usage.
  702. StringTableEntry varNodeVarName;
  703. if (isSimpleVarLookup(arrayIndex, varNodeVarName))
  704. {
  705. codeStream.emit(OP_SETCURVAR_ARRAY_VARLOOKUP);
  706. codeStream.emitSTE(varName);
  707. codeStream.emitSTE(varNodeVarName);
  708. }
  709. else
  710. {
  711. codeStream.emit(OP_LOADIMMED_IDENT);
  712. codeStream.emitSTE(varName);
  713. codeStream.emit(OP_ADVANCE_STR);
  714. ip = arrayIndex->compile(codeStream, ip, TypeReqString);
  715. codeStream.emit(OP_REWIND_STR);
  716. codeStream.emit(OP_SETCURVAR_ARRAY);
  717. }
  718. }
  719. else
  720. {
  721. codeStream.emit(OP_SETCURVAR);
  722. codeStream.emitSTE(varName);
  723. }
  724. switch (type)
  725. {
  726. case TypeReqUInt:
  727. codeStream.emit(OP_LOADVAR_UINT);
  728. break;
  729. case TypeReqFloat:
  730. codeStream.emit(OP_LOADVAR_FLT);
  731. break;
  732. case TypeReqString:
  733. codeStream.emit(OP_LOADVAR_STR);
  734. break;
  735. case TypeReqVar:
  736. codeStream.emit(OP_LOADVAR_VAR);
  737. break;
  738. case TypeReqNone:
  739. break;
  740. default:
  741. break;
  742. }
  743. return codeStream.tell();
  744. }
  745. TypeReq VarNode::getPreferredType()
  746. {
  747. return TypeReqNone; // no preferred type
  748. }
  749. //------------------------------------------------------------
  750. U32 IntNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  751. {
  752. if (type == TypeReqString)
  753. index = getCurrentStringTable()->addIntString(value);
  754. else if (type == TypeReqFloat)
  755. index = getCurrentFloatTable()->add(value);
  756. switch (type)
  757. {
  758. case TypeReqUInt:
  759. codeStream.emit(OP_LOADIMMED_UINT);
  760. codeStream.emit(value);
  761. break;
  762. case TypeReqString:
  763. codeStream.emit(OP_LOADIMMED_STR);
  764. codeStream.emit(index);
  765. break;
  766. case TypeReqFloat:
  767. codeStream.emit(OP_LOADIMMED_FLT);
  768. codeStream.emit(index);
  769. break;
  770. case TypeReqNone:
  771. break;
  772. }
  773. return codeStream.tell();
  774. }
  775. TypeReq IntNode::getPreferredType()
  776. {
  777. return TypeReqUInt;
  778. }
  779. //------------------------------------------------------------
  780. U32 FloatNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  781. {
  782. if (type == TypeReqString)
  783. index = getCurrentStringTable()->addFloatString(value);
  784. else if (type == TypeReqFloat)
  785. index = getCurrentFloatTable()->add(value);
  786. switch (type)
  787. {
  788. case TypeReqUInt:
  789. codeStream.emit(OP_LOADIMMED_UINT);
  790. codeStream.emit(U32(value));
  791. break;
  792. case TypeReqString:
  793. codeStream.emit(OP_LOADIMMED_STR);
  794. codeStream.emit(index);
  795. break;
  796. case TypeReqFloat:
  797. codeStream.emit(OP_LOADIMMED_FLT);
  798. codeStream.emit(index);
  799. break;
  800. case TypeReqNone:
  801. break;
  802. }
  803. return codeStream.tell();
  804. }
  805. TypeReq FloatNode::getPreferredType()
  806. {
  807. return TypeReqFloat;
  808. }
  809. //------------------------------------------------------------
  810. U32 StrConstNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  811. {
  812. // Early out for documentation block.
  813. if (doc)
  814. {
  815. index = getCurrentStringTable()->add(str, true, tag);
  816. }
  817. else if (type == TypeReqString)
  818. {
  819. index = getCurrentStringTable()->add(str, true, tag);
  820. }
  821. else if (type != TypeReqNone)
  822. {
  823. fVal = consoleStringToNumber(str, dbgFileName, dbgLineNumber);
  824. if (type == TypeReqFloat)
  825. {
  826. index = getCurrentFloatTable()->add(fVal);
  827. }
  828. }
  829. // If this is a DOCBLOCK, then process w/ appropriate op...
  830. if (doc)
  831. {
  832. codeStream.emit(OP_DOCBLOCK_STR);
  833. codeStream.emit(index);
  834. return ip;
  835. }
  836. // Otherwise, deal with it normally as a string literal case.
  837. switch (type)
  838. {
  839. case TypeReqString:
  840. codeStream.emit(tag ? OP_TAG_TO_STR : OP_LOADIMMED_STR);
  841. codeStream.emit(index);
  842. break;
  843. case TypeReqUInt:
  844. codeStream.emit(OP_LOADIMMED_UINT);
  845. codeStream.emit(U32(fVal));
  846. break;
  847. case TypeReqFloat:
  848. codeStream.emit(OP_LOADIMMED_FLT);
  849. codeStream.emit(index);
  850. break;
  851. case TypeReqNone:
  852. break;
  853. }
  854. return codeStream.tell();
  855. }
  856. TypeReq StrConstNode::getPreferredType()
  857. {
  858. return TypeReqString;
  859. }
  860. //------------------------------------------------------------
  861. U32 ConstantNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  862. {
  863. if (type == TypeReqString)
  864. {
  865. precompileIdent(value);
  866. }
  867. else if (type != TypeReqNone)
  868. {
  869. fVal = consoleStringToNumber(value, dbgFileName, dbgLineNumber);
  870. if (type == TypeReqFloat)
  871. index = getCurrentFloatTable()->add(fVal);
  872. }
  873. switch (type)
  874. {
  875. case TypeReqString:
  876. codeStream.emit(OP_LOADIMMED_IDENT);
  877. codeStream.emitSTE(value);
  878. break;
  879. case TypeReqUInt:
  880. codeStream.emit(OP_LOADIMMED_UINT);
  881. codeStream.emit(U32(fVal));
  882. break;
  883. case TypeReqFloat:
  884. codeStream.emit(OP_LOADIMMED_FLT);
  885. codeStream.emit(index);
  886. break;
  887. case TypeReqNone:
  888. break;
  889. }
  890. return ip;
  891. }
  892. TypeReq ConstantNode::getPreferredType()
  893. {
  894. return TypeReqString;
  895. }
  896. //------------------------------------------------------------
  897. U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  898. {
  899. subType = expr->getPreferredType();
  900. if (subType == TypeReqNone)
  901. subType = type;
  902. if (subType == TypeReqNone)
  903. {
  904. // What we need to do in this case is turn it into a VarNode reference.
  905. // Unfortunately other nodes such as field access (SlotAccessNode)
  906. // cannot be optimized in the same manner as all fields are exposed
  907. // and set as strings.
  908. if (dynamic_cast<VarNode*>(expr) != NULL)
  909. {
  910. subType = TypeReqVar;
  911. }
  912. else
  913. {
  914. subType = TypeReqString;
  915. }
  916. }
  917. //if we are an array index and we are gonna short circuit
  918. // eval expr
  919. // compute new varName
  920. // OP_SETCURVAR_CREATE
  921. // varName
  922. // OP_SAVEVAR
  923. //else if it's an array expr and we don't short circuit, the formula is:
  924. // eval expr
  925. // (push and pop if it's TypeReqString) OP_ADVANCE_STR
  926. // if array lookup is varnode
  927. // OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP
  928. // varName
  929. // varNodeVarName
  930. // else
  931. // OP_LOADIMMED_IDENT
  932. // varName
  933. // OP_ADVANCE_STR
  934. // eval array
  935. // OP_REWIND_STR
  936. // OP_SETCURVAR_ARRAY_CREATE
  937. // endif
  938. // OP_TERMINATE_REWIND_STR
  939. // OP_SAVEVAR
  940. //else
  941. // eval expr
  942. // OP_SETCURVAR_CREATE
  943. // varname
  944. // OP_SAVEVAR
  945. ip = expr->compile(codeStream, ip, subType);
  946. bool shortCircuit = false;
  947. if (arrayIndex)
  948. {
  949. // If we have a constant, shortcircuit the array logic.
  950. IntNode *intNode = dynamic_cast<IntNode*>(arrayIndex);
  951. StrConstNode *strNode = dynamic_cast<StrConstNode*>(arrayIndex);
  952. if (intNode)
  953. {
  954. varName = StringTable->insert(avar("%s%d", varName, intNode->value));
  955. shortCircuit = true;
  956. }
  957. else if (strNode)
  958. {
  959. varName = StringTable->insert(avar("%s%s", varName, strNode->str));
  960. shortCircuit = true;
  961. }
  962. }
  963. precompileIdent(varName);
  964. if (arrayIndex && !shortCircuit)
  965. {
  966. if (subType == TypeReqString)
  967. codeStream.emit(OP_ADVANCE_STR);
  968. // Ok, lets try to optimize %var[%someothervar] as this is
  969. // a common case for array usage.
  970. StringTableEntry varNodeVarName;
  971. if (isSimpleVarLookup(arrayIndex, varNodeVarName))
  972. {
  973. codeStream.emit(OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP);
  974. codeStream.emitSTE(varName);
  975. codeStream.emitSTE(varNodeVarName);
  976. }
  977. else
  978. {
  979. codeStream.emit(OP_LOADIMMED_IDENT);
  980. codeStream.emitSTE(varName);
  981. codeStream.emit(OP_ADVANCE_STR);
  982. ip = arrayIndex->compile(codeStream, ip, TypeReqString);
  983. codeStream.emit(OP_REWIND_STR);
  984. codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
  985. }
  986. if (subType == TypeReqString)
  987. codeStream.emit(OP_TERMINATE_REWIND_STR);
  988. }
  989. else
  990. {
  991. codeStream.emit(OP_SETCURVAR_CREATE);
  992. codeStream.emitSTE(varName);
  993. }
  994. switch (subType)
  995. {
  996. case TypeReqString:
  997. codeStream.emit(OP_SAVEVAR_STR);
  998. break;
  999. case TypeReqUInt:
  1000. codeStream.emit(OP_SAVEVAR_UINT);
  1001. break;
  1002. case TypeReqFloat:
  1003. codeStream.emit(OP_SAVEVAR_FLT);
  1004. break;
  1005. case TypeReqVar:
  1006. codeStream.emit(OP_SAVEVAR_VAR);
  1007. break;
  1008. case TypeReqNone:
  1009. break;
  1010. }
  1011. if (type != subType)
  1012. codeStream.emit(conversionOp(subType, type));
  1013. return ip;
  1014. }
  1015. TypeReq AssignExprNode::getPreferredType()
  1016. {
  1017. return expr->getPreferredType();
  1018. }
  1019. //------------------------------------------------------------
  1020. static void getAssignOpTypeOp(S32 op, TypeReq &type, U32 &operand)
  1021. {
  1022. switch (op)
  1023. {
  1024. case '+':
  1025. case opPLUSPLUS:
  1026. type = TypeReqFloat;
  1027. operand = OP_ADD;
  1028. break;
  1029. case '-':
  1030. case opMINUSMINUS:
  1031. type = TypeReqFloat;
  1032. operand = OP_SUB;
  1033. break;
  1034. case '*':
  1035. type = TypeReqFloat;
  1036. operand = OP_MUL;
  1037. break;
  1038. case '/':
  1039. type = TypeReqFloat;
  1040. operand = OP_DIV;
  1041. break;
  1042. case '%':
  1043. type = TypeReqUInt;
  1044. operand = OP_MOD;
  1045. break;
  1046. case '&':
  1047. type = TypeReqUInt;
  1048. operand = OP_BITAND;
  1049. break;
  1050. case '^':
  1051. type = TypeReqUInt;
  1052. operand = OP_XOR;
  1053. break;
  1054. case '|':
  1055. type = TypeReqUInt;
  1056. operand = OP_BITOR;
  1057. break;
  1058. case opSHL:
  1059. type = TypeReqUInt;
  1060. operand = OP_SHL;
  1061. break;
  1062. case opSHR:
  1063. type = TypeReqUInt;
  1064. operand = OP_SHR;
  1065. break;
  1066. }
  1067. }
  1068. U32 AssignOpExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  1069. {
  1070. // goes like this...
  1071. //
  1072. // IF no array index && (op == OPPLUSPLUS or op == OPMINUSMINUS)
  1073. // if op == OPPLUSPLUS
  1074. // OP_INC
  1075. // varName
  1076. // else if op == OPMINUSMINUS
  1077. // OP_DEC
  1078. // varName
  1079. // else
  1080. // OP_INVALID
  1081. // endif
  1082. // ELSE
  1083. // eval expr as float or int
  1084. // if there's an arrayIndex and we don't short circuit
  1085. // if arrayIndex is a var node
  1086. // OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP
  1087. // varName
  1088. // varNodeVarName
  1089. // else
  1090. // OP_LOADIMMED_IDENT
  1091. // varName
  1092. // OP_ADVANCE_STR
  1093. // eval arrayIndex stringwise
  1094. // OP_REWIND_STR
  1095. // OP_SETCURVAR_ARRAY_CREATE
  1096. // endif
  1097. // else
  1098. // OP_SETCURVAR_CREATE
  1099. // varName
  1100. // endif
  1101. // OP_LOADVAR_FLT or UINT
  1102. // operand
  1103. // OP_SAVEVAR_FLT or UINT
  1104. // ENDIF
  1105. //
  1106. // if subtype != type
  1107. // convert type
  1108. // endif
  1109. // conversion OP if necessary.
  1110. getAssignOpTypeOp(op, subType, operand);
  1111. // ++ or -- optimization support for non indexed variables.
  1112. if ((!arrayIndex) && (op == opPLUSPLUS || op == opMINUSMINUS))
  1113. {
  1114. precompileIdent(varName);
  1115. if (op == opPLUSPLUS)
  1116. {
  1117. codeStream.emit(OP_INC);
  1118. codeStream.emitSTE(varName);
  1119. }
  1120. else if (op == opMINUSMINUS)
  1121. {
  1122. codeStream.emit(OP_DEC);
  1123. codeStream.emitSTE(varName);
  1124. }
  1125. else
  1126. {
  1127. // This should NEVER happen. This is just for sanity.
  1128. AssertISV(false, "Tried to use ++ or -- but something weird happened.");
  1129. codeStream.emit(OP_INVALID);
  1130. }
  1131. }
  1132. else
  1133. {
  1134. ip = expr->compile(codeStream, ip, subType);
  1135. bool shortCircuit = false;
  1136. if (arrayIndex)
  1137. {
  1138. // If we have a constant, shortcircuit the array logic.
  1139. IntNode *intNode = dynamic_cast<IntNode*>(arrayIndex);
  1140. StrConstNode *strNode = dynamic_cast<StrConstNode*>(arrayIndex);
  1141. if (intNode)
  1142. {
  1143. varName = StringTable->insert(avar("%s%d", varName, intNode->value));
  1144. shortCircuit = true;
  1145. }
  1146. else if (strNode)
  1147. {
  1148. varName = StringTable->insert(avar("%s%s", varName, strNode->str));
  1149. shortCircuit = true;
  1150. }
  1151. }
  1152. precompileIdent(varName);
  1153. if (!arrayIndex || shortCircuit)
  1154. {
  1155. codeStream.emit(OP_SETCURVAR_CREATE);
  1156. codeStream.emitSTE(varName);
  1157. }
  1158. else
  1159. {
  1160. // Ok, lets try to optimize %var[%someothervar] as this is
  1161. // a common case for array usage.
  1162. StringTableEntry varNodeVarName;
  1163. if (isSimpleVarLookup(arrayIndex, varNodeVarName))
  1164. {
  1165. codeStream.emit(OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP);
  1166. codeStream.emitSTE(varName);
  1167. codeStream.emitSTE(varNodeVarName);
  1168. }
  1169. else
  1170. {
  1171. codeStream.emit(OP_LOADIMMED_IDENT);
  1172. codeStream.emitSTE(varName);
  1173. codeStream.emit(OP_ADVANCE_STR);
  1174. ip = arrayIndex->compile(codeStream, ip, TypeReqString);
  1175. codeStream.emit(OP_REWIND_STR);
  1176. codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
  1177. }
  1178. }
  1179. codeStream.emit((subType == TypeReqFloat) ? OP_LOADVAR_FLT : OP_LOADVAR_UINT);
  1180. codeStream.emit(operand);
  1181. codeStream.emit((subType == TypeReqFloat) ? OP_SAVEVAR_FLT : OP_SAVEVAR_UINT);
  1182. }
  1183. if (subType != type)
  1184. codeStream.emit(conversionOp(subType, type));
  1185. return codeStream.tell();
  1186. }
  1187. TypeReq AssignOpExprNode::getPreferredType()
  1188. {
  1189. getAssignOpTypeOp(op, subType, operand);
  1190. return subType;
  1191. }
  1192. //------------------------------------------------------------
  1193. U32 TTagSetStmtNode::compileStmt(CodeStream&, U32 ip)
  1194. {
  1195. return ip;
  1196. }
  1197. //------------------------------------------------------------
  1198. U32 TTagDerefNode::compile(CodeStream&, U32 ip, TypeReq)
  1199. {
  1200. return ip;
  1201. }
  1202. TypeReq TTagDerefNode::getPreferredType()
  1203. {
  1204. return TypeReqNone;
  1205. }
  1206. //------------------------------------------------------------
  1207. U32 TTagExprNode::compile(CodeStream&, U32 ip, TypeReq)
  1208. {
  1209. return ip;
  1210. }
  1211. TypeReq TTagExprNode::getPreferredType()
  1212. {
  1213. return TypeReqNone;
  1214. }
  1215. //------------------------------------------------------------
  1216. U32 FuncCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  1217. {
  1218. // OP_PUSH_FRAME
  1219. // arg OP_PUSH arg OP_PUSH arg OP_PUSH
  1220. // eval all the args, then call the function.
  1221. // OP_CALLFUNC
  1222. // function
  1223. // namespace
  1224. // isDot
  1225. precompileIdent(funcName);
  1226. precompileIdent(nameSpace);
  1227. codeStream.emit(OP_PUSH_FRAME);
  1228. bool isThisCall = false;
  1229. ExprNode *walk = args;
  1230. // Try to optimize the this pointer call if it is a variable
  1231. // that we are loading.
  1232. if (callType == MethodCall)
  1233. {
  1234. // We cannot optimize array indices because it can have quite
  1235. // a bit of code to figure out the array index.
  1236. VarNode *var = dynamic_cast<VarNode*>(args);
  1237. if (var && !var->arrayIndex)
  1238. {
  1239. precompileIdent(var->varName);
  1240. // Are we a %this call?
  1241. isThisCall = (var->varName == StringTable->insert("%this"));
  1242. codeStream.emit(OP_PUSH_THIS);
  1243. codeStream.emitSTE(var->varName);
  1244. // inc args since we took care of first arg.
  1245. walk = (ExprNode*)walk ->getNext();
  1246. }
  1247. }
  1248. for (; walk; walk = (ExprNode *)walk->getNext())
  1249. {
  1250. TypeReq walkType = walk->getPreferredType();
  1251. if (walkType == TypeReqNone) walkType = TypeReqString;
  1252. ip = walk->compile(codeStream, ip, walkType);
  1253. switch (walk->getPreferredType())
  1254. {
  1255. case TypeReqFloat:
  1256. codeStream.emit(OP_PUSH_FLT);
  1257. break;
  1258. case TypeReqUInt:
  1259. codeStream.emit(OP_PUSH_UINT);
  1260. break;
  1261. default:
  1262. codeStream.emit(OP_PUSH);
  1263. break;
  1264. }
  1265. }
  1266. if (isThisCall)
  1267. {
  1268. codeStream.emit(OP_CALLFUNC_THIS);
  1269. codeStream.emitSTE(funcName);
  1270. }
  1271. else
  1272. {
  1273. if (callType == MethodCall || callType == ParentCall)
  1274. codeStream.emit(OP_CALLFUNC);
  1275. else
  1276. codeStream.emit(OP_CALLFUNC_RESOLVE);
  1277. codeStream.emitSTE(funcName);
  1278. codeStream.emitSTE(nameSpace);
  1279. codeStream.emit(callType);
  1280. }
  1281. if (type != TypeReqString)
  1282. codeStream.emit(conversionOp(TypeReqString, type));
  1283. return codeStream.tell();
  1284. }
  1285. TypeReq FuncCallExprNode::getPreferredType()
  1286. {
  1287. return TypeReqString;
  1288. }
  1289. //------------------------------------------------------------
  1290. U32 FuncPointerCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  1291. {
  1292. // OP_PUSH_FRAME
  1293. // arg OP_PUSH arg OP_PUSH arg OP_PUSH
  1294. // eval all the args, then call the function.
  1295. // eval fn pointer
  1296. // OP_CALLFUNC_POINTER
  1297. codeStream.emit(OP_PUSH_FRAME);
  1298. for (ExprNode *walk = args; walk; walk = (ExprNode *)walk->getNext())
  1299. {
  1300. TypeReq walkType = walk->getPreferredType();
  1301. if (walkType == TypeReqNone) walkType = TypeReqString;
  1302. ip = walk->compile(codeStream, ip, walkType);
  1303. switch (walk->getPreferredType())
  1304. {
  1305. case TypeReqFloat:
  1306. codeStream.emit(OP_PUSH_FLT);
  1307. break;
  1308. case TypeReqUInt:
  1309. codeStream.emit(OP_PUSH_UINT);
  1310. break;
  1311. default:
  1312. codeStream.emit(OP_PUSH);
  1313. break;
  1314. }
  1315. }
  1316. ip = funcPointer->compile(codeStream, ip, TypeReqString);
  1317. codeStream.emit(OP_CALLFUNC_POINTER);
  1318. if (type != TypeReqString)
  1319. codeStream.emit(conversionOp(TypeReqString, type));
  1320. return codeStream.tell();
  1321. }
  1322. TypeReq FuncPointerCallExprNode::getPreferredType()
  1323. {
  1324. return TypeReqString;
  1325. }
  1326. //------------------------------------------------------------
  1327. U32 AssertCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  1328. {
  1329. #ifdef TORQUE_ENABLE_SCRIPTASSERTS
  1330. messageIndex = getCurrentStringTable()->add(message, true, false);
  1331. ip = testExpr->compile(codeStream, ip, TypeReqUInt);
  1332. codeStream.emit(OP_ASSERT);
  1333. codeStream.emit(messageIndex);
  1334. #endif
  1335. return codeStream.tell();
  1336. }
  1337. TypeReq AssertCallExprNode::getPreferredType()
  1338. {
  1339. return TypeReqNone;
  1340. }
  1341. //------------------------------------------------------------
  1342. U32 SlotAccessNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  1343. {
  1344. if (type == TypeReqNone)
  1345. return ip;
  1346. precompileIdent(slotName);
  1347. // check if object is %this. If we are, we can do additional optimizations.
  1348. if (isThisVar(objectExpr))
  1349. {
  1350. optimizeThisPointer(codeStream, arrayExpr, ip, slotName);
  1351. }
  1352. else
  1353. {
  1354. if (arrayExpr)
  1355. {
  1356. // eval array
  1357. // OP_ADVANCE_STR
  1358. // evaluate object expression sub (OP_SETCURFIELD)
  1359. // OP_TERMINATE_REWIND_STR
  1360. // OP_SETCURFIELDARRAY
  1361. // total add of 4 + array precomp
  1362. ip = arrayExpr->compile(codeStream, ip, TypeReqString);
  1363. codeStream.emit(OP_ADVANCE_STR);
  1364. }
  1365. ip = objectExpr->compile(codeStream, ip, TypeReqString);
  1366. codeStream.emit(OP_SETCUROBJECT);
  1367. codeStream.emit(OP_SETCURFIELD);
  1368. codeStream.emitSTE(slotName);
  1369. if (arrayExpr)
  1370. {
  1371. codeStream.emit(OP_TERMINATE_REWIND_STR);
  1372. codeStream.emit(OP_SETCURFIELD_ARRAY);
  1373. }
  1374. }
  1375. switch (type)
  1376. {
  1377. case TypeReqUInt:
  1378. codeStream.emit(OP_LOADFIELD_UINT);
  1379. break;
  1380. case TypeReqFloat:
  1381. codeStream.emit(OP_LOADFIELD_FLT);
  1382. break;
  1383. case TypeReqString:
  1384. codeStream.emit(OP_LOADFIELD_STR);
  1385. break;
  1386. case TypeReqNone:
  1387. break;
  1388. }
  1389. return codeStream.tell();
  1390. }
  1391. TypeReq SlotAccessNode::getPreferredType()
  1392. {
  1393. return TypeReqNone;
  1394. }
  1395. //-----------------------------------------------------------------------------
  1396. U32 InternalSlotAccessNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  1397. {
  1398. if (type == TypeReqNone)
  1399. return ip;
  1400. ip = objectExpr->compile(codeStream, ip, TypeReqString);
  1401. codeStream.emit(OP_SETCUROBJECT);
  1402. ip = slotExpr->compile(codeStream, ip, TypeReqString);
  1403. codeStream.emit(OP_SETCUROBJECT_INTERNAL);
  1404. codeStream.emit(recurse);
  1405. if (type != TypeReqUInt)
  1406. codeStream.emit(conversionOp(TypeReqUInt, type));
  1407. return codeStream.tell();
  1408. }
  1409. TypeReq InternalSlotAccessNode::getPreferredType()
  1410. {
  1411. return TypeReqUInt;
  1412. }
  1413. //-----------------------------------------------------------------------------
  1414. U32 SlotAssignNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  1415. {
  1416. // first eval the expression TypeReqString
  1417. // if it's an array:
  1418. // if OP_ADVANCE_STR 1
  1419. // eval array
  1420. // OP_ADVANCE_STR 1
  1421. // evaluate object expr
  1422. // OP_SETCUROBJECT 1
  1423. // OP_SETCURFIELD 1
  1424. // fieldName 1
  1425. // OP_TERMINATE_REWIND_STR 1
  1426. // OP_SETCURFIELDARRAY 1
  1427. // OP_TERMINATE_REWIND_STR 1
  1428. // else
  1429. // OP_ADVANCE_STR
  1430. // evaluate object expr
  1431. // OP_SETCUROBJECT
  1432. // OP_SETCURFIELD
  1433. // fieldName
  1434. // OP_TERMINATE_REWIND_STR
  1435. // OP_SAVEFIELD
  1436. // convert to return type if necessary.
  1437. precompileIdent(slotName);
  1438. ip = valueExpr->compile(codeStream, ip, TypeReqString);
  1439. if (isThisVar(objectExpr))
  1440. {
  1441. optimizeThisPointer(codeStream, arrayExpr, ip, slotName);
  1442. }
  1443. else
  1444. {
  1445. codeStream.emit(OP_ADVANCE_STR);
  1446. if (arrayExpr)
  1447. {
  1448. ip = arrayExpr->compile(codeStream, ip, TypeReqString);
  1449. codeStream.emit(OP_ADVANCE_STR);
  1450. }
  1451. if (objectExpr)
  1452. {
  1453. ip = objectExpr->compile(codeStream, ip, TypeReqString);
  1454. codeStream.emit(OP_SETCUROBJECT);
  1455. }
  1456. else
  1457. codeStream.emit(OP_SETCUROBJECT_NEW);
  1458. codeStream.emit(OP_SETCURFIELD);
  1459. codeStream.emitSTE(slotName);
  1460. if (arrayExpr)
  1461. {
  1462. codeStream.emit(OP_TERMINATE_REWIND_STR);
  1463. codeStream.emit(OP_SETCURFIELD_ARRAY);
  1464. }
  1465. codeStream.emit(OP_TERMINATE_REWIND_STR);
  1466. }
  1467. codeStream.emit(OP_SAVEFIELD_STR);
  1468. if (typeID != -1)
  1469. {
  1470. codeStream.emit(OP_SETCURFIELD_TYPE);
  1471. codeStream.emit(typeID);
  1472. }
  1473. if (type != TypeReqString)
  1474. codeStream.emit(conversionOp(TypeReqString, type));
  1475. return codeStream.tell();
  1476. }
  1477. TypeReq SlotAssignNode::getPreferredType()
  1478. {
  1479. return TypeReqString;
  1480. }
  1481. //------------------------------------------------------------
  1482. U32 SlotAssignOpNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  1483. {
  1484. // first eval the expression as its type
  1485. // if it's an array:
  1486. // eval array
  1487. // OP_ADVANCE_STR
  1488. // evaluate object expr
  1489. // OP_SETCUROBJECT
  1490. // OP_SETCURFIELD
  1491. // fieldName
  1492. // OP_TERMINATE_REWIND_STR
  1493. // OP_SETCURFIELDARRAY
  1494. // else
  1495. // evaluate object expr
  1496. // OP_SETCUROBJECT
  1497. // OP_SETCURFIELD
  1498. // fieldName
  1499. // OP_LOADFIELD of appropriate type
  1500. // operand
  1501. // OP_SAVEFIELD of appropriate type
  1502. // convert to return type if necessary.
  1503. getAssignOpTypeOp(op, subType, operand);
  1504. precompileIdent(slotName);
  1505. ip = valueExpr->compile(codeStream, ip, subType);
  1506. if (isThisVar(objectExpr))
  1507. {
  1508. optimizeThisPointer(codeStream, arrayExpr, ip, slotName);
  1509. }
  1510. else
  1511. {
  1512. if (arrayExpr)
  1513. {
  1514. ip = arrayExpr->compile(codeStream, ip, TypeReqString);
  1515. codeStream.emit(OP_ADVANCE_STR);
  1516. }
  1517. ip = objectExpr->compile(codeStream, ip, TypeReqString);
  1518. codeStream.emit(OP_SETCUROBJECT);
  1519. codeStream.emit(OP_SETCURFIELD);
  1520. codeStream.emitSTE(slotName);
  1521. if (arrayExpr)
  1522. {
  1523. codeStream.emit(OP_TERMINATE_REWIND_STR);
  1524. codeStream.emit(OP_SETCURFIELD_ARRAY);
  1525. }
  1526. }
  1527. codeStream.emit((subType == TypeReqFloat) ? OP_LOADFIELD_FLT : OP_LOADFIELD_UINT);
  1528. codeStream.emit(operand);
  1529. codeStream.emit((subType == TypeReqFloat) ? OP_SAVEFIELD_FLT : OP_SAVEFIELD_UINT);
  1530. if (subType != type)
  1531. codeStream.emit(conversionOp(subType, type));
  1532. return codeStream.tell();
  1533. }
  1534. TypeReq SlotAssignOpNode::getPreferredType()
  1535. {
  1536. getAssignOpTypeOp(op, subType, operand);
  1537. return subType;
  1538. }
  1539. //------------------------------------------------------------
  1540. U32 ObjectDeclNode::compileSubObject(CodeStream &codeStream, U32 ip, bool root)
  1541. {
  1542. // goes
  1543. // OP_PUSHFRAME 1
  1544. // name expr
  1545. // OP_PUSH 1
  1546. // args... PUSH
  1547. // OP_CREATE_OBJECT 1
  1548. // parentObject 1
  1549. // isDatablock 1
  1550. // internalName 1
  1551. // isSingleton 1
  1552. // lineNumber 1
  1553. // fail point 1
  1554. // for each field, eval
  1555. // OP_ADD_OBJECT (to UINT[0]) 1
  1556. // root? 1
  1557. // add all the sub objects.
  1558. // OP_END_OBJECT 1
  1559. // root? 1
  1560. // To fix the stack issue [7/9/2007 Black]
  1561. // OP_FINISH_OBJECT <-- fail point jumps to this opcode
  1562. codeStream.emit(OP_PUSH_FRAME);
  1563. ip = classNameExpr->compile(codeStream, ip, TypeReqString);
  1564. codeStream.emit(OP_PUSH);
  1565. ip = objectNameExpr->compile(codeStream, ip, TypeReqString);
  1566. codeStream.emit(OP_PUSH);
  1567. for (ExprNode *exprWalk = argList; exprWalk; exprWalk = (ExprNode *)exprWalk->getNext())
  1568. {
  1569. TypeReq walkType = exprWalk->getPreferredType();
  1570. if (walkType == TypeReqNone) walkType = TypeReqString;
  1571. ip = exprWalk->compile(codeStream, ip, walkType);
  1572. switch (exprWalk->getPreferredType())
  1573. {
  1574. case TypeReqFloat:
  1575. codeStream.emit(OP_PUSH_FLT);
  1576. break;
  1577. case TypeReqUInt:
  1578. codeStream.emit(OP_PUSH_UINT);
  1579. break;
  1580. default:
  1581. codeStream.emit(OP_PUSH);
  1582. break;
  1583. }
  1584. }
  1585. codeStream.emit(OP_CREATE_OBJECT);
  1586. codeStream.emitSTE(parentObject);
  1587. codeStream.emit(isDatablock);
  1588. codeStream.emit(isClassNameInternal);
  1589. codeStream.emit(isSingleton);
  1590. codeStream.emit(dbgLineNumber);
  1591. const U32 failIp = codeStream.emit(0);
  1592. for (SlotAssignNode *slotWalk = slotDecls; slotWalk; slotWalk = (SlotAssignNode *)slotWalk->getNext())
  1593. ip = slotWalk->compile(codeStream, ip, TypeReqNone);
  1594. codeStream.emit(OP_ADD_OBJECT);
  1595. codeStream.emit(root);
  1596. for (ObjectDeclNode *objectWalk = subObjects; objectWalk; objectWalk = (ObjectDeclNode *)objectWalk->getNext())
  1597. ip = objectWalk->compileSubObject(codeStream, ip, false);
  1598. codeStream.emit(OP_END_OBJECT);
  1599. codeStream.emit(root || isDatablock);
  1600. // Added to fix the object creation issue [7/9/2007 Black]
  1601. failOffset = codeStream.emit(OP_FINISH_OBJECT);
  1602. codeStream.patch(failIp, failOffset);
  1603. return codeStream.tell();
  1604. }
  1605. U32 ObjectDeclNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
  1606. {
  1607. // root object decl does:
  1608. // push 0 onto the UINT stack OP_LOADIMMED_UINT
  1609. // precompiles the subObject(true)
  1610. // UINT stack now has object id
  1611. // type conv to type
  1612. codeStream.emit(OP_LOADIMMED_UINT);
  1613. codeStream.emit(0);
  1614. ip = compileSubObject(codeStream, ip, true);
  1615. if (type != TypeReqUInt)
  1616. codeStream.emit(conversionOp(TypeReqUInt, type));
  1617. return codeStream.tell();
  1618. }
  1619. TypeReq ObjectDeclNode::getPreferredType()
  1620. {
  1621. return TypeReqUInt;
  1622. }
  1623. //------------------------------------------------------------
  1624. U32 FunctionDeclStmtNode::compileStmt(CodeStream &codeStream, U32 ip)
  1625. {
  1626. // OP_FUNC_DECL
  1627. // func name
  1628. // namespace
  1629. // package
  1630. // hasBody?
  1631. // func end ip
  1632. // argc
  1633. // ident array[argc]
  1634. // code
  1635. // OP_RETURN_VOID
  1636. setCurrentStringTable(&getFunctionStringTable());
  1637. setCurrentFloatTable(&getFunctionFloatTable());
  1638. argc = 0;
  1639. for (VarNode *walk = args; walk; walk = (VarNode *)((StmtNode*)walk)->getNext())
  1640. {
  1641. precompileIdent(walk->varName);
  1642. argc++;
  1643. }
  1644. CodeBlock::smInFunction = true;
  1645. precompileIdent(fnName);
  1646. precompileIdent(nameSpace);
  1647. precompileIdent(package);
  1648. CodeBlock::smInFunction = false;
  1649. codeStream.emit(OP_FUNC_DECL);
  1650. codeStream.emitSTE(fnName);
  1651. codeStream.emitSTE(nameSpace);
  1652. codeStream.emitSTE(package);
  1653. codeStream.emit(U32(bool(stmts != NULL) ? 1 : 0) + U32(dbgLineNumber << 1));
  1654. const U32 endIp = codeStream.emit(0);
  1655. codeStream.emit(argc);
  1656. for (VarNode *walk = args; walk; walk = (VarNode *)((StmtNode*)walk)->getNext())
  1657. {
  1658. codeStream.emitSTE(walk->varName);
  1659. }
  1660. CodeBlock::smInFunction = true;
  1661. ip = compileBlock(stmts, codeStream, ip);
  1662. // Add break so breakpoint can be set at closing brace or
  1663. // in empty function.
  1664. addBreakLine(codeStream);
  1665. CodeBlock::smInFunction = false;
  1666. codeStream.emit(OP_RETURN_VOID);
  1667. codeStream.patch(endIp, codeStream.tell());
  1668. setCurrentStringTable(&getGlobalStringTable());
  1669. setCurrentFloatTable(&getGlobalFloatTable());
  1670. return ip;
  1671. }