astNodes.cpp 42 KB

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