astNodes.cpp

Engine/source/console/astNodes.cpp

More...

Classes:

class

Namespaces:

namespace

Public Functions

getAssignOpTypeOp(S32 op, TypeReq & type, U32 & operand)

Detailed Description

Public Functions

conversionOp(TypeReq src, TypeReq dst)

getAssignOpTypeOp(S32 op, TypeReq & type, U32 & operand)

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