astNodes.cpp 39 KB

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