astNodes.cpp 42 KB

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