astNodes.cpp
Engine/source/console/astNodes.cpp
Classes:
class
Namespaces:
namespace
Public Functions
conversionOp(TypeReq src, TypeReq dst)
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
