Areloch 7 years ago
parent
commit
d666322a1b

+ 4 - 0
Engine/source/app/mainLoop.cpp

@@ -45,6 +45,7 @@
 #include "console/debugOutputConsumer.h"
 #include "console/consoleTypes.h"
 #include "console/engineAPI.h"
+#include "console/codeInterpreter.h"
 
 #include "gfx/bitmap/gBitmap.h"
 #include "gfx/gFont.h"
@@ -227,6 +228,9 @@ void StandardMainLoop::init()
    ManagedSingleton< ThreadManager >::createSingleton();
    FrameAllocator::init(TORQUE_FRAME_SIZE);      // See comments in torqueConfig.h
 
+   // Initialize the TorqueScript interpreter.
+   CodeInterpreter::init();
+
    // Yell if we can't initialize the network.
    if(!Net::init())
    {

+ 4 - 2
Engine/source/console/CMDgram.y

@@ -496,9 +496,9 @@ class_name_expr
 
 assign_op_struct
    : opPLUSPLUS
-      { $$.lineNumber = $1.lineNumber; $$.token = '+'; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
+      { $$.lineNumber = $1.lineNumber; $$.token = opPLUSPLUS; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
    | opMINUSMINUS
-      { $$.lineNumber = $1.lineNumber; $$.token = '-'; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
+      { $$.lineNumber = $1.lineNumber; $$.token = opMINUSMINUS; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
    | opPLASN expr
       { $$.lineNumber = $1.lineNumber; $$.token = '+'; $$.expr = $2; }
    | opMIASN expr
@@ -551,6 +551,8 @@ funcall_expr
      { $$ = FuncCallExprNode::alloc( $1.lineNumber, $3.value, $1.value, $5, false); }
    | expr '.' IDENT '(' expr_list_decl ')'
       { $1->append($5); $$ = FuncCallExprNode::alloc( $1->dbgLineNumber, $3.value, NULL, $1, true); }
+   | expr '(' expr_list_decl ')'
+      { $$ = FuncPointerCallExprNode::alloc( $1->dbgLineNumber, $1, $3); }
    ;
 
 assert_expr

File diff suppressed because it is too large
+ 895 - 896
Engine/source/console/CMDscan.cpp


+ 84 - 72
Engine/source/console/ast.h

@@ -56,7 +56,7 @@ struct StmtNode
 
    StmtNode();
    virtual ~StmtNode() {}
-   
+
    /// @name next Accessors
    /// @{
 
@@ -99,17 +99,17 @@ struct StmtNode
 
 struct BreakStmtNode : StmtNode
 {
-   static BreakStmtNode *alloc( S32 lineNumber );
+   static BreakStmtNode *alloc(S32 lineNumber);
+
 
-   
    U32 compileStmt(CodeStream &codeStream, U32 ip);
    DBG_STMT_TYPE(BreakStmtNode);
 };
 
 struct ContinueStmtNode : StmtNode
 {
-   static ContinueStmtNode *alloc( S32 lineNumber );
-   
+   static ContinueStmtNode *alloc(S32 lineNumber);
+
    U32 compileStmt(CodeStream &codeStream, U32 ip);
    DBG_STMT_TYPE(ContinueStmtNode);
 };
@@ -117,7 +117,7 @@ struct ContinueStmtNode : StmtNode
 /// A mathematical expression.
 struct ExprNode : StmtNode
 {
-   
+
    U32 compileStmt(CodeStream &codeStream, U32 ip);
 
    virtual U32 compile(CodeStream &codeStream, U32 ip, TypeReq type) = 0;
@@ -128,8 +128,8 @@ struct ReturnStmtNode : StmtNode
 {
    ExprNode *expr;
 
-   static ReturnStmtNode *alloc( S32 lineNumber, ExprNode *expr );
-   
+   static ReturnStmtNode *alloc(S32 lineNumber, ExprNode *expr);
+
    U32 compileStmt(CodeStream &codeStream, U32 ip);
    DBG_STMT_TYPE(ReturnStmtNode);
 };
@@ -143,10 +143,10 @@ struct IfStmtNode : StmtNode
    bool integer;
    bool propagate;
 
-   static IfStmtNode *alloc( S32 lineNumber, ExprNode *testExpr, StmtNode *ifBlock, StmtNode *elseBlock, bool propagateThrough );
+   static IfStmtNode *alloc(S32 lineNumber, ExprNode *testExpr, StmtNode *ifBlock, StmtNode *elseBlock, bool propagateThrough);
    void propagateSwitchExpr(ExprNode *left, bool string);
    ExprNode *getSwitchOR(ExprNode *left, ExprNode *list, bool string);
-   
+
    U32 compileStmt(CodeStream &codeStream, U32 ip);
    DBG_STMT_TYPE(IfStmtNode);
 };
@@ -163,8 +163,8 @@ struct LoopStmtNode : StmtNode
    U32 loopBlockStartOffset;
    bool integer;
 
-   static LoopStmtNode *alloc( S32 lineNumber, ExprNode *testExpr, ExprNode *initExpr, ExprNode *endLoopExpr, StmtNode *loopBlock, bool isDoLoop );
-   
+   static LoopStmtNode *alloc(S32 lineNumber, ExprNode *testExpr, ExprNode *initExpr, ExprNode *endLoopExpr, StmtNode *loopBlock, bool isDoLoop);
+
    U32 compileStmt(CodeStream &codeStream, U32 ip);
    DBG_STMT_TYPE(LoopStmtNode);
 };
@@ -174,22 +174,22 @@ struct IterStmtNode : StmtNode
 {
    /// Local variable name to use for the container element.
    StringTableEntry varName;
-   
+
    /// Expression evaluating to a SimSet object.
    ExprNode* containerExpr;
-   
+
    /// The statement body.
    StmtNode* body;
-   
+
    /// If true, this is a 'foreach$'.
    bool isStringIter;
-   
+
    /// Bytecode size of body statement.  Set by precompileStmt.
    U32 bodySize;
-   
-   static IterStmtNode* alloc( S32 lineNumber, StringTableEntry varName, ExprNode* containerExpr, StmtNode* body, bool isStringIter );
-   
-   U32 compileStmt( CodeStream &codeStream, U32 ip );
+
+   static IterStmtNode* alloc(S32 lineNumber, StringTableEntry varName, ExprNode* containerExpr, StmtNode* body, bool isStringIter);
+
+   U32 compileStmt(CodeStream &codeStream, U32 ip);
 };
 
 /// A binary mathematical expression (ie, left op right).
@@ -202,8 +202,8 @@ struct BinaryExprNode : ExprNode
 
 struct FloatBinaryExprNode : BinaryExprNode
 {
-   static FloatBinaryExprNode *alloc( S32 lineNumber, S32 op, ExprNode *left, ExprNode *right );
-  
+   static FloatBinaryExprNode *alloc(S32 lineNumber, S32 op, ExprNode *left, ExprNode *right);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(FloatBinaryExprNode);
@@ -215,8 +215,8 @@ struct ConditionalExprNode : ExprNode
    ExprNode *trueExpr;
    ExprNode *falseExpr;
    bool integer;
-   static ConditionalExprNode *alloc( S32 lineNumber, ExprNode *testExpr, ExprNode *trueExpr, ExprNode *falseExpr );
-   
+   static ConditionalExprNode *alloc(S32 lineNumber, ExprNode *testExpr, ExprNode *trueExpr, ExprNode *falseExpr);
+
    virtual U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    virtual TypeReq getPreferredType();
    DBG_STMT_TYPE(ConditionalExprNode);
@@ -227,10 +227,10 @@ struct IntBinaryExprNode : BinaryExprNode
    TypeReq subType;
    U32 operand;
 
-   static IntBinaryExprNode *alloc( S32 lineNumber, S32 op, ExprNode *left, ExprNode *right );
+   static IntBinaryExprNode *alloc(S32 lineNumber, S32 op, ExprNode *left, ExprNode *right);
 
    void getSubTypeOperand();
-   
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(IntBinaryExprNode);
@@ -239,8 +239,8 @@ struct IntBinaryExprNode : BinaryExprNode
 struct StreqExprNode : BinaryExprNode
 {
    bool eq;
-   static StreqExprNode *alloc( S32 lineNumber, ExprNode *left, ExprNode *right, bool eq );
-   
+   static StreqExprNode *alloc(S32 lineNumber, ExprNode *left, ExprNode *right, bool eq);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(StreqExprNode);
@@ -249,8 +249,8 @@ struct StreqExprNode : BinaryExprNode
 struct StrcatExprNode : BinaryExprNode
 {
    S32 appendChar;
-   static StrcatExprNode *alloc( S32 lineNumber, ExprNode *left, ExprNode *right, S32 appendChar );
-  
+   static StrcatExprNode *alloc(S32 lineNumber, ExprNode *left, ExprNode *right, S32 appendChar);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(StrcatExprNode);
@@ -258,9 +258,9 @@ struct StrcatExprNode : BinaryExprNode
 
 struct CommaCatExprNode : BinaryExprNode
 {
-   static CommaCatExprNode *alloc( S32 lineNumber, ExprNode *left, ExprNode *right );
+   static CommaCatExprNode *alloc(S32 lineNumber, ExprNode *left, ExprNode *right);
+
 
-  
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(CommaCatExprNode);
@@ -272,8 +272,8 @@ struct IntUnaryExprNode : ExprNode
    ExprNode *expr;
    bool integer;
 
-   static IntUnaryExprNode *alloc( S32 lineNumber, S32 op, ExprNode *expr );
-  
+   static IntUnaryExprNode *alloc(S32 lineNumber, S32 op, ExprNode *expr);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(IntUnaryExprNode);
@@ -284,8 +284,8 @@ struct FloatUnaryExprNode : ExprNode
    S32 op;
    ExprNode *expr;
 
-   static FloatUnaryExprNode *alloc( S32 lineNumber, S32 op, ExprNode *expr );
-  
+   static FloatUnaryExprNode *alloc(S32 lineNumber, S32 op, ExprNode *expr);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(FloatUnaryExprNode);
@@ -296,8 +296,8 @@ struct VarNode : ExprNode
    StringTableEntry varName;
    ExprNode *arrayIndex;
 
-   static VarNode *alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex );
-  
+   static VarNode *alloc(S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(VarNode);
@@ -308,8 +308,8 @@ struct IntNode : ExprNode
    S32 value;
    U32 index; // if it's converted to float/string
 
-   static IntNode *alloc( S32 lineNumber, S32 value );
-  
+   static IntNode *alloc(S32 lineNumber, S32 value);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(IntNode);
@@ -320,8 +320,8 @@ struct FloatNode : ExprNode
    F64 value;
    U32 index;
 
-   static FloatNode *alloc( S32 lineNumber, F64 value );
-  
+   static FloatNode *alloc(S32 lineNumber, F64 value);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(FloatNode);
@@ -335,8 +335,8 @@ struct StrConstNode : ExprNode
    bool tag;
    bool doc; // Specifies that this string is a documentation block.
 
-   static StrConstNode *alloc( S32 lineNumber, char *str, bool tag, bool doc = false );
-  
+   static StrConstNode *alloc(S32 lineNumber, char *str, bool tag, bool doc = false);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(StrConstNode);
@@ -348,8 +348,8 @@ struct ConstantNode : ExprNode
    F64 fVal;
    U32 index;
 
-   static ConstantNode *alloc( S32 lineNumber, StringTableEntry value );
-  
+   static ConstantNode *alloc(S32 lineNumber, StringTableEntry value);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(ConstantNode);
@@ -362,8 +362,8 @@ struct AssignExprNode : ExprNode
    ExprNode *arrayIndex;
    TypeReq subType;
 
-   static AssignExprNode *alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr );
-  
+   static AssignExprNode *alloc(S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(AssignExprNode);
@@ -386,8 +386,8 @@ struct AssignOpExprNode : ExprNode
    U32 operand;
    TypeReq subType;
 
-   static AssignOpExprNode *alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr, S32 op );
-  
+   static AssignOpExprNode *alloc(S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr, S32 op);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(AssignOpExprNode);
@@ -399,8 +399,8 @@ struct TTagSetStmtNode : StmtNode
    ExprNode *valueExpr;
    ExprNode *stringExpr;
 
-   static TTagSetStmtNode *alloc( S32 lineNumber, StringTableEntry tag, ExprNode *valueExpr, ExprNode *stringExpr );
-   
+   static TTagSetStmtNode *alloc(S32 lineNumber, StringTableEntry tag, ExprNode *valueExpr, ExprNode *stringExpr);
+
    U32 compileStmt(CodeStream &codeStream, U32 ip);
    DBG_STMT_TYPE(TTagSetStmtNode);
 };
@@ -409,8 +409,8 @@ struct TTagDerefNode : ExprNode
 {
    ExprNode *expr;
 
-   static TTagDerefNode *alloc( S32 lineNumber, ExprNode *expr );
-  
+   static TTagDerefNode *alloc(S32 lineNumber, ExprNode *expr);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(TTagDerefNode);
@@ -420,8 +420,8 @@ struct TTagExprNode : ExprNode
 {
    StringTableEntry tag;
 
-   static TTagExprNode *alloc( S32 lineNumber, StringTableEntry tag );
-  
+   static TTagExprNode *alloc(S32 lineNumber, StringTableEntry tag);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(TTagExprNode);
@@ -439,21 +439,33 @@ struct FuncCallExprNode : ExprNode
       ParentCall
    };
 
-   static FuncCallExprNode *alloc( S32 lineNumber, StringTableEntry funcName, StringTableEntry nameSpace, ExprNode *args, bool dot );
-  
+   static FuncCallExprNode *alloc(S32 lineNumber, StringTableEntry funcName, StringTableEntry nameSpace, ExprNode *args, bool dot);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(FuncCallExprNode);
 };
 
+struct FuncPointerCallExprNode : ExprNode
+{
+   ExprNode *funcPointer;
+   ExprNode *args;
+
+   static FuncPointerCallExprNode *alloc(S32 lineNumber, ExprNode *stmt, ExprNode *args);
+
+   U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
+   TypeReq getPreferredType();
+   DBG_STMT_TYPE(FuncPointerCallExprNode);
+};
+
 struct AssertCallExprNode : ExprNode
 {
    ExprNode *testExpr;
    const char *message;
    U32 messageIndex;
 
-   static AssertCallExprNode *alloc( S32 lineNumber, ExprNode *testExpr, const char *message );
-  
+   static AssertCallExprNode *alloc(S32 lineNumber, ExprNode *testExpr, const char *message);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(AssertCallExprNode);
@@ -472,8 +484,8 @@ struct SlotAccessNode : ExprNode
    ExprNode *objectExpr, *arrayExpr;
    StringTableEntry slotName;
 
-   static SlotAccessNode *alloc( S32 lineNumber, ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName );
-  
+   static SlotAccessNode *alloc(S32 lineNumber, ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(SlotAccessNode);
@@ -492,8 +504,8 @@ struct InternalSlotAccessNode : ExprNode
    ExprNode *objectExpr, *slotExpr;
    bool recurse;
 
-   static InternalSlotAccessNode *alloc( S32 lineNumber, ExprNode *objectExpr, ExprNode *slotExpr, bool recurse );
-  
+   static InternalSlotAccessNode *alloc(S32 lineNumber, ExprNode *objectExpr, ExprNode *slotExpr, bool recurse);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(InternalSlotAccessNode);
@@ -506,8 +518,8 @@ struct SlotAssignNode : ExprNode
    ExprNode *valueExpr;
    U32 typeID;
 
-   static SlotAssignNode *alloc( S32 lineNumber, ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName, ExprNode *valueExpr, U32 typeID = -1 );
-  
+   static SlotAssignNode *alloc(S32 lineNumber, ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName, ExprNode *valueExpr, U32 typeID = -1);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(SlotAssignNode);
@@ -522,8 +534,8 @@ struct SlotAssignOpNode : ExprNode
    U32 operand;
    TypeReq subType;
 
-   static SlotAssignOpNode *alloc( S32 lineNumber, ExprNode *objectExpr, StringTableEntry slotName, ExprNode *arrayExpr, S32 op, ExprNode *valueExpr );
-  
+   static SlotAssignOpNode *alloc(S32 lineNumber, ExprNode *objectExpr, StringTableEntry slotName, ExprNode *arrayExpr, S32 op, ExprNode *valueExpr);
+
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    TypeReq getPreferredType();
    DBG_STMT_TYPE(SlotAssignOpNode);
@@ -542,8 +554,8 @@ struct ObjectDeclNode : ExprNode
    bool isClassNameInternal;
    bool isSingleton;
 
-   static ObjectDeclNode *alloc( S32 lineNumber, ExprNode *classNameExpr, ExprNode *objectNameExpr, ExprNode *argList, StringTableEntry parentObject, SlotAssignNode *slotDecls, ObjectDeclNode *subObjects, bool isDatablock, bool classNameInternal, bool isSingleton );
-  
+   static ObjectDeclNode *alloc(S32 lineNumber, ExprNode *classNameExpr, ExprNode *objectNameExpr, ExprNode *argList, StringTableEntry parentObject, SlotAssignNode *slotDecls, ObjectDeclNode *subObjects, bool isDatablock, bool classNameInternal, bool isSingleton);
+
    U32 precompileSubObject(bool);
    U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
    U32 compileSubObject(CodeStream &codeStream, U32 ip, bool);
@@ -567,8 +579,8 @@ struct FunctionDeclStmtNode : StmtNode
    U32 endOffset;
    U32 argc;
 
-   static FunctionDeclStmtNode *alloc( S32 lineNumber, StringTableEntry fnName, StringTableEntry nameSpace, VarNode *args, StmtNode *stmts );
-   
+   static FunctionDeclStmtNode *alloc(S32 lineNumber, StringTableEntry fnName, StringTableEntry nameSpace, VarNode *args, StmtNode *stmts);
+
    U32 compileStmt(CodeStream &codeStream, U32 ip);
    void setPackage(StringTableEntry packageName);
    DBG_STMT_TYPE(FunctionDeclStmtNode);

+ 93 - 83
Engine/source/console/astAlloc.cpp

@@ -38,25 +38,25 @@ using namespace Compiler;
 
 //------------------------------------------------------------
 
-BreakStmtNode *BreakStmtNode::alloc( S32 lineNumber )
+BreakStmtNode *BreakStmtNode::alloc(S32 lineNumber)
 {
-   BreakStmtNode *ret = (BreakStmtNode *) consoleAlloc(sizeof(BreakStmtNode));
+   BreakStmtNode *ret = (BreakStmtNode *)consoleAlloc(sizeof(BreakStmtNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    return ret;
 }
 
-ContinueStmtNode *ContinueStmtNode::alloc( S32 lineNumber )
+ContinueStmtNode *ContinueStmtNode::alloc(S32 lineNumber)
 {
-   ContinueStmtNode *ret = (ContinueStmtNode *) consoleAlloc(sizeof(ContinueStmtNode));
+   ContinueStmtNode *ret = (ContinueStmtNode *)consoleAlloc(sizeof(ContinueStmtNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    return ret;
 }
 
-ReturnStmtNode *ReturnStmtNode::alloc( S32 lineNumber, ExprNode *expr)
+ReturnStmtNode *ReturnStmtNode::alloc(S32 lineNumber, ExprNode *expr)
 {
-   ReturnStmtNode *ret = (ReturnStmtNode *) consoleAlloc(sizeof(ReturnStmtNode));
+   ReturnStmtNode *ret = (ReturnStmtNode *)consoleAlloc(sizeof(ReturnStmtNode));
    constructInPlace(ret);
    ret->expr = expr;
    ret->dbgLineNumber = lineNumber;
@@ -64,9 +64,9 @@ ReturnStmtNode *ReturnStmtNode::alloc( S32 lineNumber, ExprNode *expr)
    return ret;
 }
 
-IfStmtNode *IfStmtNode::alloc( S32 lineNumber, ExprNode *testExpr, StmtNode *ifBlock, StmtNode *elseBlock, bool propagate )
+IfStmtNode *IfStmtNode::alloc(S32 lineNumber, ExprNode *testExpr, StmtNode *ifBlock, StmtNode *elseBlock, bool propagate)
 {
-   IfStmtNode *ret = (IfStmtNode *) consoleAlloc(sizeof(IfStmtNode));
+   IfStmtNode *ret = (IfStmtNode *)consoleAlloc(sizeof(IfStmtNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
 
@@ -78,9 +78,9 @@ IfStmtNode *IfStmtNode::alloc( S32 lineNumber, ExprNode *testExpr, StmtNode *ifB
    return ret;
 }
 
-LoopStmtNode *LoopStmtNode::alloc( S32 lineNumber, ExprNode *initExpr, ExprNode *testExpr, ExprNode *endLoopExpr, StmtNode *loopBlock, bool isDoLoop )
+LoopStmtNode *LoopStmtNode::alloc(S32 lineNumber, ExprNode *initExpr, ExprNode *testExpr, ExprNode *endLoopExpr, StmtNode *loopBlock, bool isDoLoop)
 {
-   LoopStmtNode *ret = (LoopStmtNode *) consoleAlloc(sizeof(LoopStmtNode));
+   LoopStmtNode *ret = (LoopStmtNode *)consoleAlloc(sizeof(LoopStmtNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->testExpr = testExpr;
@@ -92,28 +92,28 @@ LoopStmtNode *LoopStmtNode::alloc( S32 lineNumber, ExprNode *initExpr, ExprNode
    // Deal with setting some dummy constant nodes if we weren't provided with
    // info... This allows us to play nice with missing parts of for(;;) for
    // instance.
-   if(!ret->testExpr) ret->testExpr = IntNode::alloc( lineNumber, 1 );
+   if (!ret->testExpr) ret->testExpr = IntNode::alloc(lineNumber, 1);
 
    return ret;
 }
 
-IterStmtNode* IterStmtNode::alloc( S32 lineNumber, StringTableEntry varName, ExprNode* containerExpr, StmtNode* body, bool isStringIter )
+IterStmtNode* IterStmtNode::alloc(S32 lineNumber, StringTableEntry varName, ExprNode* containerExpr, StmtNode* body, bool isStringIter)
 {
-   IterStmtNode* ret = ( IterStmtNode* ) consoleAlloc( sizeof( IterStmtNode ) );
-   constructInPlace( ret );
-   
+   IterStmtNode* ret = (IterStmtNode*)consoleAlloc(sizeof(IterStmtNode));
+   constructInPlace(ret);
+
    ret->dbgLineNumber = lineNumber;
    ret->varName = varName;
    ret->containerExpr = containerExpr;
    ret->body = body;
    ret->isStringIter = isStringIter;
-   
+
    return ret;
 }
 
-FloatBinaryExprNode *FloatBinaryExprNode::alloc( S32 lineNumber, S32 op, ExprNode *left, ExprNode *right )
+FloatBinaryExprNode *FloatBinaryExprNode::alloc(S32 lineNumber, S32 op, ExprNode *left, ExprNode *right)
 {
-   FloatBinaryExprNode *ret = (FloatBinaryExprNode *) consoleAlloc(sizeof(FloatBinaryExprNode));
+   FloatBinaryExprNode *ret = (FloatBinaryExprNode *)consoleAlloc(sizeof(FloatBinaryExprNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
 
@@ -124,9 +124,9 @@ FloatBinaryExprNode *FloatBinaryExprNode::alloc( S32 lineNumber, S32 op, ExprNod
    return ret;
 }
 
-IntBinaryExprNode *IntBinaryExprNode::alloc( S32 lineNumber, S32 op, ExprNode *left, ExprNode *right )
+IntBinaryExprNode *IntBinaryExprNode::alloc(S32 lineNumber, S32 op, ExprNode *left, ExprNode *right)
 {
-   IntBinaryExprNode *ret = (IntBinaryExprNode *) consoleAlloc(sizeof(IntBinaryExprNode));
+   IntBinaryExprNode *ret = (IntBinaryExprNode *)consoleAlloc(sizeof(IntBinaryExprNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
 
@@ -137,9 +137,9 @@ IntBinaryExprNode *IntBinaryExprNode::alloc( S32 lineNumber, S32 op, ExprNode *l
    return ret;
 }
 
-StreqExprNode *StreqExprNode::alloc( S32 lineNumber, ExprNode *left, ExprNode *right, bool eq )
+StreqExprNode *StreqExprNode::alloc(S32 lineNumber, ExprNode *left, ExprNode *right, bool eq)
 {
-   StreqExprNode *ret = (StreqExprNode *) consoleAlloc(sizeof(StreqExprNode));
+   StreqExprNode *ret = (StreqExprNode *)consoleAlloc(sizeof(StreqExprNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->left = left;
@@ -149,9 +149,9 @@ StreqExprNode *StreqExprNode::alloc( S32 lineNumber, ExprNode *left, ExprNode *r
    return ret;
 }
 
-StrcatExprNode *StrcatExprNode::alloc( S32 lineNumber, ExprNode *left, ExprNode *right, S32 appendChar )
+StrcatExprNode *StrcatExprNode::alloc(S32 lineNumber, ExprNode *left, ExprNode *right, S32 appendChar)
 {
-   StrcatExprNode *ret = (StrcatExprNode *) consoleAlloc(sizeof(StrcatExprNode));
+   StrcatExprNode *ret = (StrcatExprNode *)consoleAlloc(sizeof(StrcatExprNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->left = left;
@@ -161,9 +161,9 @@ StrcatExprNode *StrcatExprNode::alloc( S32 lineNumber, ExprNode *left, ExprNode
    return ret;
 }
 
-CommaCatExprNode *CommaCatExprNode::alloc( S32 lineNumber, ExprNode *left, ExprNode *right )
+CommaCatExprNode *CommaCatExprNode::alloc(S32 lineNumber, ExprNode *left, ExprNode *right)
 {
-   CommaCatExprNode *ret = (CommaCatExprNode *) consoleAlloc(sizeof(CommaCatExprNode));
+   CommaCatExprNode *ret = (CommaCatExprNode *)consoleAlloc(sizeof(CommaCatExprNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->left = left;
@@ -172,9 +172,9 @@ CommaCatExprNode *CommaCatExprNode::alloc( S32 lineNumber, ExprNode *left, ExprN
    return ret;
 }
 
-IntUnaryExprNode *IntUnaryExprNode::alloc( S32 lineNumber, S32 op, ExprNode *expr )
+IntUnaryExprNode *IntUnaryExprNode::alloc(S32 lineNumber, S32 op, ExprNode *expr)
 {
-   IntUnaryExprNode *ret = (IntUnaryExprNode *) consoleAlloc(sizeof(IntUnaryExprNode));
+   IntUnaryExprNode *ret = (IntUnaryExprNode *)consoleAlloc(sizeof(IntUnaryExprNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->op = op;
@@ -182,9 +182,9 @@ IntUnaryExprNode *IntUnaryExprNode::alloc( S32 lineNumber, S32 op, ExprNode *exp
    return ret;
 }
 
-FloatUnaryExprNode *FloatUnaryExprNode::alloc( S32 lineNumber, S32 op, ExprNode *expr )
+FloatUnaryExprNode *FloatUnaryExprNode::alloc(S32 lineNumber, S32 op, ExprNode *expr)
 {
-   FloatUnaryExprNode *ret = (FloatUnaryExprNode *) consoleAlloc(sizeof(FloatUnaryExprNode));
+   FloatUnaryExprNode *ret = (FloatUnaryExprNode *)consoleAlloc(sizeof(FloatUnaryExprNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->op = op;
@@ -192,9 +192,9 @@ FloatUnaryExprNode *FloatUnaryExprNode::alloc( S32 lineNumber, S32 op, ExprNode
    return ret;
 }
 
-VarNode *VarNode::alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex )
+VarNode *VarNode::alloc(S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex)
 {
-   VarNode *ret = (VarNode *) consoleAlloc(sizeof(VarNode));
+   VarNode *ret = (VarNode *)consoleAlloc(sizeof(VarNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->varName = varName;
@@ -202,18 +202,18 @@ VarNode *VarNode::alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arr
    return ret;
 }
 
-IntNode *IntNode::alloc( S32 lineNumber, S32 value )
+IntNode *IntNode::alloc(S32 lineNumber, S32 value)
 {
-   IntNode *ret = (IntNode *) consoleAlloc(sizeof(IntNode));
+   IntNode *ret = (IntNode *)consoleAlloc(sizeof(IntNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->value = value;
    return ret;
 }
 
-ConditionalExprNode *ConditionalExprNode::alloc( S32 lineNumber, ExprNode *testExpr, ExprNode *trueExpr, ExprNode *falseExpr )
+ConditionalExprNode *ConditionalExprNode::alloc(S32 lineNumber, ExprNode *testExpr, ExprNode *trueExpr, ExprNode *falseExpr)
 {
-   ConditionalExprNode *ret = (ConditionalExprNode *) consoleAlloc(sizeof(ConditionalExprNode));
+   ConditionalExprNode *ret = (ConditionalExprNode *)consoleAlloc(sizeof(ConditionalExprNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->testExpr = testExpr;
@@ -223,22 +223,22 @@ ConditionalExprNode *ConditionalExprNode::alloc( S32 lineNumber, ExprNode *testE
    return ret;
 }
 
-FloatNode *FloatNode::alloc( S32 lineNumber, F64 value )
+FloatNode *FloatNode::alloc(S32 lineNumber, F64 value)
 {
-   FloatNode *ret = (FloatNode *) consoleAlloc(sizeof(FloatNode));
+   FloatNode *ret = (FloatNode *)consoleAlloc(sizeof(FloatNode));
    constructInPlace(ret);
-   
+
    ret->dbgLineNumber = lineNumber;
    ret->value = value;
    return ret;
 }
 
-StrConstNode *StrConstNode::alloc( S32 lineNumber, char *str, bool tag, bool doc )
+StrConstNode *StrConstNode::alloc(S32 lineNumber, char *str, bool tag, bool doc)
 {
-   StrConstNode *ret = (StrConstNode *) consoleAlloc(sizeof(StrConstNode));
+   StrConstNode *ret = (StrConstNode *)consoleAlloc(sizeof(StrConstNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
-   ret->str = (char *) consoleAlloc(dStrlen(str) + 1);
+   ret->str = (char *)consoleAlloc(dStrlen(str) + 1);
    ret->tag = tag;
    ret->doc = doc;
    dStrcpy(ret->str, str);
@@ -246,18 +246,18 @@ StrConstNode *StrConstNode::alloc( S32 lineNumber, char *str, bool tag, bool doc
    return ret;
 }
 
-ConstantNode *ConstantNode::alloc( S32 lineNumber, StringTableEntry value )
+ConstantNode *ConstantNode::alloc(S32 lineNumber, StringTableEntry value)
 {
-   ConstantNode *ret = (ConstantNode *) consoleAlloc(sizeof(ConstantNode));
+   ConstantNode *ret = (ConstantNode *)consoleAlloc(sizeof(ConstantNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->value = value;
    return ret;
 }
 
-AssignExprNode *AssignExprNode::alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr )
+AssignExprNode *AssignExprNode::alloc(S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr)
 {
-   AssignExprNode *ret = (AssignExprNode *) consoleAlloc(sizeof(AssignExprNode));
+   AssignExprNode *ret = (AssignExprNode *)consoleAlloc(sizeof(AssignExprNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->varName = varName;
@@ -267,9 +267,9 @@ AssignExprNode *AssignExprNode::alloc( S32 lineNumber, StringTableEntry varName,
    return ret;
 }
 
-AssignOpExprNode *AssignOpExprNode::alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr, S32 op )
+AssignOpExprNode *AssignOpExprNode::alloc(S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr, S32 op)
 {
-   AssignOpExprNode *ret = (AssignOpExprNode *) consoleAlloc(sizeof(AssignOpExprNode));
+   AssignOpExprNode *ret = (AssignOpExprNode *)consoleAlloc(sizeof(AssignOpExprNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->varName = varName;
@@ -279,9 +279,9 @@ AssignOpExprNode *AssignOpExprNode::alloc( S32 lineNumber, StringTableEntry varN
    return ret;
 }
 
-TTagSetStmtNode *TTagSetStmtNode::alloc( S32 lineNumber, StringTableEntry tag, ExprNode *valueExpr, ExprNode *stringExpr )
+TTagSetStmtNode *TTagSetStmtNode::alloc(S32 lineNumber, StringTableEntry tag, ExprNode *valueExpr, ExprNode *stringExpr)
 {
-   TTagSetStmtNode *ret = (TTagSetStmtNode *) consoleAlloc(sizeof(TTagSetStmtNode));
+   TTagSetStmtNode *ret = (TTagSetStmtNode *)consoleAlloc(sizeof(TTagSetStmtNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->tag = tag;
@@ -290,37 +290,37 @@ TTagSetStmtNode *TTagSetStmtNode::alloc( S32 lineNumber, StringTableEntry tag, E
    return ret;
 }
 
-TTagDerefNode *TTagDerefNode::alloc( S32 lineNumber, ExprNode *expr )
+TTagDerefNode *TTagDerefNode::alloc(S32 lineNumber, ExprNode *expr)
 {
-   TTagDerefNode *ret = (TTagDerefNode *) consoleAlloc(sizeof(TTagDerefNode));
+   TTagDerefNode *ret = (TTagDerefNode *)consoleAlloc(sizeof(TTagDerefNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->expr = expr;
    return ret;
 }
 
-TTagExprNode *TTagExprNode::alloc( S32 lineNumber, StringTableEntry tag )
+TTagExprNode *TTagExprNode::alloc(S32 lineNumber, StringTableEntry tag)
 {
-   TTagExprNode *ret = (TTagExprNode *) consoleAlloc(sizeof(TTagExprNode));
+   TTagExprNode *ret = (TTagExprNode *)consoleAlloc(sizeof(TTagExprNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->tag = tag;
    return ret;
 }
 
-FuncCallExprNode *FuncCallExprNode::alloc( S32 lineNumber, StringTableEntry funcName, StringTableEntry nameSpace, ExprNode *args, bool dot )
+FuncCallExprNode *FuncCallExprNode::alloc(S32 lineNumber, StringTableEntry funcName, StringTableEntry nameSpace, ExprNode *args, bool dot)
 {
-   FuncCallExprNode *ret = (FuncCallExprNode *) consoleAlloc(sizeof(FuncCallExprNode));
+   FuncCallExprNode *ret = (FuncCallExprNode *)consoleAlloc(sizeof(FuncCallExprNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->funcName = funcName;
    ret->nameSpace = nameSpace;
    ret->args = args;
-   if(dot)
+   if (dot)
       ret->callType = MethodCall;
    else
    {
-      if(nameSpace && !dStricmp(nameSpace, "Parent"))
+      if (nameSpace && !dStricmp(nameSpace, "Parent"))
          ret->callType = ParentCall;
       else
          ret->callType = FunctionCall;
@@ -328,27 +328,37 @@ FuncCallExprNode *FuncCallExprNode::alloc( S32 lineNumber, StringTableEntry func
    return ret;
 }
 
-AssertCallExprNode *AssertCallExprNode::alloc( S32 lineNumber,  ExprNode *testExpr, const char *message )
+FuncPointerCallExprNode *FuncPointerCallExprNode::alloc(S32 lineNumber, ExprNode *funcPointer, ExprNode *args)
+{
+   FuncPointerCallExprNode *ret = (FuncPointerCallExprNode *)consoleAlloc(sizeof(FuncPointerCallExprNode));
+   constructInPlace(ret);
+   ret->dbgLineNumber = lineNumber;
+   ret->funcPointer = funcPointer;
+   ret->args = args;
+   return ret;
+}
+
+AssertCallExprNode *AssertCallExprNode::alloc(S32 lineNumber, ExprNode *testExpr, const char *message)
 {
-   #ifdef TORQUE_ENABLE_SCRIPTASSERTS      
+#ifdef TORQUE_ENABLE_SCRIPTASSERTS      
+
+   AssertCallExprNode *ret = (AssertCallExprNode *)consoleAlloc(sizeof(FuncCallExprNode));
+   constructInPlace(ret);
+   ret->dbgLineNumber = lineNumber;
+   ret->testExpr = testExpr;
+   ret->message = message ? message : "TorqueScript assert!";
+   return ret;
 
-      AssertCallExprNode *ret = (AssertCallExprNode *) consoleAlloc(sizeof(FuncCallExprNode));
-      constructInPlace(ret);
-      ret->dbgLineNumber = lineNumber;
-      ret->testExpr = testExpr;
-      ret->message = message ? message : "TorqueScript assert!";   
-      return ret;
-   
-   #else
+#else
 
-      return NULL;
+   return NULL;
 
-   #endif
+#endif
 }
 
-SlotAccessNode *SlotAccessNode::alloc( S32 lineNumber, ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName )
+SlotAccessNode *SlotAccessNode::alloc(S32 lineNumber, ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName)
 {
-   SlotAccessNode *ret = (SlotAccessNode *) consoleAlloc(sizeof(SlotAccessNode));
+   SlotAccessNode *ret = (SlotAccessNode *)consoleAlloc(sizeof(SlotAccessNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->objectExpr = objectExpr;
@@ -357,9 +367,9 @@ SlotAccessNode *SlotAccessNode::alloc( S32 lineNumber, ExprNode *objectExpr, Exp
    return ret;
 }
 
-InternalSlotAccessNode *InternalSlotAccessNode::alloc( S32 lineNumber, ExprNode *objectExpr, ExprNode *slotExpr, bool recurse )
+InternalSlotAccessNode *InternalSlotAccessNode::alloc(S32 lineNumber, ExprNode *objectExpr, ExprNode *slotExpr, bool recurse)
 {
-   InternalSlotAccessNode *ret = (InternalSlotAccessNode *) consoleAlloc(sizeof(InternalSlotAccessNode));
+   InternalSlotAccessNode *ret = (InternalSlotAccessNode *)consoleAlloc(sizeof(InternalSlotAccessNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->objectExpr = objectExpr;
@@ -368,9 +378,9 @@ InternalSlotAccessNode *InternalSlotAccessNode::alloc( S32 lineNumber, ExprNode
    return ret;
 }
 
-SlotAssignNode *SlotAssignNode::alloc( S32 lineNumber, ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName, ExprNode *valueExpr, U32 typeID /* = -1 */ )
+SlotAssignNode *SlotAssignNode::alloc(S32 lineNumber, ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName, ExprNode *valueExpr, U32 typeID /* = -1 */)
 {
-   SlotAssignNode *ret = (SlotAssignNode *) consoleAlloc(sizeof(SlotAssignNode));
+   SlotAssignNode *ret = (SlotAssignNode *)consoleAlloc(sizeof(SlotAssignNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->objectExpr = objectExpr;
@@ -381,9 +391,9 @@ SlotAssignNode *SlotAssignNode::alloc( S32 lineNumber, ExprNode *objectExpr, Exp
    return ret;
 }
 
-SlotAssignOpNode *SlotAssignOpNode::alloc( S32 lineNumber, ExprNode *objectExpr, StringTableEntry slotName, ExprNode *arrayExpr, S32 op, ExprNode *valueExpr )
+SlotAssignOpNode *SlotAssignOpNode::alloc(S32 lineNumber, ExprNode *objectExpr, StringTableEntry slotName, ExprNode *arrayExpr, S32 op, ExprNode *valueExpr)
 {
-   SlotAssignOpNode *ret = (SlotAssignOpNode *) consoleAlloc(sizeof(SlotAssignOpNode));
+   SlotAssignOpNode *ret = (SlotAssignOpNode *)consoleAlloc(sizeof(SlotAssignOpNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->objectExpr = objectExpr;
@@ -394,9 +404,9 @@ SlotAssignOpNode *SlotAssignOpNode::alloc( S32 lineNumber, ExprNode *objectExpr,
    return ret;
 }
 
-ObjectDeclNode *ObjectDeclNode::alloc( S32 lineNumber, ExprNode *classNameExpr, ExprNode *objectNameExpr, ExprNode *argList, StringTableEntry parentObject, SlotAssignNode *slotDecls, ObjectDeclNode *subObjects, bool isDatablock, bool classNameInternal, bool isSingleton )
+ObjectDeclNode *ObjectDeclNode::alloc(S32 lineNumber, ExprNode *classNameExpr, ExprNode *objectNameExpr, ExprNode *argList, StringTableEntry parentObject, SlotAssignNode *slotDecls, ObjectDeclNode *subObjects, bool isDatablock, bool classNameInternal, bool isSingleton)
 {
-   ObjectDeclNode *ret = (ObjectDeclNode *) consoleAlloc(sizeof(ObjectDeclNode));
+   ObjectDeclNode *ret = (ObjectDeclNode *)consoleAlloc(sizeof(ObjectDeclNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->classNameExpr = classNameExpr;
@@ -408,16 +418,16 @@ ObjectDeclNode *ObjectDeclNode::alloc( S32 lineNumber, ExprNode *classNameExpr,
    ret->isClassNameInternal = classNameInternal;
    ret->isSingleton = isSingleton;
    ret->failOffset = 0;
-   if(parentObject)
+   if (parentObject)
       ret->parentObject = parentObject;
    else
       ret->parentObject = StringTable->EmptyString();
    return ret;
 }
 
-FunctionDeclStmtNode *FunctionDeclStmtNode::alloc( S32 lineNumber, StringTableEntry fnName, StringTableEntry nameSpace, VarNode *args, StmtNode *stmts )
+FunctionDeclStmtNode *FunctionDeclStmtNode::alloc(S32 lineNumber, StringTableEntry fnName, StringTableEntry nameSpace, VarNode *args, StmtNode *stmts)
 {
-   FunctionDeclStmtNode *ret = (FunctionDeclStmtNode *) consoleAlloc(sizeof(FunctionDeclStmtNode));
+   FunctionDeclStmtNode *ret = (FunctionDeclStmtNode *)consoleAlloc(sizeof(FunctionDeclStmtNode));
    constructInPlace(ret);
    ret->dbgLineNumber = lineNumber;
    ret->fnName = fnName;

File diff suppressed because it is too large
+ 387 - 271
Engine/source/console/astNodes.cpp


File diff suppressed because it is too large
+ 1003 - 985
Engine/source/console/cmdgram.cpp


+ 72 - 72
Engine/source/console/cmdgram.h

@@ -15,78 +15,78 @@ typedef union {
    AssignDecl              asn;
    IfStmtNode*             ifnode;
 } YYSTYPE;
-#define  rwDEFINE 258
-#define  rwENDDEF 259
-#define  rwDECLARE   260
-#define  rwDECLARESINGLETON   261
-#define  rwBREAK  262
-#define  rwELSE   263
-#define  rwCONTINUE  264
-#define  rwGLOBAL 265
-#define  rwIF  266
-#define  rwNIL 267
-#define  rwRETURN 268
-#define  rwWHILE  269
-#define  rwDO  270
-#define  rwENDIF  271
-#define  rwENDWHILE  272
-#define  rwENDFOR 273
-#define  rwDEFAULT   274
-#define  rwFOR 275
-#define  rwFOREACH   276
-#define  rwFOREACHSTR   277
-#define  rwIN  278
-#define  rwDATABLOCK 279
-#define  rwSWITCH 280
-#define  rwCASE   281
-#define  rwSWITCHSTR 282
-#define  rwCASEOR 283
-#define  rwPACKAGE   284
-#define  rwNAMESPACE 285
-#define  rwCLASS  286
-#define  rwASSERT 287
-#define  ILLEGAL_TOKEN  288
-#define  CHRCONST 289
-#define  INTCONST 290
-#define  TTAG  291
-#define  VAR   292
-#define  IDENT 293
-#define  TYPEIDENT   294
-#define  DOCBLOCK 295
-#define  STRATOM  296
-#define  TAGATOM  297
-#define  FLTCONST 298
-#define  opINTNAME   299
-#define  opINTNAMER  300
-#define  opMINUSMINUS   301
-#define  opPLUSPLUS  302
-#define  STMT_SEP 303
-#define  opSHL 304
-#define  opSHR 305
-#define  opPLASN  306
-#define  opMIASN  307
-#define  opMLASN  308
-#define  opDVASN  309
-#define  opMODASN 310
-#define  opANDASN 311
-#define  opXORASN 312
-#define  opORASN  313
-#define  opSLASN  314
-#define  opSRASN  315
-#define  opCAT 316
-#define  opEQ  317
-#define  opNE  318
-#define  opGE  319
-#define  opLE  320
-#define  opAND 321
-#define  opOR  322
-#define  opSTREQ  323
-#define  opCOLONCOLON   324
-#define  opMDASN  325
-#define  opNDASN  326
-#define  opNTASN  327
-#define  opSTRNE  328
-#define  UNARY 329
+#define	rwDEFINE	258
+#define	rwENDDEF	259
+#define	rwDECLARE	260
+#define	rwDECLARESINGLETON	261
+#define	rwBREAK	262
+#define	rwELSE	263
+#define	rwCONTINUE	264
+#define	rwGLOBAL	265
+#define	rwIF	266
+#define	rwNIL	267
+#define	rwRETURN	268
+#define	rwWHILE	269
+#define	rwDO	270
+#define	rwENDIF	271
+#define	rwENDWHILE	272
+#define	rwENDFOR	273
+#define	rwDEFAULT	274
+#define	rwFOR	275
+#define	rwFOREACH	276
+#define	rwFOREACHSTR	277
+#define	rwIN	278
+#define	rwDATABLOCK	279
+#define	rwSWITCH	280
+#define	rwCASE	281
+#define	rwSWITCHSTR	282
+#define	rwCASEOR	283
+#define	rwPACKAGE	284
+#define	rwNAMESPACE	285
+#define	rwCLASS	286
+#define	rwASSERT	287
+#define	ILLEGAL_TOKEN	288
+#define	CHRCONST	289
+#define	INTCONST	290
+#define	TTAG	291
+#define	VAR	292
+#define	IDENT	293
+#define	TYPEIDENT	294
+#define	DOCBLOCK	295
+#define	STRATOM	296
+#define	TAGATOM	297
+#define	FLTCONST	298
+#define	opINTNAME	299
+#define	opINTNAMER	300
+#define	opMINUSMINUS	301
+#define	opPLUSPLUS	302
+#define	STMT_SEP	303
+#define	opSHL	304
+#define	opSHR	305
+#define	opPLASN	306
+#define	opMIASN	307
+#define	opMLASN	308
+#define	opDVASN	309
+#define	opMODASN	310
+#define	opANDASN	311
+#define	opXORASN	312
+#define	opORASN	313
+#define	opSLASN	314
+#define	opSRASN	315
+#define	opCAT	316
+#define	opEQ	317
+#define	opNE	318
+#define	opGE	319
+#define	opLE	320
+#define	opAND	321
+#define	opOR	322
+#define	opSTREQ	323
+#define	opCOLONCOLON	324
+#define	opMDASN	325
+#define	opNDASN	326
+#define	opNTASN	327
+#define	opSTRNE	328
+#define	UNARY	329
 
 
 extern YYSTYPE CMDlval;

File diff suppressed because it is too large
+ 366 - 294
Engine/source/console/codeBlock.cpp


+ 7 - 6
Engine/source/console/codeBlock.h

@@ -35,10 +35,11 @@ class ConsoleValueRef;
 /// This class represents a block of code, usually mapped directly to a file.
 class CodeBlock
 {
+   friend class CodeInterpreter;
 private:
    static CodeBlock* smCodeBlockList;
    static CodeBlock* smCurrentCodeBlock;
-   
+
 public:
    static bool                      smInFunction;
    static Compiler::ConsoleParser * smCurrentParser;
@@ -89,7 +90,7 @@ public:
    void calcBreakList();
    void clearAllBreaks();
    void setAllBreaks();
-   void dumpInstructions( U32 startIp = 0, bool upToReturn = false );
+   void dumpInstructions(U32 startIp = 0, bool upToReturn = false);
 
    /// Returns the first breakable line or 0 if none was found.
    /// @param lineNumber The one based line number.
@@ -106,7 +107,7 @@ public:
    const char *getFileLine(U32 ip);
 
    /// 
-   String getFunctionArgs( U32 offset );
+   String getFunctionArgs(U32 offset);
 
    bool read(StringTableEntry fileName, Stream &st);
    bool compile(const char *dsoName, StringTableEntry fileName, const char *script, bool overrideNoDso = false);
@@ -129,8 +130,8 @@ public:
    /// with, zero being the top of the stack. If the the index is
    /// -1 a new frame is created. If the index is out of range the
    /// top stack frame is used.
-   ConsoleValueRef compileExec(StringTableEntry fileName, const char *script, 
-      bool noCalls, S32 setFrame = -1 );
+   ConsoleValueRef compileExec(StringTableEntry fileName, const char *script,
+      bool noCalls, S32 setFrame = -1);
 
    /// Executes the existing code in the CodeBlock. The return string is any 
    /// result of the code executed, if any, or an empty string.
@@ -147,7 +148,7 @@ public:
    /// -1 a new frame is created. If the index is out of range the
    /// top stack frame is used.
    /// @param packageName The code package name or null.
-   ConsoleValueRef exec(U32 offset, const char *fnName, Namespace *ns, U32 argc, 
+   ConsoleValueRef exec(U32 offset, const char *fnName, Namespace *ns, U32 argc,
       ConsoleValueRef *argv, bool noCalls, StringTableEntry packageName,
       S32 setFrame = -1);
 };

+ 2979 - 0
Engine/source/console/codeInterpreter.cpp

@@ -0,0 +1,2979 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
+// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
+// Copyright (C) 2015 Faust Logic, Inc.
+//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
+
+#include "console/codeInterpreter.h"
+#include "console/compiler.h"
+#include "console/simBase.h"
+#include "console/telnetDebugger.h"
+#include "sim/netStringTable.h"
+#include "console/ICallMethod.h"
+#include "console/stringStack.h"
+#include "util/messaging/message.h"
+#include "core/strings/findMatch.h"
+#include "core/strings/stringUnit.h"
+#include "console/console.h"
+#include "console/consoleInternal.h"
+
+//#define TORQUE_VALIDATE_STACK
+
+using namespace Compiler;
+
+enum EvalConstants
+{
+   MaxStackSize = 1024,
+   FieldBufferSizeString = 2048,
+   FieldBufferSizeNumeric = 128,
+   MethodOnComponent = -2
+};
+
+namespace Con
+{
+   // Current script file name and root, these are registered as
+   // console variables.
+   extern StringTableEntry gCurrentFile;
+   extern StringTableEntry gCurrentRoot;
+   extern S32 gObjectCopyFailures;
+}
+
+// Gets a component of an object's field value or a variable and returns it
+// in val.
+static void getFieldComponent(SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField, char val[])
+{
+   const char* prevVal = NULL;
+
+   // Grab value from object.
+   if (object && field)
+      prevVal = object->getDataField(field, array);
+
+   // Otherwise, grab from the string stack. The value coming in will always
+   // be a string because that is how multicomponent variables are handled.
+   else
+      prevVal = STR.getStringValue();
+
+   // Make sure we got a value.
+   if (prevVal && *prevVal)
+   {
+      static const StringTableEntry xyzw[] =
+      {
+         StringTable->insert("x"),
+         StringTable->insert("y"),
+         StringTable->insert("z"),
+         StringTable->insert("w")
+      };
+
+      static const StringTableEntry rgba[] =
+      {
+         StringTable->insert("r"),
+         StringTable->insert("g"),
+         StringTable->insert("b"),
+         StringTable->insert("a")
+      };
+
+      // Translate xyzw and rgba into the indexed component 
+      // of the variable or field.
+      //
+      // Review: Should we use strncpy to prevent a buffer overflow?
+      if (subField == xyzw[0] || subField == rgba[0])
+         dStrcpy(val, StringUnit::getUnit(prevVal, 0, " \t\n"));
+
+      else if (subField == xyzw[1] || subField == rgba[1])
+         dStrcpy(val, StringUnit::getUnit(prevVal, 1, " \t\n"));
+
+      else if (subField == xyzw[2] || subField == rgba[2])
+         dStrcpy(val, StringUnit::getUnit(prevVal, 2, " \t\n"));
+
+      else if (subField == xyzw[3] || subField == rgba[3])
+         dStrcpy(val, StringUnit::getUnit(prevVal, 3, " \t\n"));
+
+      else
+         val[0] = 0;
+   }
+   else
+      val[0] = 0;
+}
+
+// Sets a component of an object's field value based on the sub field. 'x' will
+// set the first field, 'y' the second, and 'z' the third.
+static void setFieldComponent(SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField)
+{
+   // Copy the current string value
+   char strValue[1024];
+   dStrncpy(strValue, STR.getStringValue(), 1024);
+
+   char val[1024] = "";
+   const char* prevVal = NULL;
+
+   // Set the value on an object field.
+   if (object && field)
+      prevVal = object->getDataField(field, array);
+
+   // Set the value on a variable.
+   else if (gEvalState.currentVariable)
+      prevVal = gEvalState.getStringVariable();
+
+   // Ensure that the variable has a value
+   if (!prevVal)
+      return;
+
+   static const StringTableEntry xyzw[] =
+   {
+      StringTable->insert("x"),
+      StringTable->insert("y"),
+      StringTable->insert("z"),
+      StringTable->insert("w")
+   };
+
+   static const StringTableEntry rgba[] =
+   {
+      StringTable->insert("r"),
+      StringTable->insert("g"),
+      StringTable->insert("b"),
+      StringTable->insert("a")
+   };
+
+   // Insert the value into the specified 
+   // component of the string.
+   //
+   // Review: Should we use strncpy to prevent a buffer overflow?
+   if (subField == xyzw[0] || subField == rgba[0])
+      dStrcpy(val, StringUnit::setUnit(prevVal, 0, strValue, " \t\n"));
+
+   else if (subField == xyzw[1] || subField == rgba[1])
+      dStrcpy(val, StringUnit::setUnit(prevVal, 1, strValue, " \t\n"));
+
+   else if (subField == xyzw[2] || subField == rgba[2])
+      dStrcpy(val, StringUnit::setUnit(prevVal, 2, strValue, " \t\n"));
+
+   else if (subField == xyzw[3] || subField == rgba[3])
+      dStrcpy(val, StringUnit::setUnit(prevVal, 3, strValue, " \t\n"));
+
+   if (val[0] != 0)
+   {
+      // Update the field or variable.
+      if (object && field)
+         object->setDataField(field, 0, val);
+      else if (gEvalState.currentVariable)
+         gEvalState.setStringVariable(val);
+   }
+}
+extern ExprEvalState gEvalState;
+
+char sTraceBuffer[1024];
+
+StringStack STR;
+ConsoleValueStack CSTK;
+
+U32 _FLT = 0;     ///< Stack pointer for floatStack.
+U32 _UINT = 0;    ///< Stack pointer for intStack.
+U32 _ITER = 0;    ///< Stack pointer for iterStack.
+
+IterStackRecord iterStack[MaxStackSize];
+
+F64 floatStack[MaxStackSize];
+S64 intStack[MaxStackSize];
+
+char curFieldArray[256];
+char prevFieldArray[256];
+
+typedef OPCodeReturn(CodeInterpreter::*OpFn)(U32&);
+
+static OpFn gOpCodeArray[MAX_OP_CODELEN];
+
+CodeInterpreter::CodeInterpreter(CodeBlock *cb) :
+   mCodeBlock(cb),
+   mIterDepth(0),
+   mCurFloatTable(nullptr),
+   mCurStringTable(nullptr),
+   mThisFunctionName(nullptr),
+   mPopFrame(false),
+   mObjectCreationStackIndex(0),
+   mCurrentNewObject(nullptr),
+   mFailJump(0),
+   mPrevField(nullptr),
+   mCurField(nullptr),
+   mPrevObject(nullptr),
+   mCurObject(nullptr),
+   mSaveObject(nullptr),
+   mThisObject(nullptr),
+   mNSEntry(nullptr),
+   mCurFNDocBlock(nullptr),
+   mCurNSDocBlock(nullptr),
+   mCallArgc(0),
+   mCallArgv(nullptr),
+   mSaveCodeBlock(nullptr),
+   mCurrentInstruction(0)
+{
+}
+
+CodeInterpreter::~CodeInterpreter()
+{
+}
+
+void CodeInterpreter::init()
+{
+   gOpCodeArray[OP_FUNC_DECL] = &CodeInterpreter::op_func_decl;
+   gOpCodeArray[OP_CREATE_OBJECT] = &CodeInterpreter::op_create_object;
+   gOpCodeArray[OP_ADD_OBJECT] = &CodeInterpreter::op_add_object;
+   gOpCodeArray[OP_END_OBJECT] = &CodeInterpreter::op_end_object;
+   gOpCodeArray[OP_FINISH_OBJECT] = &CodeInterpreter::op_finish_object;
+   gOpCodeArray[OP_JMPIFFNOT] = &CodeInterpreter::op_jmpiffnot;
+   gOpCodeArray[OP_JMPIFNOT] = &CodeInterpreter::op_jmpifnot;
+   gOpCodeArray[OP_JMPIFF] = &CodeInterpreter::op_jmpiff;
+   gOpCodeArray[OP_JMPIF] = &CodeInterpreter::op_jmpif;
+   gOpCodeArray[OP_JMPIFNOT_NP] = &CodeInterpreter::op_jmpifnot_np;
+   gOpCodeArray[OP_JMPIF_NP] = &CodeInterpreter::op_jmpif_np;
+   gOpCodeArray[OP_JMP] = &CodeInterpreter::op_jmp;
+   gOpCodeArray[OP_RETURN] = &CodeInterpreter::op_return;
+   gOpCodeArray[OP_RETURN_VOID] = &CodeInterpreter::op_return_void;
+   gOpCodeArray[OP_RETURN_FLT] = &CodeInterpreter::op_return_flt;
+   gOpCodeArray[OP_RETURN_UINT] = &CodeInterpreter::op_return_uint;
+   gOpCodeArray[OP_CMPEQ] = &CodeInterpreter::op_cmpeq;
+   gOpCodeArray[OP_CMPGR] = &CodeInterpreter::op_cmpgr;
+   gOpCodeArray[OP_CMPGE] = &CodeInterpreter::op_cmpge;
+   gOpCodeArray[OP_CMPLT] = &CodeInterpreter::op_cmplt;
+   gOpCodeArray[OP_CMPLE] = &CodeInterpreter::op_cmple;
+   gOpCodeArray[OP_CMPNE] = &CodeInterpreter::op_cmpne;
+   gOpCodeArray[OP_XOR] = &CodeInterpreter::op_xor;
+   gOpCodeArray[OP_MOD] = &CodeInterpreter::op_mod;
+   gOpCodeArray[OP_BITAND] = &CodeInterpreter::op_bitand;
+   gOpCodeArray[OP_BITOR] = &CodeInterpreter::op_bitor;
+   gOpCodeArray[OP_NOT] = &CodeInterpreter::op_not;
+   gOpCodeArray[OP_NOTF] = &CodeInterpreter::op_notf;
+   gOpCodeArray[OP_ONESCOMPLEMENT] = &CodeInterpreter::op_onescomplement;
+   gOpCodeArray[OP_SHR] = &CodeInterpreter::op_shr;
+   gOpCodeArray[OP_SHL] = &CodeInterpreter::op_shl;
+   gOpCodeArray[OP_AND] = &CodeInterpreter::op_and;
+   gOpCodeArray[OP_OR] = &CodeInterpreter::op_or;
+   gOpCodeArray[OP_ADD] = &CodeInterpreter::op_add;
+   gOpCodeArray[OP_SUB] = &CodeInterpreter::op_sub;
+   gOpCodeArray[OP_MUL] = &CodeInterpreter::op_mul;
+   gOpCodeArray[OP_DIV] = &CodeInterpreter::op_div;
+   gOpCodeArray[OP_NEG] = &CodeInterpreter::op_neg;
+   gOpCodeArray[OP_INC] = &CodeInterpreter::op_inc;
+   gOpCodeArray[OP_DEC] = &CodeInterpreter::op_dec;
+   gOpCodeArray[OP_SETCURVAR] = &CodeInterpreter::op_setcurvar;
+   gOpCodeArray[OP_SETCURVAR_CREATE] = &CodeInterpreter::op_setcurvar_create;
+   gOpCodeArray[OP_SETCURVAR_ARRAY] = &CodeInterpreter::op_setcurvar_array;
+   gOpCodeArray[OP_SETCURVAR_ARRAY_VARLOOKUP] = &CodeInterpreter::op_setcurvar_array_varlookup;
+   gOpCodeArray[OP_SETCURVAR_ARRAY_CREATE] = &CodeInterpreter::op_setcurvar_array_create;
+   gOpCodeArray[OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP] = &CodeInterpreter::op_setcurvar_array_create_varlookup;
+   gOpCodeArray[OP_LOADVAR_UINT] = &CodeInterpreter::op_loadvar_uint;
+   gOpCodeArray[OP_LOADVAR_FLT] = &CodeInterpreter::op_loadvar_flt;
+   gOpCodeArray[OP_LOADVAR_STR] = &CodeInterpreter::op_loadvar_str;
+   gOpCodeArray[OP_LOADVAR_VAR] = &CodeInterpreter::op_loadvar_var;
+   gOpCodeArray[OP_SAVEVAR_UINT] = &CodeInterpreter::op_savevar_uint;
+   gOpCodeArray[OP_SAVEVAR_FLT] = &CodeInterpreter::op_savevar_flt;
+   gOpCodeArray[OP_SAVEVAR_STR] = &CodeInterpreter::op_savevar_str;
+   gOpCodeArray[OP_SAVEVAR_VAR] = &CodeInterpreter::op_savevar_var;
+   gOpCodeArray[OP_SETCUROBJECT] = &CodeInterpreter::op_setcurobject;
+   gOpCodeArray[OP_SETCUROBJECT_INTERNAL] = &CodeInterpreter::op_setcurobject_internal;
+   gOpCodeArray[OP_SETCUROBJECT_NEW] = &CodeInterpreter::op_setcurobject_new;
+   gOpCodeArray[OP_SETCURFIELD] = &CodeInterpreter::op_setcurfield;
+   gOpCodeArray[OP_SETCURFIELD_ARRAY] = &CodeInterpreter::op_setcurfield_array;
+   gOpCodeArray[OP_SETCURFIELD_TYPE] = &CodeInterpreter::op_setcurfield_type;
+   gOpCodeArray[OP_SETCURFIELD_ARRAY_VAR] = &CodeInterpreter::op_setcurfield_array_var;
+   gOpCodeArray[OP_SETCURFIELD_THIS] = &CodeInterpreter::op_setcurfield_this;
+   gOpCodeArray[OP_LOADFIELD_UINT] = &CodeInterpreter::op_loadfield_uint;
+   gOpCodeArray[OP_LOADFIELD_FLT] = &CodeInterpreter::op_loadfield_flt;
+   gOpCodeArray[OP_LOADFIELD_STR] = &CodeInterpreter::op_loadfield_str;
+   gOpCodeArray[OP_SAVEFIELD_UINT] = &CodeInterpreter::op_savefield_uint;
+   gOpCodeArray[OP_SAVEFIELD_FLT] = &CodeInterpreter::op_savefield_flt;
+   gOpCodeArray[OP_SAVEFIELD_STR] = &CodeInterpreter::op_savefield_str;
+   gOpCodeArray[OP_STR_TO_UINT] = &CodeInterpreter::op_str_to_uint;
+   gOpCodeArray[OP_STR_TO_FLT] = &CodeInterpreter::op_str_to_flt;
+   gOpCodeArray[OP_STR_TO_NONE] = &CodeInterpreter::op_str_to_none;
+   gOpCodeArray[OP_FLT_TO_UINT] = &CodeInterpreter::op_flt_to_uint;
+   gOpCodeArray[OP_FLT_TO_STR] = &CodeInterpreter::op_flt_to_str;
+   gOpCodeArray[OP_FLT_TO_NONE] = &CodeInterpreter::op_flt_to_none;
+   gOpCodeArray[OP_UINT_TO_FLT] = &CodeInterpreter::op_uint_to_flt;
+   gOpCodeArray[OP_UINT_TO_STR] = &CodeInterpreter::op_uint_to_str;
+   gOpCodeArray[OP_UINT_TO_NONE] = &CodeInterpreter::op_uint_to_none;
+   gOpCodeArray[OP_COPYVAR_TO_NONE] = &CodeInterpreter::op_copyvar_to_none;
+   gOpCodeArray[OP_LOADIMMED_UINT] = &CodeInterpreter::op_loadimmed_uint;
+   gOpCodeArray[OP_LOADIMMED_FLT] = &CodeInterpreter::op_loadimmed_flt;
+   gOpCodeArray[OP_TAG_TO_STR] = &CodeInterpreter::op_tag_to_str;
+   gOpCodeArray[OP_LOADIMMED_STR] = &CodeInterpreter::op_loadimmed_str;
+   gOpCodeArray[OP_DOCBLOCK_STR] = &CodeInterpreter::op_docblock_str;
+   gOpCodeArray[OP_LOADIMMED_IDENT] = &CodeInterpreter::op_loadimmed_ident;
+   gOpCodeArray[OP_CALLFUNC_RESOLVE] = &CodeInterpreter::op_callfunc_resolve;
+   gOpCodeArray[OP_CALLFUNC] = &CodeInterpreter::op_callfunc;
+   gOpCodeArray[OP_CALLFUNC_POINTER] = &CodeInterpreter::op_callfunc_pointer;
+   gOpCodeArray[OP_CALLFUNC_THIS] = &CodeInterpreter::op_callfunc_this;
+   gOpCodeArray[OP_ADVANCE_STR] = &CodeInterpreter::op_advance_str;
+   gOpCodeArray[OP_ADVANCE_STR_APPENDCHAR] = &CodeInterpreter::op_advance_str_appendchar;
+   gOpCodeArray[OP_ADVANCE_STR_COMMA] = &CodeInterpreter::op_advance_str_comma;
+   gOpCodeArray[OP_ADVANCE_STR_NUL] = &CodeInterpreter::op_advance_str_nul;
+   gOpCodeArray[OP_REWIND_STR] = &CodeInterpreter::op_rewind_str;
+   gOpCodeArray[OP_TERMINATE_REWIND_STR] = &CodeInterpreter::op_terminate_rewind_str;
+   gOpCodeArray[OP_COMPARE_STR] = &CodeInterpreter::op_compare_str;
+   gOpCodeArray[OP_PUSH] = &CodeInterpreter::op_push;
+   gOpCodeArray[OP_PUSH_UINT] = &CodeInterpreter::op_push_uint;
+   gOpCodeArray[OP_PUSH_FLT] = &CodeInterpreter::op_push_flt;
+   gOpCodeArray[OP_PUSH_VAR] = &CodeInterpreter::op_push_var;
+   gOpCodeArray[OP_PUSH_THIS] = &CodeInterpreter::op_push_this;
+   gOpCodeArray[OP_PUSH_FRAME] = &CodeInterpreter::op_push_frame;
+   gOpCodeArray[OP_ASSERT] = &CodeInterpreter::op_assert;
+   gOpCodeArray[OP_BREAK] = &CodeInterpreter::op_break;
+   gOpCodeArray[OP_ITER_BEGIN_STR] = &CodeInterpreter::op_iter_begin_str;
+   gOpCodeArray[OP_ITER_BEGIN] = &CodeInterpreter::op_iter_begin;
+   gOpCodeArray[OP_ITER] = &CodeInterpreter::op_iter;
+   gOpCodeArray[OP_ITER_END] = &CodeInterpreter::op_iter_end;
+   gOpCodeArray[OP_INVALID] = &CodeInterpreter::op_invalid;
+}
+
+ConsoleValueRef CodeInterpreter::exec(U32 ip,
+                                      StringTableEntry functionName,
+                                      Namespace *thisNamespace,
+                                      U32 argc, 
+                                      ConsoleValueRef *argv,
+                                      bool noCalls,
+                                      StringTableEntry packageName,
+                                      S32 setFrame) 
+{
+   mExec.functionName = functionName;
+   mExec.thisNamespace = thisNamespace;
+   mExec.argc = argc;
+   mExec.argv = argv;
+   mExec.noCalls = noCalls;
+   mExec.packageName = packageName;
+   mExec.setFrame = setFrame;
+
+   mCodeBlock->incRefCount();
+
+   mPopFrame = false;
+
+#ifdef TORQUE_VALIDATE_STACK
+   U32 stackStart = STR.mStartStackSize;
+#endif
+
+   STR.clearFunctionOffset(); // ensures arg buffer offset is back to 0
+
+   // Lets load up our function arguments.
+   parseArgs(ip);
+
+   // Grab the state of the telenet debugger here once
+   // so that the push and pop frames are always balanced.
+   const bool telDebuggerOn = TelDebugger && TelDebugger->isConnected();
+   if (telDebuggerOn && setFrame < 0)
+      TelDebugger->pushStackFrame();
+
+   mSaveCodeBlock = CodeBlock::smCurrentCodeBlock;
+   CodeBlock::smCurrentCodeBlock = mCodeBlock;
+   if (mCodeBlock->name)
+   {
+      Con::gCurrentFile = mCodeBlock->name;
+      Con::gCurrentRoot = mCodeBlock->modPath;
+   }
+
+   U32 *code = mCodeBlock->code;
+
+   while (true)
+   {
+      mCurrentInstruction = code[ip++];
+      mNSEntry = nullptr;
+
+#ifdef TORQUE_VALIDATE_STACK
+      // OP Code check.
+      AssertFatal(mCurrentInstruction < MAX_OP_CODELEN, "Invalid OP code in script interpreter");
+#endif
+
+   breakContinueLabel:
+      OPCodeReturn ret = (this->*gOpCodeArray[mCurrentInstruction])(ip);
+      if (ret == OPCodeReturn::exitCode)
+         goto exitLabel;
+      else if (ret == OPCodeReturn::breakContinue)
+         goto breakContinueLabel;
+   }
+exitLabel:
+   if (telDebuggerOn && setFrame < 0)
+      TelDebugger->popStackFrame();
+
+   if (mPopFrame)
+      gEvalState.popFrame();
+
+   if (argv)
+   {
+      if (gEvalState.traceOn)
+      {
+         sTraceBuffer[0] = 0;
+         dStrcat(sTraceBuffer, "Leaving ");
+
+         if (packageName)
+         {
+            dStrcat(sTraceBuffer, "[");
+            dStrcat(sTraceBuffer, packageName);
+            dStrcat(sTraceBuffer, "]");
+         }
+         if (thisNamespace && thisNamespace->mName)
+         {
+            dSprintf(sTraceBuffer + dStrlen(sTraceBuffer), sizeof(sTraceBuffer) - dStrlen(sTraceBuffer),
+               "%s::%s() - return %s", thisNamespace->mName, mThisFunctionName, STR.getStringValue());
+         }
+         else
+         {
+            dSprintf(sTraceBuffer + dStrlen(sTraceBuffer), sizeof(sTraceBuffer) - dStrlen(sTraceBuffer),
+               "%s() - return %s", mThisFunctionName, STR.getStringValue());
+         }
+         Con::printf("%s", sTraceBuffer);
+      }
+   }
+
+   CodeBlock::smCurrentCodeBlock = mSaveCodeBlock;
+   if (mSaveCodeBlock && mSaveCodeBlock->name)
+   {
+      Con::gCurrentFile = mSaveCodeBlock->name;
+      Con::gCurrentRoot = mSaveCodeBlock->modPath;
+   }
+
+   mCodeBlock->decRefCount();
+
+#ifdef TORQUE_VALIDATE_STACK
+   AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec");
+   AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec");
+#endif
+
+   return mReturnValue;
+}
+
+void CodeInterpreter::parseArgs(U32 &ip)
+{
+   U32 *code = mCodeBlock->code;
+
+   if (mExec.argv)
+   {
+      U32 fnArgc = code[ip + 2 + 6];
+      mThisFunctionName = Compiler::CodeToSTE(code, ip);
+      S32 wantedArgc = getMin(mExec.argc - 1, fnArgc); // argv[0] is func name
+      if (gEvalState.traceOn)
+      {
+         sTraceBuffer[0] = 0;
+         dStrcat(sTraceBuffer, "Entering ");
+
+         if (mExec.packageName)
+         {
+            dStrcat(sTraceBuffer, "[");
+            dStrcat(sTraceBuffer, mExec.packageName);
+            dStrcat(sTraceBuffer, "]");
+         }
+         if (mExec.thisNamespace && mExec.thisNamespace->mName)
+         {
+            dSprintf(sTraceBuffer + dStrlen(sTraceBuffer), sizeof(sTraceBuffer) - dStrlen(sTraceBuffer),
+               "%s::%s(", mExec.thisNamespace->mName, mThisFunctionName);
+         }
+         else
+         {
+            dSprintf(sTraceBuffer + dStrlen(sTraceBuffer), sizeof(sTraceBuffer) - dStrlen(sTraceBuffer),
+               "%s(", mThisFunctionName);
+         }
+         for (S32 i = 0; i < wantedArgc; i++)
+         {
+            dStrcat(sTraceBuffer, mExec.argv[i + 1]);
+            if (i != wantedArgc - 1)
+               dStrcat(sTraceBuffer, ", ");
+         }
+         dStrcat(sTraceBuffer, ")");
+         Con::printf("%s", sTraceBuffer);
+      }
+
+      gEvalState.pushFrame(mThisFunctionName, mExec.thisNamespace);
+      mPopFrame = true;
+
+      StringTableEntry thisPointer = StringTable->insert("%this");
+
+      for (S32 i = 0; i < wantedArgc; i++)
+      {
+         StringTableEntry var = Compiler::CodeToSTE(code, ip + (2 + 6 + 1) + (i * 2));
+         gEvalState.setCurVarNameCreate(var);
+
+         ConsoleValueRef ref = mExec.argv[i + 1];
+
+         switch (ref.getType())
+         {
+         case ConsoleValue::TypeInternalInt:
+            gEvalState.setIntVariable(ref);
+            break;
+         case ConsoleValue::TypeInternalFloat:
+            gEvalState.setFloatVariable(ref);
+            break;
+         case ConsoleValue::TypeInternalStringStackPtr:
+            gEvalState.setStringStackPtrVariable(ref.getStringStackPtrValue());
+            break;
+         case ConsoleValue::TypeInternalStackString:
+         case ConsoleValue::TypeInternalString:
+         default:
+            gEvalState.setStringVariable(ref);
+            break;
+         }
+
+         if (var == thisPointer)
+         {
+            // %this gets optimized as it is flagged as a constant.
+            // Since it is guarenteed to be constant, we can then perform optimizations.
+            gEvalState.currentVariable->mIsConstant = true;
+
+            // Store a reference to the this pointer object.
+            mThisObject = Sim::findObject(gEvalState.getStringVariable());
+         }
+      }
+
+      ip = ip + (fnArgc * 2) + (2 + 6 + 1);
+      mCurFloatTable = mCodeBlock->functionFloats;
+      mCurStringTable = mCodeBlock->functionStrings;
+   }
+   else
+   {
+      mCurFloatTable = mCodeBlock->globalFloats;
+      mCurStringTable = mCodeBlock->globalStrings;
+
+      // If requested stack frame isn't available, request a new one
+      // (this prevents assert failures when creating local
+      //  variables without a stack frame)
+      if (gEvalState.getStackDepth() <= mExec.setFrame)
+         mExec.setFrame = -1;
+
+      // Do we want this code to execute using a new stack frame?
+      if (mExec.setFrame < 0)
+      {
+         gEvalState.pushFrame(NULL, NULL);
+         mPopFrame = true;
+      }
+      else
+      {
+         // We want to copy a reference to an existing stack frame
+         // on to the top of the stack.  Any change that occurs to 
+         // the locals during this new frame will also occur in the 
+         // original frame.
+         S32 stackIndex = gEvalState.getStackDepth() - mExec.setFrame - 1;
+         gEvalState.pushFrameRef(stackIndex);
+         mPopFrame = true;
+      }
+   }
+}
+
+OPCodeReturn CodeInterpreter::op_func_decl(U32 &ip)
+{
+   U32 *code = mCodeBlock->code;
+
+   if (!mExec.noCalls)
+   {
+      StringTableEntry fnName = CodeToSTE(code, ip);
+      StringTableEntry fnNamespace = CodeToSTE(code, ip + 2);
+      StringTableEntry fnPackage = CodeToSTE(code, ip + 4);
+      bool hasBody = (code[ip + 6] & 0x01) != 0;
+      U32 lineNumber = code[ip + 6] >> 1;
+
+      Namespace::unlinkPackages();
+      Namespace *ns = Namespace::find(fnNamespace, fnPackage);
+      ns->addFunction(fnName, mCodeBlock, hasBody ? ip : 0, mCurFNDocBlock ? dStrdup(mCurFNDocBlock) : NULL, lineNumber);// if no body, set the IP to 0
+      if (mCurNSDocBlock)
+      {
+         // If we have a docblock before we declare the function in the script file,
+         // this will attempt to set the doc block to the function.
+         // See OP_DOCBLOCK_STR
+         if (fnNamespace == StringTable->lookup(mNSDocBlockClass))
+         {
+            char *usageStr = dStrdup(mCurNSDocBlock);
+            usageStr[dStrlen(usageStr)] = '\0';
+            ns->mUsage = usageStr;
+            ns->mCleanUpUsage = true;
+            mCurNSDocBlock = NULL;
+         }
+      }
+      Namespace::relinkPackages();
+
+      // If we had a docblock, it's definitely not valid anymore, so clear it out.
+      mCurFNDocBlock = NULL;
+
+      //Con::printf("Adding function %s::%s (%d)", fnNamespace, fnName, ip);
+   }
+   ip = code[ip + 7];
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_create_object(U32 &ip)
+{
+   U32 *code = mCodeBlock->code;
+
+   // Read some useful info.
+   StringTableEntry objParent = CodeToSTE(code, ip);
+   bool isDataBlock = code[ip + 2];
+   bool isInternal = code[ip + 3];
+   bool isSingleton = code[ip + 4];
+   U32  lineNumber = code[ip + 5];
+   mFailJump = code[ip + 6];
+
+   // If we don't allow calls, we certainly don't allow creating objects!
+   // Moved this to after failJump is set. Engine was crashing when
+   // noCalls = true and an object was being created at the beginning of
+   // a file. ADL.
+   if (mExec.noCalls)
+   {
+      ip = mFailJump;
+      return OPCodeReturn::success;
+   }
+
+   // Push the old info to the stack
+   //Assert( objectCreationStackIndex < objectCreationStackSize );
+   mObjectCreationStack[mObjectCreationStackIndex].newObject = mCurrentNewObject;
+   mObjectCreationStack[mObjectCreationStackIndex++].failJump = mFailJump;
+
+   // Get the constructor information off the stack.
+   CSTK.getArgcArgv(NULL, &mCallArgc, &mCallArgv);
+   const char *objectName = mCallArgv[2];
+
+   // Con::printf("Creating object...");
+
+   // objectName = argv[1]...
+   mCurrentNewObject = NULL;
+
+   // Are we creating a datablock? If so, deal with case where we override
+   // an old one.
+   if (isDataBlock)
+   {
+      // Con::printf("  - is a datablock");
+
+      // Find the old one if any.
+      SimObject *db = Sim::getDataBlockGroup()->findObject(objectName);
+
+      // Make sure we're not changing types on ourselves...
+      if (db && dStricmp(db->getClassName(), mCallArgv[1]))
+      {
+         Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare data block %s with a different class.", mCodeBlock->getFileLine(ip), objectName);
+         ip = mFailJump;
+         STR.popFrame();
+         CSTK.popFrame();
+         return OPCodeReturn::success;
+      }
+
+      // If there was one, set the currentNewObject and move on.
+      if (db)
+         mCurrentNewObject = db;
+   }
+   else if (!isInternal)
+   {
+      // IF we aren't looking at a local/internal object, then check if 
+      // this object already exists in the global space
+
+      AbstractClassRep* rep = AbstractClassRep::findClassRep(objectName);
+      if (rep != NULL) {
+         Con::errorf(ConsoleLogEntry::General, "%s: Cannot name object [%s] the same name as a script class.",
+            mCodeBlock->getFileLine(ip), objectName);
+         ip = mFailJump;
+         STR.popFrame();
+         CSTK.popFrame();
+         return OPCodeReturn::success;
+      }
+
+      SimObject *obj = Sim::findObject((const char*)objectName);
+      if (obj /*&& !obj->isLocalName()*/)
+      {
+         if (isSingleton)
+         {
+            // Make sure we're not trying to change types
+            if (dStricmp(obj->getClassName(), (const char*)mCallArgv[1]) != 0)
+            {
+               Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare object [%s] with a different class [%s] - was [%s].",
+                  mCodeBlock->getFileLine(ip), objectName, (const char*)mCallArgv[1], obj->getClassName());
+               ip = mFailJump;
+               STR.popFrame();
+               CSTK.popFrame();
+               return OPCodeReturn::success;
+            }
+
+            // We're creating a singleton, so use the found object
+            // instead of creating a new object.
+            mCurrentNewObject = obj;
+         }
+         else
+         {
+            const char* redefineBehavior = Con::getVariable("$Con::redefineBehavior");
+
+            if (dStricmp(redefineBehavior, "replaceExisting") == 0)
+            {
+               // Save our constructor args as the argv vector is stored on the
+               // string stack and may get stomped if deleteObject triggers
+               // script execution.
+
+               ConsoleValueRef savedArgv[StringStack::MaxArgs];
+               for (int i = 0; i< mCallArgc; i++) {
+                  savedArgv[i] = mCallArgv[i];
+               }
+               //dMemcpy( savedArgv, callArgv, sizeof( savedArgv[ 0 ] ) * callArgc );
+
+               // Prevent stack value corruption
+               CSTK.pushFrame();
+               STR.pushFrame();
+               // --
+
+               obj->deleteObject();
+               obj = NULL;
+
+               // Prevent stack value corruption
+               CSTK.popFrame();
+               STR.popFrame();
+               // --
+
+               //dMemcpy( callArgv, savedArgv, sizeof( callArgv[ 0 ] ) * callArgc );
+               for (int i = 0; i<mCallArgc; i++) {
+                  mCallArgv[i] = savedArgv[i];
+               }
+            }
+            else if (dStricmp(redefineBehavior, "renameNew") == 0)
+            {
+               for (U32 i = 1;; ++i)
+               {
+                  String newName = String::ToString("%s%i", objectName, i);
+                  if (!Sim::findObject(newName))
+                  {
+                     objectName = StringTable->insert(newName);
+                     break;
+                  }
+               }
+            }
+            else if (dStricmp(redefineBehavior, "unnameNew") == 0)
+            {
+               objectName = StringTable->insert("");
+            }
+            else if (dStricmp(redefineBehavior, "postfixNew") == 0)
+            {
+               const char* postfix = Con::getVariable("$Con::redefineBehaviorPostfix");
+               String newName = String::ToString("%s%s", objectName, postfix);
+
+               if (Sim::findObject(newName))
+               {
+                  Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare object with postfix [%s].",
+                     mCodeBlock->getFileLine(ip), newName.c_str());
+                  ip = mFailJump;
+                  STR.popFrame();
+                  CSTK.popFrame();
+                  return OPCodeReturn::success;
+               }
+               else
+                  objectName = StringTable->insert(newName);
+            }
+            else
+            {
+               Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare object [%s].",
+                  mCodeBlock->getFileLine(ip), objectName);
+               ip = mFailJump;
+               STR.popFrame();
+               CSTK.popFrame();
+               return OPCodeReturn::success;
+            }
+         }
+      }
+   }
+
+   STR.popFrame();
+   CSTK.popFrame();
+
+   if (!mCurrentNewObject)
+   {
+      // Well, looks like we have to create a new object.
+      ConsoleObject *object = ConsoleObject::create((const char*)mCallArgv[1]);
+
+      // Deal with failure!
+      if (!object)
+      {
+         Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-conobject class %s.", mCodeBlock->getFileLine(ip), (const char*)mCallArgv[1]);
+         ip = mFailJump;
+         return OPCodeReturn::success;
+      }
+
+      // Do special datablock init if appropros
+      if (isDataBlock)
+      {
+         SimDataBlock *dataBlock = dynamic_cast<SimDataBlock *>(object);
+         if (dataBlock)
+         {
+            dataBlock->assignId();
+         }
+         else
+         {
+            // They tried to make a non-datablock with a datablock keyword!
+            Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-datablock class %s.", mCodeBlock->getFileLine(ip), (const char*)mCallArgv[1]);
+            // Clean up...
+            delete object;
+            mCurrentNewObject = NULL;
+            ip = mFailJump;
+            return OPCodeReturn::success;
+         }
+      }
+
+      // Finally, set currentNewObject to point to the new one.
+      mCurrentNewObject = dynamic_cast<SimObject *>(object);
+
+      // Deal with the case of a non-SimObject.
+      if (!mCurrentNewObject)
+      {
+         Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-SimObject class %s.", mCodeBlock->getFileLine(ip), (const char*)mCallArgv[1]);
+         delete object;
+         mCurrentNewObject = NULL;
+         ip = mFailJump;
+         return OPCodeReturn::success;
+      }
+
+      // Set the declaration line
+      mCurrentNewObject->setDeclarationLine(lineNumber);
+
+      // Set the file that this object was created in
+      mCurrentNewObject->setFilename(mCodeBlock->name);
+
+      // Does it have a parent object? (ie, the copy constructor : syntax, not inheriance)
+      if (*objParent)
+      {
+         // Find it!
+         SimObject *parent;
+         if (Sim::findObject(objParent, parent))
+         {
+            // Con::printf(" - Parent object found: %s", parent->getClassName());
+
+            mCurrentNewObject->setCopySource(parent);
+            mCurrentNewObject->assignFieldsFrom(parent);
+
+            // copy any substitution statements
+            SimDataBlock* parent_db = dynamic_cast<SimDataBlock*>(parent);
+            if (parent_db)
+            {
+               SimDataBlock* currentNewObject_db = dynamic_cast<SimDataBlock*>(mCurrentNewObject);
+               if (currentNewObject_db)
+                  currentNewObject_db->copySubstitutionsFrom(parent_db);
+            }
+         }
+         else
+         {
+            if (Con::gObjectCopyFailures == -1)
+               Con::errorf(ConsoleLogEntry::General, "%s: Unable to find parent object %s for %s.", mCodeBlock->getFileLine(ip), objParent, (const char*)mCallArgv[1]);
+            else
+               ++Con::gObjectCopyFailures;
+
+            // Fail to create the object.
+            delete object;
+            mCurrentNewObject = NULL;
+            ip = mFailJump;
+            return OPCodeReturn::success;
+         }
+      }
+
+      // If a name was passed, assign it.
+      if (objectName[0])
+      {
+         if (!isInternal)
+            mCurrentNewObject->assignName(objectName);
+         else
+            mCurrentNewObject->setInternalName(objectName);
+
+         // Set the original name
+         mCurrentNewObject->setOriginalName(objectName);
+      }
+
+      // Prevent stack value corruption
+      CSTK.pushFrame();
+      STR.pushFrame();
+      // --
+
+      // Do the constructor parameters.
+      if (!mCurrentNewObject->processArguments(mCallArgc - 3, mCallArgv + 3))
+      {
+         delete mCurrentNewObject;
+         mCurrentNewObject = NULL;
+         ip = mFailJump;
+
+         // Prevent stack value corruption
+         CSTK.popFrame();
+         STR.popFrame();
+         // --
+         return OPCodeReturn::success;
+      }
+
+      // Prevent stack value corruption
+      CSTK.popFrame();
+      STR.popFrame();
+      // --
+
+      // If it's not a datablock, allow people to modify bits of it.
+      if (!isDataBlock)
+      {
+         mCurrentNewObject->setModStaticFields(true);
+         mCurrentNewObject->setModDynamicFields(true);
+      }
+   }
+   else
+   {
+      mCurrentNewObject->reloadReset(); // AFX (reload-reset)
+                                       // Does it have a parent object? (ie, the copy constructor : syntax, not inheriance)
+      if (*objParent)
+      {
+         // Find it!
+         SimObject *parent;
+         if (Sim::findObject(objParent, parent))
+         {
+            // Con::printf(" - Parent object found: %s", parent->getClassName());
+
+            // temporarily block name change
+            SimObject::preventNameChanging = true;
+            mCurrentNewObject->setCopySource(parent);
+            mCurrentNewObject->assignFieldsFrom(parent);
+            // restore name changing
+            SimObject::preventNameChanging = false;
+
+            // copy any substitution statements
+            SimDataBlock* parent_db = dynamic_cast<SimDataBlock*>(parent);
+            if (parent_db)
+            {
+               SimDataBlock* currentNewObject_db = dynamic_cast<SimDataBlock*>(mCurrentNewObject);
+               if (currentNewObject_db)
+                  currentNewObject_db->copySubstitutionsFrom(parent_db);
+            }
+         }
+         else
+            Con::errorf(ConsoleLogEntry::General, "%d: Unable to find parent object %s for %s.", lineNumber, objParent, (const char*)mCallArgv[1]);
+      }
+   }
+
+   // Advance the IP past the create info...
+   ip += 7;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_add_object(U32 &ip)
+{
+   // See OP_SETCURVAR for why we do this.
+   mCurFNDocBlock = NULL;
+   mCurNSDocBlock = NULL;
+
+   // Do we place this object at the root?
+   bool placeAtRoot = mCodeBlock->code[ip++];
+
+   // Con::printf("Adding object %s", currentNewObject->getName());
+
+   // Prevent stack value corruption
+   CSTK.pushFrame();
+   STR.pushFrame();
+   // --
+
+   // Make sure it wasn't already added, then add it.
+   if (mCurrentNewObject->isProperlyAdded() == false)
+   {
+      bool ret = false;
+
+      Message *msg = dynamic_cast<Message *>(mCurrentNewObject);
+      if (msg)
+      {
+         SimObjectId id = Message::getNextMessageID();
+         if (id != 0xffffffff)
+            ret = mCurrentNewObject->registerObject(id);
+         else
+            Con::errorf("%s: No more object IDs available for messages", mCodeBlock->getFileLine(ip));
+      }
+      else
+         ret = mCurrentNewObject->registerObject();
+
+      if (!ret)
+      {
+         // This error is usually caused by failing to call Parent::initPersistFields in the class' initPersistFields().
+         Con::warnf(ConsoleLogEntry::General, "%s: Register object failed for object %s of class %s.", mCodeBlock->getFileLine(ip), mCurrentNewObject->getName(), mCurrentNewObject->getClassName());
+         delete mCurrentNewObject;
+         mCurrentNewObject = NULL;
+         ip = mFailJump;
+         // Prevent stack value corruption
+         CSTK.popFrame();
+         STR.popFrame();
+         // --
+         return OPCodeReturn::success;
+      }
+   }
+
+   // Are we dealing with a datablock?
+   SimDataBlock *dataBlock = dynamic_cast<SimDataBlock *>(mCurrentNewObject);
+   static String errorStr;
+
+   // If so, preload it.
+   if (dataBlock && !dataBlock->preload(true, errorStr))
+   {
+      Con::errorf(ConsoleLogEntry::General, "%s: preload failed for %s: %s.", mCodeBlock->getFileLine(ip),
+         mCurrentNewObject->getName(), errorStr.c_str());
+      dataBlock->deleteObject();
+      mCurrentNewObject = NULL;
+      ip = mFailJump;
+
+      // Prevent stack value corruption
+      CSTK.popFrame();
+      STR.popFrame();
+      // --
+      return OPCodeReturn::success;
+   }
+
+   // What group will we be added to, if any?
+   U32 groupAddId = intStack[_UINT];
+   SimGroup *grp = NULL;
+   SimSet   *set = NULL;
+   bool isMessage = dynamic_cast<Message *>(mCurrentNewObject) != NULL;
+
+   if (!placeAtRoot || !mCurrentNewObject->getGroup())
+   {
+      if (!isMessage)
+      {
+         if (!placeAtRoot)
+         {
+            // Otherwise just add to the requested group or set.
+            if (!Sim::findObject(groupAddId, grp))
+               Sim::findObject(groupAddId, set);
+         }
+
+         if (placeAtRoot)
+         {
+            // Deal with the instantGroup if we're being put at the root or we're adding to a component.
+            if (Con::gInstantGroup.isEmpty()
+               || !Sim::findObject(Con::gInstantGroup, grp))
+               grp = Sim::getRootGroup();
+         }
+      }
+
+      // If we didn't get a group, then make sure we have a pointer to
+      // the rootgroup.
+      if (!grp)
+         grp = Sim::getRootGroup();
+
+      // add to the parent group
+      grp->addObject(mCurrentNewObject);
+
+      // If for some reason the add failed, add the object to the
+      // root group so it won't leak.
+      if (!mCurrentNewObject->getGroup())
+         Sim::getRootGroup()->addObject(mCurrentNewObject);
+
+      // add to any set we might be in
+      if (set)
+         set->addObject(mCurrentNewObject);
+   }
+
+   // store the new object's ID on the stack (overwriting the group/set
+   // id, if one was given, otherwise getting pushed)
+   if (placeAtRoot)
+      intStack[_UINT] = mCurrentNewObject->getId();
+   else
+      intStack[++_UINT] = mCurrentNewObject->getId();
+
+   // Prevent stack value corruption
+   CSTK.popFrame();
+   STR.popFrame();
+   // --
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_end_object(U32 &ip)
+{
+   // If we're not to be placed at the root, make sure we clean up
+   // our group reference.
+   bool placeAtRoot = mCodeBlock->code[ip++];
+   if (!placeAtRoot)
+      _UINT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_finish_object(U32 &ip)
+{
+   if (mCurrentNewObject)
+      mCurrentNewObject->onPostAdd();
+
+   //Assert( objectCreationStackIndex >= 0 );
+   // Restore the object info from the stack [7/9/2007 Black]
+   mCurrentNewObject = mObjectCreationStack[--mObjectCreationStackIndex].newObject;
+   mFailJump = mObjectCreationStack[mObjectCreationStackIndex].failJump;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_jmpiffnot(U32 &ip)
+{
+   if (floatStack[_FLT--])
+   {
+      ip++;
+      return OPCodeReturn::success;
+   }
+   ip = mCodeBlock->code[ip];
+   return OPCodeReturn::success;
+}
+
+
+OPCodeReturn CodeInterpreter::op_jmpifnot(U32 &ip)
+{
+   if (intStack[_UINT--])
+   {
+      ip++;
+      return OPCodeReturn::success;
+   }
+   ip = mCodeBlock->code[ip];
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_jmpiff(U32 &ip)
+{
+   if (!floatStack[_FLT--])
+   {
+      ip++;
+      return OPCodeReturn::success;
+   }
+   ip = mCodeBlock->code[ip];
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_jmpif(U32 &ip)
+{
+   if (!intStack[_UINT--])
+   {
+      ip++;
+      return OPCodeReturn::success;
+   }
+   ip = mCodeBlock->code[ip];
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_jmpifnot_np(U32 &ip)
+{
+   if (intStack[_UINT])
+   {
+      _UINT--;
+      ip++;
+      return OPCodeReturn::success;
+   }
+   ip = mCodeBlock->code[ip];
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_jmpif_np(U32 &ip)
+{
+   if (!intStack[_UINT])
+   {
+      _UINT--;
+      ip++;
+      return OPCodeReturn::success;
+   }
+   ip = mCodeBlock->code[ip];
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_jmp(U32 &ip)
+{
+   ip = mCodeBlock->code[ip];
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_return_void(U32 &ip)
+{
+   STR.setStringValue("");
+   // We're falling thru here on purpose.
+
+   OPCodeReturn ret = op_return(ip);
+
+   return ret;
+}
+
+OPCodeReturn CodeInterpreter::op_return(U32 &ip)
+{
+   StringStackPtr retValue = STR.getStringValuePtr();
+
+   if (mIterDepth > 0)
+   {
+      // Clear iterator state.
+      while (mIterDepth > 0)
+      {
+         iterStack[--_ITER].mIsStringIter = false;
+         --mIterDepth;
+      }
+
+      STR.rewind();
+      STR.setStringValue(StringStackPtrRef(retValue).getPtr(&STR)); // Not nice but works.
+      retValue = STR.getStringValuePtr();
+   }
+
+   // Previously the return value was on the stack and would be returned using STR.getStringValue().
+   // Now though we need to wrap it in a ConsoleValueRef 
+   mReturnValue.value = CSTK.pushStringStackPtr(retValue);
+
+   return OPCodeReturn::exitCode;
+}
+
+OPCodeReturn CodeInterpreter::op_return_flt(U32 &ip)
+{
+   if (mIterDepth > 0)
+   {
+      // Clear iterator state.
+      while (mIterDepth > 0)
+      {
+         iterStack[--_ITER].mIsStringIter = false;
+         --mIterDepth;
+      }
+
+   }
+
+   mReturnValue.value = CSTK.pushFLT(floatStack[_FLT]);
+   _FLT--;
+
+   return OPCodeReturn::exitCode;
+}
+
+OPCodeReturn CodeInterpreter::op_return_uint(U32 &ip)
+{
+   if (mIterDepth > 0)
+   {
+      // Clear iterator state.
+      while (mIterDepth > 0)
+      {
+         iterStack[--_ITER].mIsStringIter = false;
+         --mIterDepth;
+      }
+   }
+
+   mReturnValue.value = CSTK.pushUINT(intStack[_UINT]);
+   _UINT--;
+
+   return OPCodeReturn::exitCode;
+}
+
+OPCodeReturn CodeInterpreter::op_cmpeq(U32 &ip)
+{
+   intStack[_UINT + 1] = bool(floatStack[_FLT] == floatStack[_FLT - 1]);
+   _UINT++;
+   _FLT -= 2;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_cmpgr(U32 &ip)
+{
+   intStack[_UINT + 1] = bool(floatStack[_FLT] > floatStack[_FLT - 1]);
+   _UINT++;
+   _FLT -= 2;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_cmpge(U32 &ip)
+{
+   intStack[_UINT + 1] = bool(floatStack[_FLT] >= floatStack[_FLT - 1]);
+   _UINT++;
+   _FLT -= 2;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_cmplt(U32 &ip)
+{
+   intStack[_UINT + 1] = bool(floatStack[_FLT] < floatStack[_FLT - 1]);
+   _UINT++;
+   _FLT -= 2;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_cmple(U32 &ip)
+{
+   intStack[_UINT + 1] = bool(floatStack[_FLT] <= floatStack[_FLT - 1]);
+   _UINT++;
+   _FLT -= 2;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_cmpne(U32 &ip)
+{
+   intStack[_UINT + 1] = bool(floatStack[_FLT] != floatStack[_FLT - 1]);
+   _UINT++;
+   _FLT -= 2;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_xor(U32 &ip)
+{
+   intStack[_UINT - 1] = intStack[_UINT] ^ intStack[_UINT - 1];
+   _UINT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_mod(U32 &ip)
+{
+   if (intStack[_UINT - 1] != 0)
+      intStack[_UINT - 1] = intStack[_UINT] % intStack[_UINT - 1];
+   else
+      intStack[_UINT - 1] = 0;
+   _UINT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_bitand(U32 &ip)
+{
+   intStack[_UINT - 1] = intStack[_UINT] & intStack[_UINT - 1];
+   _UINT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_bitor(U32 &ip)
+{
+   intStack[_UINT - 1] = intStack[_UINT] | intStack[_UINT - 1];
+   _UINT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_not(U32 &ip)
+{
+   intStack[_UINT] = !intStack[_UINT];
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_notf(U32 &ip)
+{
+   intStack[_UINT + 1] = !floatStack[_FLT];
+   _FLT--;
+   _UINT++;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_onescomplement(U32 &ip)
+{
+   intStack[_UINT] = ~intStack[_UINT];
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_shr(U32 &ip)
+{
+   intStack[_UINT - 1] = intStack[_UINT] >> intStack[_UINT - 1];
+   _UINT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_shl(U32 &ip)
+{
+   intStack[_UINT - 1] = intStack[_UINT] << intStack[_UINT - 1];
+   _UINT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_and(U32 &ip)
+{
+   intStack[_UINT - 1] = intStack[_UINT] && intStack[_UINT - 1];
+   _UINT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_or(U32 &ip)
+{
+   intStack[_UINT - 1] = intStack[_UINT] || intStack[_UINT - 1];
+   _UINT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_add(U32 &ip)
+{
+   floatStack[_FLT - 1] = floatStack[_FLT] + floatStack[_FLT - 1];
+   _FLT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_sub(U32 &ip)
+{
+   floatStack[_FLT - 1] = floatStack[_FLT] - floatStack[_FLT - 1];
+   _FLT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_mul(U32 &ip)
+{
+   floatStack[_FLT - 1] = floatStack[_FLT] * floatStack[_FLT - 1];
+   _FLT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_div(U32 &ip)
+{
+   floatStack[_FLT - 1] = floatStack[_FLT] / floatStack[_FLT - 1];
+   _FLT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_neg(U32 &ip)
+{
+   floatStack[_FLT] = -floatStack[_FLT];
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_inc(U32 &ip)
+{
+   StringTableEntry var = CodeToSTE(mCodeBlock->code, ip);
+   ip += 2;
+
+   // If a variable is set, then these must be NULL. It is necessary
+   // to set this here so that the vector parser can appropriately
+   // identify whether it's dealing with a vector.
+   mPrevField = NULL;
+   mPrevObject = NULL;
+   mCurObject = NULL;
+
+   gEvalState.setCurVarNameCreate(var);
+
+   // In order to let docblocks work properly with variables, we have
+   // clear the current docblock when we do an assign. This way it 
+   // won't inappropriately carry forward to following function decls.
+   mCurFNDocBlock = NULL;
+   mCurNSDocBlock = NULL;
+
+   F64 val = gEvalState.getFloatVariable() + 1.0;
+   gEvalState.setFloatVariable(val);
+
+   // We gotta push val onto the stack. What if we have
+   // more expressions that have to use this.
+   // If we don't, we send out an op code to pop it.
+   floatStack[_FLT + 1] = val;
+   _FLT++;
+
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_dec(U32 &ip)
+{
+   StringTableEntry var = CodeToSTE(mCodeBlock->code, ip);
+   ip += 2;
+
+   // If a variable is set, then these must be NULL. It is necessary
+   // to set this here so that the vector parser can appropriately
+   // identify whether it's dealing with a vector.
+   mPrevField = NULL;
+   mPrevObject = NULL;
+   mCurObject = NULL;
+
+   gEvalState.setCurVarNameCreate(var);
+
+   // In order to let docblocks work properly with variables, we have
+   // clear the current docblock when we do an assign. This way it 
+   // won't inappropriately carry forward to following function decls.
+   mCurFNDocBlock = NULL;
+   mCurNSDocBlock = NULL;
+
+   F64 val = gEvalState.getFloatVariable() - 1.0;
+   gEvalState.setFloatVariable(val);
+
+   // We gotta push val onto the stack. What if we have
+   // more expressions that have to use this.
+   // If we don't, we send out an op code to pop it.
+   floatStack[_FLT + 1] = val;
+   _FLT++;
+
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurvar(U32 &ip)
+{
+   StringTableEntry var = CodeToSTE(mCodeBlock->code, ip);
+   ip += 2;
+
+   // If a variable is set, then these must be NULL. It is necessary
+   // to set this here so that the vector parser can appropriately
+   // identify whether it's dealing with a vector.
+   mPrevField = NULL;
+   mPrevObject = NULL;
+   mCurObject = NULL;
+
+   gEvalState.setCurVarName(var);
+
+   // In order to let docblocks work properly with variables, we have
+   // clear the current docblock when we do an assign. This way it 
+   // won't inappropriately carry forward to following function decls.
+   mCurFNDocBlock = NULL;
+   mCurNSDocBlock = NULL;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurvar_create(U32 &ip)
+{
+   StringTableEntry var = CodeToSTE(mCodeBlock->code, ip);
+   ip += 2;
+
+   // See OP_SETCURVAR
+   mPrevField = NULL;
+   mPrevObject = NULL;
+   mCurObject = NULL;
+
+   gEvalState.setCurVarNameCreate(var);
+
+   // See OP_SETCURVAR for why we do this.
+   mCurFNDocBlock = NULL;
+   mCurNSDocBlock = NULL;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurvar_array(U32 &ip)
+{
+   StringTableEntry var = STR.getSTValue();
+
+   // See OP_SETCURVAR
+   mPrevField = NULL;
+   mPrevObject = NULL;
+   mCurObject = NULL;
+
+   gEvalState.setCurVarName(var);
+
+   // See OP_SETCURVAR for why we do this.
+   mCurFNDocBlock = NULL;
+   mCurNSDocBlock = NULL;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurvar_array_varlookup(U32 &ip)
+{
+   StringTableEntry arrayName = CodeToSTE(mCodeBlock->code, ip);
+   StringTableEntry arrayLookup = CodeToSTE(mCodeBlock->code, ip + 2);
+   ip += 4;
+
+   STR.setStringValue(arrayName);
+   STR.advance();
+
+   // See OP_SETCURVAR
+   mPrevField = NULL;
+   mPrevObject = NULL;
+   mCurObject = NULL;
+
+   // resolve arrayLookup to get the 'value'
+   // Note: we have to setCurVarNameCreate in case the var doesn't exist.
+   // this won't cause much of a performance hit since vars are hashed.
+   gEvalState.setCurVarNameCreate(arrayLookup);
+   StringTableEntry hash = gEvalState.getStringVariable();
+
+   STR.setStringValue(hash);
+   STR.rewind();
+
+   // Generate new array name.
+   StringTableEntry var = STR.getSTValue();
+   gEvalState.setCurVarName(var);
+
+   // See OP_SETCURVAR for why we do this.
+   mCurFNDocBlock = NULL;
+   mCurNSDocBlock = NULL;
+
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurvar_array_create(U32 &ip)
+{
+   StringTableEntry var = STR.getSTValue();
+
+   // See OP_SETCURVAR
+   mPrevField = NULL;
+   mPrevObject = NULL;
+   mCurObject = NULL;
+
+   gEvalState.setCurVarNameCreate(var);
+
+   // See OP_SETCURVAR for why we do this.
+   mCurFNDocBlock = NULL;
+   mCurNSDocBlock = NULL;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurvar_array_create_varlookup(U32 &ip)
+{
+   StringTableEntry arrayName = CodeToSTE(mCodeBlock->code, ip);
+   StringTableEntry arrayLookup = CodeToSTE(mCodeBlock->code, ip + 2);
+   ip += 4;
+
+   // See OP_SETCURVAR
+   mPrevField = NULL;
+   mPrevObject = NULL;
+   mCurObject = NULL;
+
+   STR.setStringValue(arrayName);
+   STR.advance();
+
+   // resolve arrayLookup to get the 'value'
+   // Note: we have to setCurVarNameCreate in case the var doesn't exist.
+   // this won't cause much of a performance hit since vars are hashed.
+   gEvalState.setCurVarNameCreate(arrayLookup);
+   StringTableEntry hash = gEvalState.getStringVariable();
+
+   STR.setStringValue(hash);
+   STR.rewind();
+
+   // Generate new array name.
+   StringTableEntry var = STR.getSTValue();
+   gEvalState.setCurVarNameCreate(var);
+
+   // See OP_SETCURVAR for why we do this.
+   mCurFNDocBlock = NULL;
+   mCurNSDocBlock = NULL;
+
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_loadvar_uint(U32 &ip)
+{
+   intStack[_UINT + 1] = gEvalState.getIntVariable();
+   _UINT++;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_loadvar_flt(U32 &ip)
+{
+   floatStack[_FLT + 1] = gEvalState.getFloatVariable();
+   _FLT++;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_loadvar_str(U32 &ip)
+{
+   StringTableEntry val = gEvalState.getStringVariable();
+   STR.setStringValue(val);
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_loadvar_var(U32 &ip)
+{
+   // Sets current source of OP_SAVEVAR_VAR
+   gEvalState.copyVariable = gEvalState.currentVariable;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_savevar_uint(U32 &ip)
+{
+   gEvalState.setIntVariable(intStack[_UINT]);
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_savevar_flt(U32 &ip)
+{
+   gEvalState.setFloatVariable(floatStack[_FLT]);
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_savevar_str(U32 &ip)
+{
+   gEvalState.setStringVariable(STR.getStringValue());
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_savevar_var(U32 &ip)
+{
+   // this basically handles %var1 = %var2
+   gEvalState.setCopyVariable();
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurobject(U32 &ip)
+{
+   // Save the previous object for parsing vector fields.
+   mPrevObject = mCurObject;
+   StringTableEntry val = STR.getStringValue();
+
+   // Sim::findObject will sometimes find valid objects from
+   // multi-component strings. This makes sure that doesn't
+   // happen.
+   for (const char* check = val; *check; check++)
+   {
+      if (*check == ' ')
+      {
+         val = "";
+         break;
+      }
+   }
+   mCurObject = Sim::findObject(val);
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurobject_internal(U32 &ip)
+{
+   ++ip; // To skip the recurse flag if the object wasn't found
+   if (mCurObject)
+   {
+      SimSet *set = dynamic_cast<SimSet *>(mCurObject);
+      if (set)
+      {
+         StringTableEntry intName = StringTable->insert(STR.getStringValue());
+         bool recurse = mCodeBlock->code[ip - 1];
+         SimObject *obj = set->findObjectByInternalName(intName, recurse);
+         intStack[_UINT + 1] = obj ? obj->getId() : 0;
+         _UINT++;
+      }
+      else
+      {
+         Con::errorf(ConsoleLogEntry::Script, "%s: Attempt to use -> on non-set %s of class %s.", mCodeBlock->getFileLine(ip - 2), mCurObject->getName(), mCurObject->getClassName());
+         intStack[_UINT] = 0;
+      }
+   }
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurobject_new(U32 &ip)
+{
+   mCurObject = mCurrentNewObject;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurfield(U32 &ip)
+{
+   // Save the previous field for parsing vector fields.
+   mPrevField = mCurField;
+   dStrcpy(prevFieldArray, curFieldArray);
+   mCurField = CodeToSTE(mCodeBlock->code, ip);
+   curFieldArray[0] = 0;
+   ip += 2;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurfield_array(U32 &ip)
+{
+   dStrcpy(curFieldArray, STR.getStringValue());
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurfield_type(U32 &ip)
+{
+   if (mCurObject)
+      mCurObject->setDataFieldType(mCodeBlock->code[ip], mCurField, curFieldArray);
+   ip++;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurfield_array_var(U32 &ip)
+{
+   StringTableEntry var = CodeToSTE(mCodeBlock->code, ip);
+   ip += 2;
+
+   // We set the current var name (create it as well in case if it doesn't exist,
+   // otherwise we will crash).
+   gEvalState.setCurVarNameCreate(var);
+
+   // Then load the var and copy the contents to the current field array
+   dStrncpy(curFieldArray, gEvalState.currentVariable->getStringValue(), sizeof(curFieldArray));
+
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_setcurfield_this(U32 &ip)
+{
+   // set the 'this pointer' as the current object.
+   mCurObject = mThisObject;
+
+   mPrevField = mCurField;
+   dStrcpy(prevFieldArray, curFieldArray);
+   mCurField = CodeToSTE(mCodeBlock->code, ip);
+   curFieldArray[0] = 0;
+   ip += 2;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_loadfield_uint(U32 &ip)
+{
+   if (mCurObject)
+      intStack[_UINT + 1] = U32(dAtoi(mCurObject->getDataField(mCurField, curFieldArray)));
+   else
+   {
+      // The field is not being retrieved from an object. Maybe it's
+      // a special accessor?
+      char buff[FieldBufferSizeNumeric];
+      memset(buff, 0, sizeof(buff));
+      getFieldComponent(mPrevObject, mPrevField, prevFieldArray, mCurField, buff);
+      intStack[_UINT + 1] = dAtoi(buff);
+   }
+   _UINT++;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_loadfield_flt(U32 &ip)
+{
+   if (mCurObject)
+      floatStack[_FLT + 1] = dAtof(mCurObject->getDataField(mCurField, curFieldArray));
+   else
+   {
+      // The field is not being retrieved from an object. Maybe it's
+      // a special accessor?
+      char buff[FieldBufferSizeNumeric];
+      memset(buff, 0, sizeof(buff));
+      getFieldComponent(mPrevObject, mPrevField, prevFieldArray, mCurField, buff);
+      floatStack[_FLT + 1] = dAtof(buff);
+   }
+   _FLT++;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_loadfield_str(U32 &ip)
+{
+   if (mCurObject)
+   {
+      StringTableEntry val = mCurObject->getDataField(mCurField, curFieldArray);
+      STR.setStringValue(val);
+   }
+   else
+   {
+      // The field is not being retrieved from an object. Maybe it's
+      // a special accessor?
+      char buff[FieldBufferSizeString];
+      memset(buff, 0, sizeof(buff));
+      getFieldComponent(mPrevObject, mPrevField, prevFieldArray, mCurField, buff);
+      STR.setStringValue(buff);
+   }
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_savefield_uint(U32 &ip)
+{
+   STR.setIntValue(intStack[_UINT]);
+   if (mCurObject)
+      mCurObject->setDataField(mCurField, curFieldArray, STR.getStringValue());
+   else
+   {
+      // The field is not being set on an object. Maybe it's
+      // a special accessor?
+      setFieldComponent(mPrevObject, mPrevField, prevFieldArray, mCurField);
+      mPrevObject = NULL;
+   }
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_savefield_flt(U32 &ip)
+{
+   STR.setFloatValue(floatStack[_FLT]);
+   if (mCurObject)
+      mCurObject->setDataField(mCurField, curFieldArray, STR.getStringValue());
+   else
+   {
+      // The field is not being set on an object. Maybe it's
+      // a special accessor?
+      setFieldComponent(mPrevObject, mPrevField, prevFieldArray, mCurField);
+      mPrevObject = NULL;
+   }
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_savefield_str(U32 &ip)
+{
+   if (mCurObject)
+      mCurObject->setDataField(mCurField, curFieldArray, STR.getStringValue());
+   else
+   {
+      // The field is not being set on an object. Maybe it's
+      // a special accessor?
+      setFieldComponent(mPrevObject, mPrevField, prevFieldArray, mCurField);
+      mPrevObject = NULL;
+   }
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_str_to_uint(U32 &ip)
+{
+   intStack[_UINT + 1] = STR.getIntValue();
+   _UINT++;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_str_to_flt(U32 &ip)
+{
+   floatStack[_FLT + 1] = STR.getFloatValue();
+   _FLT++;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_str_to_none(U32 &ip)
+{
+   // This exists simply to deal with certain typecast situations.
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_flt_to_uint(U32 &ip)
+{
+   intStack[_UINT + 1] = (S64)floatStack[_FLT];
+   _FLT--;
+   _UINT++;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_flt_to_str(U32 &ip)
+{
+   STR.setFloatValue(floatStack[_FLT]);
+   _FLT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_flt_to_none(U32 &ip)
+{
+   _FLT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_uint_to_flt(U32 &ip)
+{
+   floatStack[_FLT + 1] = (F32)intStack[_UINT];
+   _UINT--;
+   _FLT++;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_uint_to_str(U32 &ip)
+{
+   STR.setIntValue(intStack[_UINT]);
+   _UINT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_uint_to_none(U32 &ip)
+{
+   _UINT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_copyvar_to_none(U32 &ip)
+{
+   gEvalState.copyVariable = NULL;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_loadimmed_uint(U32 &ip)
+{
+   intStack[_UINT + 1] = mCodeBlock->code[ip++];
+   _UINT++;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_loadimmed_flt(U32 &ip)
+{
+   floatStack[_FLT + 1] = mCurFloatTable[mCodeBlock->code[ip]];
+   ip++;
+   _FLT++;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_tag_to_str(U32 &ip)
+{
+   mCodeBlock->code[ip - 1] = OP_LOADIMMED_STR;
+   // it's possible the string has already been converted
+   if (U8(mCurStringTable[mCodeBlock->code[ip]]) != StringTagPrefixByte)
+   {
+      U32 id = GameAddTaggedString(mCurStringTable + mCodeBlock->code[ip]);
+      dSprintf(mCurStringTable + mCodeBlock->code[ip] + 1, 7, "%d", id);
+      *(mCurStringTable + mCodeBlock->code[ip]) = StringTagPrefixByte;
+   }
+
+   // Fallthrough
+   OPCodeReturn ret = op_loadimmed_str(ip);
+
+   return ret;
+}
+
+OPCodeReturn CodeInterpreter::op_loadimmed_str(U32 &ip)
+{
+   STR.setStringValue(mCurStringTable + mCodeBlock->code[ip++]);
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_docblock_str(U32 &ip)
+{
+   // If the first word of the doc is '\class' or '@class', then this
+   // is a namespace doc block, otherwise it is a function doc block.
+   const char* docblock = mCurStringTable + mCodeBlock->code[ip++];
+
+   const char* sansClass = dStrstr(docblock, "@class");
+   if (!sansClass)
+      sansClass = dStrstr(docblock, "\\class");
+
+   if (sansClass)
+   {
+      // Don't save the class declaration. Scan past the 'class'
+      // keyword and up to the first whitespace.
+      sansClass += 7;
+      S32 index = 0;
+      while ((*sansClass != ' ') && (*sansClass != '\n') && *sansClass && (index < (nsDocLength - 1)))
+      {
+         mNSDocBlockClass[index++] = *sansClass;
+         sansClass++;
+      }
+      mNSDocBlockClass[index] = '\0';
+
+      mCurNSDocBlock = sansClass + 1;
+   }
+   else
+      mCurFNDocBlock = docblock;
+
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_loadimmed_ident(U32 &ip)
+{
+   STR.setStringValue(CodeToSTE(mCodeBlock->code, ip));
+   ip += 2;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_callfunc_resolve(U32 &ip)
+{
+   // This deals with a function that is potentially living in a namespace.
+   StringTableEntry fnNamespace = CodeToSTE(mCodeBlock->code, ip + 2);
+   StringTableEntry fnName = CodeToSTE(mCodeBlock->code, ip);
+
+   // Try to look it up.
+   mNSEntry = Namespace::find(fnNamespace)->lookup(fnName);
+   if (!mNSEntry)
+   {
+      ip += 5;
+      Con::warnf(ConsoleLogEntry::General,
+         "%s: Unable to find function %s%s%s",
+         mCodeBlock->getFileLine(ip - 7), fnNamespace ? fnNamespace : "",
+         fnNamespace ? "::" : "", fnName);
+      STR.popFrame();
+      CSTK.popFrame();
+      return OPCodeReturn::success;
+   }
+
+   // Fallthrough to op_callfunc_resolve
+   OPCodeReturn ret = op_callfunc(ip);
+
+   return ret;
+}
+
+OPCodeReturn CodeInterpreter::op_callfunc(U32 &ip)
+{
+   // This routingId is set when we query the object as to whether
+   // it handles this method.  It is set to an enum from the table
+   // above indicating whether it handles it on a component it owns
+   // or just on the object.
+   S32 routingId = 0;
+
+   U32 *code = mCodeBlock->code;
+
+   StringTableEntry fnName = CodeToSTE(code, ip);
+
+   //if this is called from inside a function, append the ip and codeptr
+   if (gEvalState.getStackDepth() > 0)
+   {
+      gEvalState.getCurrentFrame().code = mCodeBlock;
+      gEvalState.getCurrentFrame().ip = ip - 1;
+   }
+
+   U32 callType = code[ip + 4];
+
+   ip += 5;
+   CSTK.getArgcArgv(fnName, &mCallArgc, &mCallArgv);
+
+   const char *componentReturnValue = "";
+   Namespace *ns = NULL;
+
+   if (callType == FuncCallExprNode::FunctionCall)
+   {
+      if (!mNSEntry)
+         mNSEntry = Namespace::global()->lookup(fnName);
+   }
+   else if (callType == FuncCallExprNode::MethodCall)
+   {
+      mSaveObject = gEvalState.thisObject;
+      gEvalState.thisObject = Sim::findObject((const char*)mCallArgv[1]);
+      if (!gEvalState.thisObject)
+      {
+         // Go back to the previous saved object.
+         gEvalState.thisObject = mSaveObject;
+
+         Con::warnf(ConsoleLogEntry::General, "%s: Unable to find object: '%s' attempting to call function '%s'", mCodeBlock->getFileLine(ip - 4), (const char*)mCallArgv[1], fnName);
+         STR.popFrame();
+         CSTK.popFrame();
+         STR.setStringValue("");
+         return OPCodeReturn::success;
+      }
+
+      bool handlesMethod = gEvalState.thisObject->handlesConsoleMethod(fnName, &routingId);
+      if (handlesMethod && routingId == MethodOnComponent)
+      {
+         ICallMethod *pComponent = dynamic_cast<ICallMethod *>(gEvalState.thisObject);
+         if (pComponent)
+            componentReturnValue = pComponent->callMethodArgList(mCallArgc, mCallArgv, false);
+      }
+
+      ns = gEvalState.thisObject->getNamespace();
+      if (ns)
+         mNSEntry = ns->lookup(fnName);
+      else
+         mNSEntry = NULL;
+   }
+   else // it's a ParentCall
+   {
+      if (mExec.thisNamespace)
+      {
+         ns = mExec.thisNamespace->mParent;
+         if (ns)
+            mNSEntry = ns->lookup(fnName);
+         else
+            mNSEntry = NULL;
+      }
+      else
+      {
+         ns = NULL;
+         mNSEntry = NULL;
+      }
+   }
+
+   Namespace::Entry::CallbackUnion * nsCb = NULL;
+   const char * nsUsage = NULL;
+   if (mNSEntry)
+   {
+      nsCb = &mNSEntry->cb;
+      nsUsage = mNSEntry->mUsage;
+      routingId = 0;
+   }
+   if (!mNSEntry || mExec.noCalls)
+   {
+      if (!mExec.noCalls && !(routingId == MethodOnComponent))
+      {
+         Con::warnf(ConsoleLogEntry::General, "%s: Unknown command %s.", mCodeBlock->getFileLine(ip - 6), fnName);
+         if (callType == FuncCallExprNode::MethodCall)
+         {
+            Con::warnf(ConsoleLogEntry::General, "  Object %s(%d) %s",
+               gEvalState.thisObject->getName() ? gEvalState.thisObject->getName() : "",
+               gEvalState.thisObject->getId(), Con::getNamespaceList(ns));
+         }
+      }
+      STR.popFrame();
+      CSTK.popFrame();
+
+      if (routingId == MethodOnComponent)
+         STR.setStringValue(componentReturnValue);
+      else
+         STR.setStringValue("");
+      return OPCodeReturn::success;
+   }
+
+   // ConsoleFunctionType is for any function defined by script.
+   // Any 'callback' type is an engine function that is exposed to script.
+   if (mNSEntry->mType == Namespace::Entry::ConsoleFunctionType)
+   {
+      ConsoleValueRef ret;
+      if (mNSEntry->mFunctionOffset)
+         ret = mNSEntry->mCode->exec(mNSEntry->mFunctionOffset, fnName, mNSEntry->mNamespace, mCallArgc, mCallArgv, false, mNSEntry->mPackage);
+
+      STR.popFrame();
+      // Functions are assumed to return strings, so look ahead to see if we can skip the conversion
+      if (code[ip] == OP_STR_TO_UINT)
+      {
+         ip++;
+         intStack[++_UINT] = (U32)((S32)ret);
+      }
+      else if (code[ip] == OP_STR_TO_FLT)
+      {
+         ip++;
+         floatStack[++_FLT] = (F32)ret;
+      }
+      else if (code[ip] == OP_STR_TO_NONE)
+      {
+         STR.setStringValue(ret.getStringValue());
+         ip++;
+      }
+      else
+         STR.setStringValue((const char*)ret);
+
+      // This will clear everything including returnValue
+      CSTK.popFrame();
+      //STR.clearFunctionOffset();
+   }
+   else
+   {
+      const char* nsName = ns ? ns->mName : "";
+#ifndef TORQUE_DEBUG
+      // [tom, 12/13/2006] This stops tools functions from working in the console,
+      // which is useful behavior when debugging so I'm ifdefing this out for debug builds.
+      if (mNSEntry->mToolOnly && !Con::isCurrentScriptToolScript())
+      {
+         Con::errorf(ConsoleLogEntry::Script, "%s: %s::%s - attempting to call tools only function from outside of tools.", mCodeBlock->getFileLine(ip - 6), nsName, fnName);
+      }
+      else
+#endif
+      if ((mNSEntry->mMinArgs && S32(mCallArgc) < mNSEntry->mMinArgs) || (mNSEntry->mMaxArgs && S32(mCallArgc) > mNSEntry->mMaxArgs))
+      {
+         Con::warnf(ConsoleLogEntry::Script, "%s: %s::%s - wrong number of arguments (got %i, expected min %i and max %i).",
+            mCodeBlock->getFileLine(ip - 6), nsName, fnName,
+            mCallArgc, mNSEntry->mMinArgs, mNSEntry->mMaxArgs);
+         Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", mCodeBlock->getFileLine(ip - 6), mNSEntry->mUsage);
+         STR.popFrame();
+         CSTK.popFrame();
+      }
+      else
+      {
+         switch (mNSEntry->mType)
+         {
+         case Namespace::Entry::StringCallbackType:
+         {
+            const char *ret = mNSEntry->cb.mStringCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv);
+            STR.popFrame();
+            CSTK.popFrame();
+            if (ret != STR.getStringValue())
+               STR.setStringValue(ret);
+            //else
+            //   sSTR.setLen(dStrlen(ret));
+            break;
+         }
+         case Namespace::Entry::IntCallbackType:
+         {
+            S32 result = mNSEntry->cb.mIntCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv);
+            STR.popFrame();
+            CSTK.popFrame();
+            if (code[ip] == OP_STR_TO_UINT)
+            {
+               ip++;
+               intStack[++_UINT] = result;
+               break;
+            }
+            else if (code[ip] == OP_STR_TO_FLT)
+            {
+               ip++;
+               floatStack[++_FLT] = result;
+               break;
+            }
+            else if (code[ip] == OP_STR_TO_NONE)
+               ip++;
+            else
+               STR.setIntValue(result);
+            break;
+         }
+         case Namespace::Entry::FloatCallbackType:
+         {
+            F64 result = mNSEntry->cb.mFloatCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv);
+            STR.popFrame();
+            CSTK.popFrame();
+            if (code[ip] == OP_STR_TO_UINT)
+            {
+               ip++;
+               intStack[++_UINT] = (S64)result;
+               break;
+            }
+            else if (code[ip] == OP_STR_TO_FLT)
+            {
+               ip++;
+               floatStack[++_FLT] = result;
+               break;
+            }
+            else if (code[ip] == OP_STR_TO_NONE)
+               ip++;
+            else
+               STR.setFloatValue(result);
+            break;
+         }
+         case Namespace::Entry::VoidCallbackType:
+            mNSEntry->cb.mVoidCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv);
+            if (code[ip] != OP_STR_TO_NONE && Con::getBoolVariable("$Con::warnVoidAssignment", true))
+               Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", mCodeBlock->getFileLine(ip - 6), fnName, mExec.functionName);
+
+            STR.popFrame();
+            CSTK.popFrame();
+            STR.setStringValue("");
+            break;
+         case Namespace::Entry::BoolCallbackType:
+         {
+            bool result = mNSEntry->cb.mBoolCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv);
+            STR.popFrame();
+            CSTK.popFrame();
+            if (code[ip] == OP_STR_TO_UINT)
+            {
+               ip++;
+               intStack[++_UINT] = result;
+               break;
+            }
+            else if (code[ip] == OP_STR_TO_FLT)
+            {
+               ip++;
+               floatStack[++_FLT] = result;
+               break;
+            }
+            else if (code[ip] == OP_STR_TO_NONE)
+               ip++;
+            else
+               STR.setIntValue(result);
+            break;
+         }
+         }
+      }
+   }
+
+   if (callType == FuncCallExprNode::MethodCall)
+      gEvalState.thisObject = mSaveObject;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_callfunc_pointer(U32 &ip)
+{
+   // get function name. This is the 'function pointer'.
+   StringTableEntry fnName = StringTable->insert(STR.getStringValue());
+
+   U32 *code = mCodeBlock->code;
+
+   mNSEntry = Namespace::global()->lookup(fnName);
+
+   //if this is called from inside a function, append the ip and codeptr
+   if (gEvalState.getStackDepth() > 0)
+   {
+      gEvalState.getCurrentFrame().code = mCodeBlock;
+      gEvalState.getCurrentFrame().ip = ip - 1;
+   }
+
+   CSTK.getArgcArgv(fnName, &mCallArgc, &mCallArgv);
+
+
+   if (!mNSEntry || mExec.noCalls)
+   {
+      if (!mExec.noCalls)
+      {
+         Con::warnf(ConsoleLogEntry::General, "%s: Unknown command %s.", mCodeBlock->getFileLine(ip - 6), fnName);
+      }
+      STR.popFrame();
+      CSTK.popFrame();
+
+      STR.setStringValue("");
+      return OPCodeReturn::success;
+   }
+
+   // ConsoleFunctionType is for any function defined by script.
+   // Any 'callback' type is an engine function that is exposed to script.
+   if (mNSEntry->mType == Namespace::Entry::ConsoleFunctionType)
+   {
+      ConsoleValueRef ret;
+      if (mNSEntry->mFunctionOffset)
+         ret = mNSEntry->mCode->exec(mNSEntry->mFunctionOffset, fnName, mNSEntry->mNamespace, mCallArgc, mCallArgv, false, mNSEntry->mPackage);
+
+      STR.popFrame();
+      // Functions are assumed to return strings, so look ahead to see if we can skip the conversion
+      if (code[ip] == OP_STR_TO_UINT)
+      {
+         ip++;
+         intStack[++_UINT] = (U32)((S32)ret);
+      }
+      else if (code[ip] == OP_STR_TO_FLT)
+      {
+         ip++;
+         floatStack[++_FLT] = (F32)ret;
+      }
+      else if (code[ip] == OP_STR_TO_NONE)
+      {
+         STR.setStringValue(ret.getStringValue());
+         ip++;
+      }
+      else
+         STR.setStringValue((const char*)ret);
+
+      // This will clear everything including returnValue
+      CSTK.popFrame();
+      //STR.clearFunctionOffset();
+   }
+   else
+   {
+      const char* nsName = "";
+
+      Namespace::Entry::CallbackUnion * nsCb = &mNSEntry->cb;
+      const char * nsUsage = mNSEntry->mUsage;
+
+#ifndef TORQUE_DEBUG
+      // [tom, 12/13/2006] This stops tools functions from working in the console,
+      // which is useful behavior when debugging so I'm ifdefing this out for debug builds.
+      if (mNSEntry->mToolOnly && !Con::isCurrentScriptToolScript())
+      {
+         Con::errorf(ConsoleLogEntry::Script, "%s: %s::%s - attempting to call tools only function from outside of tools.", mCodeBlock->getFileLine(ip - 6), nsName, fnName);
+      }
+      else
+#endif
+         if ((mNSEntry->mMinArgs && S32(mCallArgc) < mNSEntry->mMinArgs) || (mNSEntry->mMaxArgs && S32(mCallArgc) > mNSEntry->mMaxArgs))
+         {
+            Con::warnf(ConsoleLogEntry::Script, "%s: %s::%s - wrong number of arguments (got %i, expected min %i and max %i).",
+               mCodeBlock->getFileLine(ip - 6), nsName, fnName,
+               mCallArgc, mNSEntry->mMinArgs, mNSEntry->mMaxArgs);
+            Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", mCodeBlock->getFileLine(ip - 6), mNSEntry->mUsage);
+            STR.popFrame();
+            CSTK.popFrame();
+         }
+         else
+         {
+            switch (mNSEntry->mType)
+            {
+            case Namespace::Entry::StringCallbackType:
+            {
+               const char *ret = mNSEntry->cb.mStringCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv);
+               STR.popFrame();
+               CSTK.popFrame();
+               if (ret != STR.getStringValue())
+                  STR.setStringValue(ret);
+               //else
+               //   sSTR.setLen(dStrlen(ret));
+               break;
+            }
+            case Namespace::Entry::IntCallbackType:
+            {
+               S32 result = mNSEntry->cb.mIntCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv);
+               STR.popFrame();
+               CSTK.popFrame();
+               if (code[ip] == OP_STR_TO_UINT)
+               {
+                  ip++;
+                  intStack[++_UINT] = result;
+                  break;
+               }
+               else if (code[ip] == OP_STR_TO_FLT)
+               {
+                  ip++;
+                  floatStack[++_FLT] = result;
+                  break;
+               }
+               else if (code[ip] == OP_STR_TO_NONE)
+                  ip++;
+               else
+                  STR.setIntValue(result);
+               break;
+            }
+            case Namespace::Entry::FloatCallbackType:
+            {
+               F64 result = mNSEntry->cb.mFloatCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv);
+               STR.popFrame();
+               CSTK.popFrame();
+               if (code[ip] == OP_STR_TO_UINT)
+               {
+                  ip++;
+                  intStack[++_UINT] = (S64)result;
+                  break;
+               }
+               else if (code[ip] == OP_STR_TO_FLT)
+               {
+                  ip++;
+                  floatStack[++_FLT] = result;
+                  break;
+               }
+               else if (code[ip] == OP_STR_TO_NONE)
+                  ip++;
+               else
+                  STR.setFloatValue(result);
+               break;
+            }
+            case Namespace::Entry::VoidCallbackType:
+               mNSEntry->cb.mVoidCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv);
+               if (code[ip] != OP_STR_TO_NONE && Con::getBoolVariable("$Con::warnVoidAssignment", true))
+                  Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", mCodeBlock->getFileLine(ip - 6), fnName, mExec.functionName);
+
+               STR.popFrame();
+               CSTK.popFrame();
+               STR.setStringValue("");
+               break;
+            case Namespace::Entry::BoolCallbackType:
+            {
+               bool result = mNSEntry->cb.mBoolCallbackFunc(gEvalState.thisObject, mCallArgc, mCallArgv);
+               STR.popFrame();
+               CSTK.popFrame();
+               if (code[ip] == OP_STR_TO_UINT)
+               {
+                  ip++;
+                  intStack[++_UINT] = result;
+                  break;
+               }
+               else if (code[ip] == OP_STR_TO_FLT)
+               {
+                  ip++;
+                  floatStack[++_FLT] = result;
+                  break;
+               }
+               else if (code[ip] == OP_STR_TO_NONE)
+                  ip++;
+               else
+                  STR.setIntValue(result);
+               break;
+            }
+            }
+         }
+   }
+
+
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_callfunc_this(U32 &ip)
+{
+   U32 *code = mCodeBlock->code;
+
+   StringTableEntry fnName = CodeToSTE(code, ip);
+
+   //if this is called from inside a function, append the ip and codeptr
+   if (gEvalState.getStackDepth() > 0)
+   {
+      gEvalState.getCurrentFrame().code = mCodeBlock;
+      gEvalState.getCurrentFrame().ip = ip - 1;
+   }
+
+   ip += 2;
+   CSTK.getArgcArgv(fnName, &mCallArgc, &mCallArgv);
+
+   Namespace *ns = mThisObject->getNamespace();
+   if (ns)
+      mNSEntry = ns->lookup(fnName);
+   else
+      mNSEntry = NULL;
+
+   if (!mNSEntry || mExec.noCalls)
+   {
+      if (!mExec.noCalls)
+      {
+         Con::warnf(ConsoleLogEntry::General, "%s: Unknown command %s.", mCodeBlock->getFileLine(ip - 6), fnName);
+         Con::warnf(ConsoleLogEntry::General, "  Object %s(%d) %s",
+            mThisObject->getName() ? mThisObject->getName() : "",
+            mThisObject->getId(), Con::getNamespaceList(ns));
+      }
+      STR.popFrame();
+      CSTK.popFrame();
+
+      STR.setStringValue("");
+      return OPCodeReturn::success;
+   }
+
+   // ConsoleFunctionType is for any function defined by script.
+   // Any 'callback' type is an engine function that is exposed to script.
+   if (mNSEntry->mType == Namespace::Entry::ConsoleFunctionType)
+   {
+      ConsoleValueRef ret;
+      if (mNSEntry->mFunctionOffset)
+         ret = mNSEntry->mCode->exec(mNSEntry->mFunctionOffset, fnName, mNSEntry->mNamespace, mCallArgc, mCallArgv, false, mNSEntry->mPackage);
+
+      STR.popFrame();
+      // Functions are assumed to return strings, so look ahead to see if we can skip the conversion
+      if (code[ip] == OP_STR_TO_UINT)
+      {
+         ip++;
+         intStack[++_UINT] = (U32)((S32)ret);
+      }
+      else if (code[ip] == OP_STR_TO_FLT)
+      {
+         ip++;
+         floatStack[++_FLT] = (F32)ret;
+      }
+      else if (code[ip] == OP_STR_TO_NONE)
+      {
+         STR.setStringValue(ret.getStringValue());
+         ip++;
+      }
+      else
+         STR.setStringValue((const char*)ret);
+
+      // This will clear everything including returnValue
+      CSTK.popFrame();
+      //STR.clearFunctionOffset();
+   }
+   else
+   {
+      Namespace::Entry::CallbackUnion * nsCb = &mNSEntry->cb;
+      const char * nsUsage = mNSEntry->mUsage;
+      const char* nsName = ns ? ns->mName : "";
+#ifndef TORQUE_DEBUG
+      // [tom, 12/13/2006] This stops tools functions from working in the console,
+      // which is useful behavior when debugging so I'm ifdefing this out for debug builds.
+      if (mNSEntry->mToolOnly && !Con::isCurrentScriptToolScript())
+      {
+         Con::errorf(ConsoleLogEntry::Script, "%s: %s::%s - attempting to call tools only function from outside of tools.", mCodeBlock->getFileLine(ip - 6), nsName, fnName);
+      }
+      else
+#endif
+         if ((mNSEntry->mMinArgs && S32(mCallArgc) < mNSEntry->mMinArgs) || (mNSEntry->mMaxArgs && S32(mCallArgc) > mNSEntry->mMaxArgs))
+         {
+            Con::warnf(ConsoleLogEntry::Script, "%s: %s::%s - wrong number of arguments (got %i, expected min %i and max %i).",
+               mCodeBlock->getFileLine(ip - 6), nsName, fnName,
+               mCallArgc, mNSEntry->mMinArgs, mNSEntry->mMaxArgs);
+            Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", mCodeBlock->getFileLine(ip - 6), mNSEntry->mUsage);
+            STR.popFrame();
+            CSTK.popFrame();
+         }
+         else
+         {
+            switch (mNSEntry->mType)
+            {
+            case Namespace::Entry::StringCallbackType:
+            {
+               const char *ret = mNSEntry->cb.mStringCallbackFunc(mThisObject, mCallArgc, mCallArgv);
+               STR.popFrame();
+               CSTK.popFrame();
+               if (ret != STR.getStringValue())
+                  STR.setStringValue(ret);
+               //else
+               //   sSTR.setLen(dStrlen(ret));
+               break;
+            }
+            case Namespace::Entry::IntCallbackType:
+            {
+               S32 result = mNSEntry->cb.mIntCallbackFunc(mThisObject, mCallArgc, mCallArgv);
+               STR.popFrame();
+               CSTK.popFrame();
+               if (code[ip] == OP_STR_TO_UINT)
+               {
+                  ip++;
+                  intStack[++_UINT] = result;
+                  break;
+               }
+               else if (code[ip] == OP_STR_TO_FLT)
+               {
+                  ip++;
+                  floatStack[++_FLT] = result;
+                  break;
+               }
+               else if (code[ip] == OP_STR_TO_NONE)
+                  ip++;
+               else
+                  STR.setIntValue(result);
+               break;
+            }
+            case Namespace::Entry::FloatCallbackType:
+            {
+               F64 result = mNSEntry->cb.mFloatCallbackFunc(mThisObject, mCallArgc, mCallArgv);
+               STR.popFrame();
+               CSTK.popFrame();
+               if (code[ip] == OP_STR_TO_UINT)
+               {
+                  ip++;
+                  intStack[++_UINT] = (S64)result;
+                  break;
+               }
+               else if (code[ip] == OP_STR_TO_FLT)
+               {
+                  ip++;
+                  floatStack[++_FLT] = result;
+                  break;
+               }
+               else if (code[ip] == OP_STR_TO_NONE)
+                  ip++;
+               else
+                  STR.setFloatValue(result);
+               break;
+            }
+            case Namespace::Entry::VoidCallbackType:
+               mNSEntry->cb.mVoidCallbackFunc(mThisObject, mCallArgc, mCallArgv);
+               if (code[ip] != OP_STR_TO_NONE && Con::getBoolVariable("$Con::warnVoidAssignment", true))
+                  Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", mCodeBlock->getFileLine(ip - 6), fnName, mExec.functionName);
+
+               STR.popFrame();
+               CSTK.popFrame();
+               STR.setStringValue("");
+               break;
+            case Namespace::Entry::BoolCallbackType:
+            {
+               bool result = mNSEntry->cb.mBoolCallbackFunc(mThisObject, mCallArgc, mCallArgv);
+               STR.popFrame();
+               CSTK.popFrame();
+               if (code[ip] == OP_STR_TO_UINT)
+               {
+                  ip++;
+                  intStack[++_UINT] = result;
+                  break;
+               }
+               else if (code[ip] == OP_STR_TO_FLT)
+               {
+                  ip++;
+                  floatStack[++_FLT] = result;
+                  break;
+               }
+               else if (code[ip] == OP_STR_TO_NONE)
+                  ip++;
+               else
+                  STR.setIntValue(result);
+               break;
+            }
+            }
+         }
+   }
+
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_advance_str(U32 &ip)
+{
+   STR.advance();
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_advance_str_appendchar(U32 &ip)
+{
+   STR.advanceChar(mCodeBlock->code[ip++]);
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_advance_str_comma(U32 &ip)
+{
+   STR.advanceChar('_');
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_advance_str_nul(U32 &ip)
+{
+   STR.advanceChar(0);
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_rewind_str(U32 &ip)
+{
+   STR.rewind();
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_terminate_rewind_str(U32 &ip)
+{
+   STR.rewindTerminate();
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_compare_str(U32 &ip)
+{
+   intStack[++_UINT] = STR.compare();
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_push(U32 &ip)
+{
+   STR.push();
+   CSTK.pushStringStackPtr(STR.getPreviousStringValuePtr());
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_push_uint(U32 &ip)
+{
+   CSTK.pushUINT(intStack[_UINT]);
+   _UINT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_push_flt(U32 &ip)
+{
+   CSTK.pushFLT(floatStack[_FLT]);
+   _FLT--;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_push_var(U32 &ip)
+{
+   if (gEvalState.currentVariable)
+      CSTK.pushValue(gEvalState.currentVariable->value);
+   else
+      CSTK.pushString("");
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_push_this(U32 &ip)
+{
+   StringTableEntry varName = CodeToSTE(mCodeBlock->code, ip);
+   ip += 2;
+
+   // shorthand OP_SETCURVAR
+
+   // If a variable is set, then these must be NULL. It is necessary
+   // to set this here so that the vector parser can appropriately
+   // identify whether it's dealing with a vector.
+   mPrevField = NULL;
+   mPrevObject = NULL;
+   mCurObject = NULL;
+
+   gEvalState.setCurVarName(varName);
+
+   // In order to let docblocks work properly with variables, we have
+   // clear the current docblock when we do an assign. This way it 
+   // won't inappropriately carry forward to following function decls.
+   mCurFNDocBlock = NULL;
+   mCurNSDocBlock = NULL;
+
+   // shorthand OP_LOADVAR_STR (since objs can be by name we can't assume uint)
+   STR.setStringValue(gEvalState.getStringVariable());
+
+   // shorthand OP_PUSH
+   STR.push();
+   CSTK.pushStringStackPtr(STR.getPreviousStringValuePtr());
+
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_push_frame(U32 &ip)
+{
+   STR.pushFrame();
+   CSTK.pushFrame();
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_assert(U32 &ip)
+{
+   if (!intStack[_UINT--])
+   {
+      const char *message = mCurStringTable + mCodeBlock->code[ip];
+
+      U32 breakLine, inst;
+      mCodeBlock->findBreakLine(ip - 1, breakLine, inst);
+
+      if (PlatformAssert::processAssert(PlatformAssert::Fatal,
+         mCodeBlock->name ? mCodeBlock->name : "eval",
+         breakLine,
+         message))
+      {
+         if (TelDebugger && TelDebugger->isConnected() && breakLine > 0)
+         {
+            TelDebugger->breakProcess();
+         }
+         else
+            Platform::debugBreak();
+      }
+   }
+
+   ip++;
+
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_break(U32 &ip)
+{
+   //append the ip and codeptr before managing the breakpoint!
+   AssertFatal(gEvalState.getStackDepth() > 0, "Empty eval stack on break!");
+   gEvalState.getCurrentFrame().code = mCodeBlock;
+   gEvalState.getCurrentFrame().ip = ip - 1;
+
+   U32 breakLine;
+   mCodeBlock->findBreakLine(ip - 1, breakLine, mCurrentInstruction);
+   if (!breakLine)
+      return OPCodeReturn::breakContinue;
+   TelDebugger->executionStopped(mCodeBlock, breakLine);
+   return OPCodeReturn::breakContinue;
+}
+
+OPCodeReturn CodeInterpreter::op_iter_begin_str(U32 &ip)
+{
+   iterStack[_ITER].mIsStringIter = true;
+
+   // Emulate fallthrough:
+   OPCodeReturn fallthrough = op_iter_begin(ip);
+
+   return fallthrough;
+}
+
+OPCodeReturn CodeInterpreter::op_iter_begin(U32 &ip)
+{
+   StringTableEntry varName = CodeToSTE(mCodeBlock->code, ip);
+   U32 failIp = mCodeBlock->code[ip + 2];
+
+   IterStackRecord& iter = iterStack[_ITER];
+
+   iter.mVariable = gEvalState.getCurrentFrame().add(varName);
+
+   if (iter.mIsStringIter)
+   {
+      iter.mData.mStr.mString = STR.getStringValuePtr();
+      iter.mData.mStr.mIndex = 0;
+   }
+   else
+   {
+      // Look up the object.
+
+      SimSet* set;
+      if (!Sim::findObject(STR.getStringValue(), set))
+      {
+         Con::errorf(ConsoleLogEntry::General, "No SimSet object '%s'", STR.getStringValue());
+         Con::errorf(ConsoleLogEntry::General, "Did you mean to use 'foreach$' instead of 'foreach'?");
+         ip = failIp;
+         return OPCodeReturn::success;
+      }
+
+      // Set up.
+
+      iter.mData.mObj.mSet = set;
+      iter.mData.mObj.mIndex = 0;
+   }
+
+   _ITER++;
+   mIterDepth++;
+
+   STR.push();
+
+   ip += 3;
+
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_iter(U32 &ip)
+{
+   U32 breakIp = mCodeBlock->code[ip];
+   IterStackRecord& iter = iterStack[_ITER - 1];
+
+   if (iter.mIsStringIter)
+   {
+      const char* str = StringStackPtrRef(iter.mData.mStr.mString).getPtr(&STR);
+
+      U32 startIndex = iter.mData.mStr.mIndex;
+      U32 endIndex = startIndex;
+
+      // Break if at end.
+
+      if (!str[startIndex])
+      {
+         ip = breakIp;
+         return OPCodeReturn::success; // continue in old interpreter
+      }
+
+      // Find right end of current component.
+
+      if (!dIsspace(str[endIndex]))
+         do ++endIndex;
+      while (str[endIndex] && !dIsspace(str[endIndex]));
+
+      // Extract component.
+
+      if (endIndex != startIndex)
+      {
+         char savedChar = str[endIndex];
+         const_cast< char* >(str)[endIndex] = '\0'; // We are on the string stack so this is okay.
+         iter.mVariable->setStringValue(&str[startIndex]);
+         const_cast< char* >(str)[endIndex] = savedChar;
+      }
+      else
+         iter.mVariable->setStringValue("");
+
+      // Skip separator.
+      if (str[endIndex] != '\0')
+         ++endIndex;
+
+      iter.mData.mStr.mIndex = endIndex;
+   }
+   else
+   {
+      U32 index = iter.mData.mObj.mIndex;
+      SimSet* set = iter.mData.mObj.mSet;
+
+      if (index >= set->size())
+      {
+         ip = breakIp;
+         return OPCodeReturn::success; // continue in old interpreter
+      }
+
+      iter.mVariable->setIntValue(set->at(index)->getId());
+      iter.mData.mObj.mIndex = index + 1;
+   }
+
+   ++ip;
+
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_iter_end(U32 &ip)
+{
+   --_ITER;
+   --mIterDepth;
+   STR.rewind();
+   iterStack[_ITER].mIsStringIter = false;
+   return OPCodeReturn::success;
+}
+
+OPCodeReturn CodeInterpreter::op_invalid(U32 &ip)
+{
+   // Invalid does nothing.
+   return OPCodeReturn::exitCode;
+}

+ 262 - 0
Engine/source/console/codeInterpreter.h

@@ -0,0 +1,262 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _CODEINTERPRETER_H_
+#define _CODEINTERPRETER_H_
+
+#include "console/codeBlock.h"
+#include "console/console.h"
+#include "console/consoleInternal.h"
+
+/// Frame data for a foreach/foreach$ loop.
+struct IterStackRecord
+{
+   /// If true, this is a foreach$ loop; if not, it's a foreach loop.
+   bool mIsStringIter;
+
+   /// The iterator variable.
+   Dictionary::Entry* mVariable;
+
+   /// Information for an object iterator loop.
+   struct ObjectPos
+   {
+      /// The set being iterated over.
+      SimSet* mSet;
+
+      /// Current index in the set.
+      U32 mIndex;
+   };
+
+   /// Information for a string iterator loop.
+   struct StringPos
+   {
+      /// The raw string data on the string stack.
+      StringStackPtr mString;
+
+      /// Current parsing position.
+      U32 mIndex;
+   };
+
+   union
+   {
+      ObjectPos mObj;
+      StringPos mStr;
+   } mData;
+};
+
+enum OPCodeReturn
+{
+   exitCode = -1,
+   success = 0,
+   breakContinue = 1
+};
+
+class CodeInterpreter
+{
+public:
+   CodeInterpreter(CodeBlock *cb);
+   ~CodeInterpreter();
+
+   ConsoleValueRef exec(U32 ip, 
+                        StringTableEntry functionName,
+                        Namespace *thisNamespace,
+                        U32 argc, 
+                        ConsoleValueRef *argv, 
+                        bool noCalls, 
+                        StringTableEntry packageName, 
+                        S32 setFrame);
+
+   static void init();
+
+   // Methods
+private:
+   void parseArgs(U32 &ip);
+
+   /// Group op codes
+   /// @{
+
+   OPCodeReturn op_func_decl(U32 &ip);
+   OPCodeReturn op_create_object(U32 &ip);
+   OPCodeReturn op_add_object(U32 &ip);
+   OPCodeReturn op_end_object(U32 &ip);
+   OPCodeReturn op_finish_object(U32 &ip);
+   OPCodeReturn op_jmpiffnot(U32 &ip);
+   OPCodeReturn op_jmpifnot(U32 &ip);
+   OPCodeReturn op_jmpiff(U32 &ip);
+   OPCodeReturn op_jmpif(U32 &ip);
+   OPCodeReturn op_jmpifnot_np(U32 &ip);
+   OPCodeReturn op_jmpif_np(U32 &ip);
+   OPCodeReturn op_jmp(U32 &ip);
+   OPCodeReturn op_return_void(U32 &ip);
+   OPCodeReturn op_return(U32 &ip);
+   OPCodeReturn op_return_flt(U32 &ip);
+   OPCodeReturn op_return_uint(U32 &ip);
+   OPCodeReturn op_cmpeq(U32 &ip);
+   OPCodeReturn op_cmpgr(U32 &ip);
+   OPCodeReturn op_cmpge(U32 &ip);
+   OPCodeReturn op_cmplt(U32 &ip);
+   OPCodeReturn op_cmple(U32 &ip);
+   OPCodeReturn op_cmpne(U32 &ip);
+   OPCodeReturn op_xor(U32 &ip);
+   OPCodeReturn op_mod(U32 &ip);
+   OPCodeReturn op_bitand(U32 &ip);
+   OPCodeReturn op_bitor(U32 &ip);
+   OPCodeReturn op_not(U32 &ip);
+   OPCodeReturn op_notf(U32 &ip);
+   OPCodeReturn op_onescomplement(U32 &ip);
+   OPCodeReturn op_shr(U32 &ip);
+   OPCodeReturn op_shl(U32 &ip);
+   OPCodeReturn op_and(U32 &ip);
+   OPCodeReturn op_or(U32 &ip);
+   OPCodeReturn op_add(U32 &ip);
+   OPCodeReturn op_sub(U32 &ip);
+   OPCodeReturn op_mul(U32 &ip);
+   OPCodeReturn op_div(U32 &ip);
+   OPCodeReturn op_neg(U32 &ip);
+   OPCodeReturn op_inc(U32 &ip);
+   OPCodeReturn op_dec(U32 &ip);
+   OPCodeReturn op_setcurvar(U32 &ip);
+   OPCodeReturn op_setcurvar_create(U32 &ip);
+   OPCodeReturn op_setcurvar_array(U32 &ip);
+   OPCodeReturn op_setcurvar_array_varlookup(U32 &ip);
+   OPCodeReturn op_setcurvar_array_create(U32 &ip);
+   OPCodeReturn op_setcurvar_array_create_varlookup(U32 &ip);
+   OPCodeReturn op_loadvar_uint(U32 &ip);
+   OPCodeReturn op_loadvar_flt(U32 &ip);
+   OPCodeReturn op_loadvar_str(U32 &ip);
+   OPCodeReturn op_loadvar_var(U32 &ip);
+   OPCodeReturn op_savevar_uint(U32 &ip);
+   OPCodeReturn op_savevar_flt(U32 &ip);
+   OPCodeReturn op_savevar_str(U32 &ip);
+   OPCodeReturn op_savevar_var(U32 &ip);
+   OPCodeReturn op_setcurobject(U32 &ip);
+   OPCodeReturn op_setcurobject_internal(U32 &ip);
+   OPCodeReturn op_setcurobject_new(U32 &ip);
+   OPCodeReturn op_setcurfield(U32 &ip);
+   OPCodeReturn op_setcurfield_array(U32 &ip);
+   OPCodeReturn op_setcurfield_type(U32 &ip);
+   OPCodeReturn op_setcurfield_this(U32 &ip);
+   OPCodeReturn op_setcurfield_array_var(U32 &ip);
+   OPCodeReturn op_loadfield_uint(U32 &ip);
+   OPCodeReturn op_loadfield_flt(U32 &ip);
+   OPCodeReturn op_loadfield_str(U32 &ip);
+   OPCodeReturn op_savefield_uint(U32 &ip);
+   OPCodeReturn op_savefield_flt(U32 &ip);
+   OPCodeReturn op_savefield_str(U32 &ip);
+   OPCodeReturn op_str_to_uint(U32 &ip);
+   OPCodeReturn op_str_to_flt(U32 &ip);
+   OPCodeReturn op_str_to_none(U32 &ip);
+   OPCodeReturn op_flt_to_uint(U32 &ip);
+   OPCodeReturn op_flt_to_str(U32 &ip);
+   OPCodeReturn op_flt_to_none(U32 &ip);
+   OPCodeReturn op_uint_to_flt(U32 &ip);
+   OPCodeReturn op_uint_to_str(U32 &ip);
+   OPCodeReturn op_uint_to_none(U32 &ip);
+   OPCodeReturn op_copyvar_to_none(U32 &ip);
+   OPCodeReturn op_loadimmed_uint(U32 &ip);
+   OPCodeReturn op_loadimmed_flt(U32 &ip);
+   OPCodeReturn op_tag_to_str(U32 &ip);
+   OPCodeReturn op_loadimmed_str(U32 &ip);
+   OPCodeReturn op_docblock_str(U32 &ip);
+   OPCodeReturn op_loadimmed_ident(U32 &ip);
+   OPCodeReturn op_callfunc_resolve(U32 &ip);
+   OPCodeReturn op_callfunc(U32 &ip);
+   OPCodeReturn op_callfunc_pointer(U32 &ip);
+   OPCodeReturn op_callfunc_this(U32 &ip);
+   OPCodeReturn op_advance_str(U32 &ip);
+   OPCodeReturn op_advance_str_appendchar(U32 &ip);
+   OPCodeReturn op_advance_str_comma(U32 &ip);
+   OPCodeReturn op_advance_str_nul(U32 &ip);
+   OPCodeReturn op_rewind_str(U32 &ip);
+   OPCodeReturn op_terminate_rewind_str(U32 &ip);
+   OPCodeReturn op_compare_str(U32 &ip);
+   OPCodeReturn op_push(U32 &ip);
+   OPCodeReturn op_push_uint(U32 &ip);
+   OPCodeReturn op_push_flt(U32 &ip);
+   OPCodeReturn op_push_var(U32 &ip);
+   OPCodeReturn op_push_this(U32 &ip);
+   OPCodeReturn op_push_frame(U32 &ip);
+   OPCodeReturn op_assert(U32 &ip);
+   OPCodeReturn op_break(U32 &ip);
+   OPCodeReturn op_iter_begin_str(U32 &ip);
+   OPCodeReturn op_iter_begin(U32 &ip);
+   OPCodeReturn op_iter(U32 &ip);
+   OPCodeReturn op_iter_end(U32 &ip);
+   OPCodeReturn op_invalid(U32 &ip);
+
+   /// @}
+
+private:
+   CodeBlock *mCodeBlock;
+
+   /// Group exec arguments.
+   struct
+   {
+      StringTableEntry functionName;
+      Namespace *thisNamespace;
+      U32 argc;
+      ConsoleValueRef *argv;
+      bool noCalls;
+      StringTableEntry packageName;
+      S32 setFrame;
+   } mExec;
+
+   U32 mIterDepth;
+   F64 *mCurFloatTable;
+   char *mCurStringTable;
+   StringTableEntry mThisFunctionName;
+   bool mPopFrame;
+
+   // Add local object creation stack [7/9/2007 Black]
+   static const U32 objectCreationStackSize = 32;
+   U32 mObjectCreationStackIndex;
+   struct 
+   {
+      SimObject *newObject;
+      U32 failJump;
+   } mObjectCreationStack[objectCreationStackSize];
+
+   SimObject *mCurrentNewObject;
+   U32 mFailJump;
+   StringTableEntry mPrevField;
+   StringTableEntry mCurField;
+   SimObject *mPrevObject;
+   SimObject *mCurObject;
+   SimObject *mSaveObject;
+   SimObject *mThisObject;
+   Namespace::Entry *mNSEntry;
+   StringTableEntry mCurFNDocBlock;
+   StringTableEntry mCurNSDocBlock;
+   U32 mCallArgc;
+   ConsoleValueRef *mCallArgv;
+   CodeBlock *mSaveCodeBlock;
+
+   // note: anything returned is pushed to CSTK and will be invalidated on the next exec()
+   ConsoleValueRef mReturnValue;
+
+   U32 mCurrentInstruction;
+
+   static const S32 nsDocLength = 128;
+   char mNSDocBlockClass[nsDocLength];
+};
+
+#endif

+ 53 - 2095
Engine/source/console/compiledEval.cpp

@@ -20,11 +20,6 @@
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 
-//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
-// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
-// Copyright (C) 2015 Faust Logic, Inc.
-//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
-
 #include "platform/platform.h"
 #include "console/console.h"
 
@@ -45,95 +40,38 @@
 #include "util/messaging/message.h"
 #include "core/frameAllocator.h"
 
+#include "console/codeInterpreter.h"
+
 #ifndef TORQUE_TGB_ONLY
 #include "materials/materialDefinition.h"
 #include "materials/materialManager.h"
 #endif
 
-// Uncomment to optimize function calls at the expense of potential invalid package lookups
-//#define COMPILER_OPTIMIZE_FUNCTION_CALLS
-
 using namespace Compiler;
 
-enum EvalConstants {
-   MaxStackSize = 1024,
-   MethodOnComponent = -2
-};
-
 namespace Con
 {
-// Current script file name and root, these are registered as
-// console variables.
-extern StringTableEntry gCurrentFile;
-extern StringTableEntry gCurrentRoot;
-extern S32 gObjectCopyFailures;
+   // Current script file name and root, these are registered as
+   // console variables.
+   extern StringTableEntry gCurrentFile;
+   extern StringTableEntry gCurrentRoot;
+   extern S32 gObjectCopyFailures;
 }
 
-/// Frame data for a foreach/foreach$ loop.
-struct IterStackRecord
-{
-   /// If true, this is a foreach$ loop; if not, it's a foreach loop.
-   bool mIsStringIter;
-   
-   /// The iterator variable.
-   Dictionary::Entry* mVariable;
-   
-   /// Information for an object iterator loop.
-   struct ObjectPos
-   {
-      /// The set being iterated over.
-      SimSet* mSet;
-
-      /// Current index in the set.
-      U32 mIndex;
-   };
-   
-   /// Information for a string iterator loop.
-   struct StringPos
-   {
-      /// The raw string data on the string stack.
-      StringStackPtr mString;
-      
-      /// Current parsing position.
-      U32 mIndex;
-   };
-   
-   union
-   {
-      ObjectPos mObj;
-      StringPos mStr;
-   } mData;
-};
-
-IterStackRecord iterStack[ MaxStackSize ];
-
-F64 floatStack[MaxStackSize];
-S64 intStack[MaxStackSize];
-
-
-
-
-StringStack STR;
-ConsoleValueStack CSTK;
-
-U32 _FLT = 0;     ///< Stack pointer for floatStack.
-U32 _UINT = 0;    ///< Stack pointer for intStack.
-U32 _ITER = 0;    ///< Stack pointer for iterStack.
-
 namespace Con
 {
    const char *getNamespaceList(Namespace *ns)
    {
       U32 size = 1;
       Namespace * walk;
-      for(walk = ns; walk; walk = walk->mParent)
+      for (walk = ns; walk; walk = walk->mParent)
          size += dStrlen(walk->mName) + 4;
       char *ret = Con::getReturnBuffer(size);
       ret[0] = 0;
-      for(walk = ns; walk; walk = walk->mParent)
+      for (walk = ns; walk; walk = walk->mParent)
       {
          dStrcat(ret, walk->mName);
-         if(walk->mParent)
+         if (walk->mParent)
             dStrcat(ret, " -> ");
       }
       return ret;
@@ -145,13 +83,13 @@ namespace Con
 F64 consoleStringToNumber(const char *str, StringTableEntry file, U32 line)
 {
    F64 val = dAtof(str);
-   if(val != 0)
+   if (val != 0)
       return val;
-   else if(!dStricmp(str, "true"))
+   else if (!dStricmp(str, "true"))
       return 1;
-   else if(!dStricmp(str, "false"))
+   else if (!dStricmp(str, "false"))
       return 0;
-   else if(file)
+   else if (file)
    {
       Con::warnf(ConsoleLogEntry::General, "%s (%d): string always evaluates to 0.", file, line);
       return 0;
@@ -170,28 +108,28 @@ namespace Con
       return STR.getReturnBuffer(bufferSize);
    }
 
-   char *getReturnBuffer( const char *stringToCopy )
+   char *getReturnBuffer(const char *stringToCopy)
    {
-      U32 len = dStrlen( stringToCopy ) + 1;
-      char *ret = STR.getReturnBuffer( len);
-      dMemcpy( ret, stringToCopy, len );
+      U32 len = dStrlen(stringToCopy) + 1;
+      char *ret = STR.getReturnBuffer(len);
+      dMemcpy(ret, stringToCopy, len);
       return ret;
    }
 
-   char* getReturnBuffer( const String& str )
+   char* getReturnBuffer(const String& str)
    {
       const U32 size = str.size();
-      char* ret = STR.getReturnBuffer( size );
-      dMemcpy( ret, str.c_str(), size );
+      char* ret = STR.getReturnBuffer(size);
+      dMemcpy(ret, str.c_str(), size);
       return ret;
    }
 
-   char* getReturnBuffer( const StringBuilder& str )
+   char* getReturnBuffer(const StringBuilder& str)
    {
-      char* buffer = Con::getReturnBuffer( str.length() + 1 );
-      str.copy( buffer );
-      buffer[ str.length() ] = '\0';
-      
+      char* buffer = Con::getReturnBuffer(str.length() + 1);
+      str.copy(buffer);
+      buffer[str.length()] = '\0';
+
       return buffer;
    }
 
@@ -221,40 +159,40 @@ namespace Con
       return ret;
    }
 
-   char *getStringArg( const char *arg )
+   char *getStringArg(const char *arg)
    {
-      U32 len = dStrlen( arg ) + 1;
-      char *ret = STR.getArgBuffer( len );
-      dMemcpy( ret, arg, len );
+      U32 len = dStrlen(arg) + 1;
+      char *ret = STR.getArgBuffer(len);
+      dMemcpy(ret, arg, len);
       return ret;
    }
 
-   char* getStringArg( const String& arg )
+   char* getStringArg(const String& arg)
    {
       const U32 size = arg.size();
-      char* ret = STR.getArgBuffer( size );
-      dMemcpy( ret, arg.c_str(), size );
+      char* ret = STR.getArgBuffer(size);
+      dMemcpy(ret, arg.c_str(), size);
       return ret;
    }
 }
 
 //------------------------------------------------------------
 
-inline void ExprEvalState::setCurVarName(StringTableEntry name)
+void ExprEvalState::setCurVarName(StringTableEntry name)
 {
-   if(name[0] == '$')
+   if (name[0] == '$')
       currentVariable = globalVars.lookup(name);
-   else if( getStackDepth() > 0 )
+   else if (getStackDepth() > 0)
       currentVariable = getCurrentFrame().lookup(name);
-   if(!currentVariable && gWarnUndefinedScriptVariables)
+   if (!currentVariable && gWarnUndefinedScriptVariables)
       Con::warnf(ConsoleLogEntry::Script, "Variable referenced before assignment: %s", name);
 }
 
-inline void ExprEvalState::setCurVarNameCreate(StringTableEntry name)
+void ExprEvalState::setCurVarNameCreate(StringTableEntry name)
 {
-   if(name[0] == '$')
+   if (name[0] == '$')
       currentVariable = globalVars.add(name);
-   else if( getStackDepth() > 0 )
+   else if (getStackDepth() > 0)
       currentVariable = getCurrentFrame().add(name);
    else
    {
@@ -265,48 +203,48 @@ inline void ExprEvalState::setCurVarNameCreate(StringTableEntry name)
 
 //------------------------------------------------------------
 
-inline S32 ExprEvalState::getIntVariable()
+S32 ExprEvalState::getIntVariable()
 {
    return currentVariable ? currentVariable->getIntValue() : 0;
 }
 
-inline F64 ExprEvalState::getFloatVariable()
+F64 ExprEvalState::getFloatVariable()
 {
    return currentVariable ? currentVariable->getFloatValue() : 0;
 }
 
-inline const char *ExprEvalState::getStringVariable()
+const char *ExprEvalState::getStringVariable()
 {
    return currentVariable ? currentVariable->getStringValue() : "";
 }
 
 //------------------------------------------------------------
 
-inline void ExprEvalState::setIntVariable(S32 val)
+void ExprEvalState::setIntVariable(S32 val)
 {
    AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!");
    currentVariable->setIntValue(val);
 }
 
-inline void ExprEvalState::setFloatVariable(F64 val)
+void ExprEvalState::setFloatVariable(F64 val)
 {
    AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!");
    currentVariable->setFloatValue(val);
 }
 
-inline void ExprEvalState::setStringVariable(const char *val)
+void ExprEvalState::setStringVariable(const char *val)
 {
    AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!");
    currentVariable->setStringValue(val);
 }
 
-inline void ExprEvalState::setStringStackPtrVariable(StringStackPtr str)
+void ExprEvalState::setStringStackPtrVariable(StringStackPtr str)
 {
    AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!");
    currentVariable->setStringStackPtrValue(str);
 }
 
-inline void ExprEvalState::setCopyVariable()
+void ExprEvalState::setCopyVariable()
 {
    if (copyVariable)
    {
@@ -314,2004 +252,24 @@ inline void ExprEvalState::setCopyVariable()
       {
          case ConsoleValue::TypeInternalInt:
             currentVariable->setIntValue(copyVariable->getIntValue());
-         break;
+            break;
          case ConsoleValue::TypeInternalFloat:
             currentVariable->setFloatValue(copyVariable->getFloatValue());
-         break;
+            break;
          default:
             currentVariable->setStringValue(copyVariable->getStringValue());
-         break;
+            break;
       }
    }
 }
 
 //------------------------------------------------------------
 
-// Gets a component of an object's field value or a variable and returns it
-// in val.
-static void getFieldComponent( SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField, char val[] )
-{
-   const char* prevVal = NULL;
-   
-   // Grab value from object.
-   if( object && field )
-      prevVal = object->getDataField( field, array );
-   
-   // Otherwise, grab from the string stack. The value coming in will always
-   // be a string because that is how multicomponent variables are handled.
-   else
-      prevVal = STR.getStringValue();
-
-   // Make sure we got a value.
-   if ( prevVal && *prevVal )
-   {
-      static const StringTableEntry xyzw[] = 
-      {
-         StringTable->insert( "x" ),
-         StringTable->insert( "y" ),
-         StringTable->insert( "z" ),
-         StringTable->insert( "w" )
-      };
-
-      static const StringTableEntry rgba[] = 
-      {
-         StringTable->insert( "r" ),
-         StringTable->insert( "g" ),
-         StringTable->insert( "b" ),
-         StringTable->insert( "a" )
-      };
-
-      // Translate xyzw and rgba into the indexed component 
-      // of the variable or field.
-      if ( subField == xyzw[0] || subField == rgba[0] )
-         dStrcpy( val, StringUnit::getUnit( prevVal, 0, " \t\n") );
-
-      else if ( subField == xyzw[1] || subField == rgba[1] )
-         dStrcpy( val, StringUnit::getUnit( prevVal, 1, " \t\n") );
-
-      else if ( subField == xyzw[2] || subField == rgba[2] )
-         dStrcpy( val, StringUnit::getUnit( prevVal, 2, " \t\n") );
-
-      else if ( subField == xyzw[3] || subField == rgba[3] )
-         dStrcpy( val, StringUnit::getUnit( prevVal, 3, " \t\n") );
-
-      else
-         val[0] = 0;
-   }
-   else
-      val[0] = 0;
-}
-
-// Sets a component of an object's field value based on the sub field. 'x' will
-// set the first field, 'y' the second, and 'z' the third.
-static void setFieldComponent( SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField )
-{
-   // Copy the current string value
-   char strValue[1024];
-   dStrncpy( strValue, STR.getStringValue(), 1024 );
-
-   char val[1024] = "";
-   const char* prevVal = NULL;
-
-   // Set the value on an object field.
-   if( object && field )
-      prevVal = object->getDataField( field, array );
-
-   // Set the value on a variable.
-   else if( gEvalState.currentVariable )
-      prevVal = gEvalState.getStringVariable();
-
-   // Ensure that the variable has a value
-   if (!prevVal)
-      return;
-
-   static const StringTableEntry xyzw[] = 
-   {
-      StringTable->insert( "x" ),
-      StringTable->insert( "y" ),
-      StringTable->insert( "z" ),
-      StringTable->insert( "w" )
-   };
-
-   static const StringTableEntry rgba[] = 
-   {
-      StringTable->insert( "r" ),
-      StringTable->insert( "g" ),
-      StringTable->insert( "b" ),
-      StringTable->insert( "a" )
-   };
-
-   // Insert the value into the specified 
-   // component of the string.
-   if ( subField == xyzw[0] || subField == rgba[0] )
-     dStrcpy( val, StringUnit::setUnit( prevVal, 0, strValue, " \t\n") );
-
-   else if ( subField == xyzw[1] || subField == rgba[1] )
-      dStrcpy( val, StringUnit::setUnit( prevVal, 1, strValue, " \t\n") );
-
-   else if ( subField == xyzw[2] || subField == rgba[2] )
-      dStrcpy( val, StringUnit::setUnit( prevVal, 2, strValue, " \t\n") );
-
-   else if ( subField == xyzw[3] || subField == rgba[3] )
-      dStrcpy( val, StringUnit::setUnit( prevVal, 3, strValue, " \t\n") );
-
-   if ( val[0] != 0 )
-   {
-      // Update the field or variable.
-      if( object && field )
-         object->setDataField( field, 0, val );
-      else if( gEvalState.currentVariable )
-         gEvalState.setStringVariable( val );
-   }
-}
 
 ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNamespace, U32 argc, ConsoleValueRef *argv, bool noCalls, StringTableEntry packageName, S32 setFrame)
 {
-
-#ifdef TORQUE_VALIDATE_STACK
-   U32 stackStart = STR.mStartStackSize;
-   U32 consoleStackStart = CSTK.mStackPos;
-#endif
-
-   //Con::printf("CodeBlock::exec(%s,%u)", functionName ? functionName : "??", ip);
-
-   static char traceBuffer[1024];
-   S32 i;
-   
-   U32 iterDepth = 0;
-
-   incRefCount();
-   F64 *curFloatTable;
-   char *curStringTable;
-   S32 curStringTableLen = 0; //clint to ensure we dont overwrite it
-   STR.clearFunctionOffset(); // ensures arg buffer offset is back to 0
-   StringTableEntry thisFunctionName = NULL;
-   bool popFrame = false;
-   if(argv)
-   {
-      // assume this points into a function decl:
-      U32 fnArgc = code[ip + 2 + 6];
-      thisFunctionName = CodeToSTE(code, ip);
-      S32 wantedArgc = getMin(argc-1, fnArgc); // argv[0] is func name
-      if(gEvalState.traceOn)
-      {
-         traceBuffer[0] = 0;
-         dStrcat(traceBuffer, "Entering ");
-         if(packageName)
-         {
-            dStrcat(traceBuffer, "[");
-            dStrcat(traceBuffer, packageName);
-            dStrcat(traceBuffer, "]");
-         }
-         if(thisNamespace && thisNamespace->mName)
-         {
-            dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
-               "%s::%s(", thisNamespace->mName, thisFunctionName);
-         }
-         else
-         {
-            dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
-               "%s(", thisFunctionName);
-         }
-         for(i = 0; i < wantedArgc; i++)
-         {
-            dStrcat(traceBuffer, argv[i+1]);
-            if(i != wantedArgc - 1)
-               dStrcat(traceBuffer, ", ");
-         }
-         dStrcat(traceBuffer, ")");
-         Con::printf("%s", traceBuffer);
-      }
-      gEvalState.pushFrame(thisFunctionName, thisNamespace);
-      popFrame = true;
-
-      for(i = 0; i < wantedArgc; i++)
-      {
-         StringTableEntry var = CodeToSTE(code, ip + (2 + 6 + 1) + (i * 2));
-         gEvalState.setCurVarNameCreate(var);
-
-         ConsoleValueRef ref = argv[i+1];
-
-         switch(argv[i+1].getType())
-         {
-         case ConsoleValue::TypeInternalInt:
-            gEvalState.setIntVariable(argv[i+1]);
-            break;
-         case ConsoleValue::TypeInternalFloat:
-            gEvalState.setFloatVariable(argv[i+1]);
-            break;
-         case ConsoleValue::TypeInternalStringStackPtr:
-            gEvalState.setStringStackPtrVariable(argv[i+1].getStringStackPtrValue());
-            break;
-         case ConsoleValue::TypeInternalStackString:
-         case ConsoleValue::TypeInternalString:
-         default:
-            gEvalState.setStringVariable(argv[i+1]);
-            break;
-         }
-      }
-
-      ip = ip + (fnArgc * 2) + (2 + 6 + 1);
-      curFloatTable = functionFloats;
-      curStringTable = functionStrings;
-      curStringTableLen = functionStringsMaxLen;
-   }
-   else
-   {
-      curFloatTable = globalFloats;
-      curStringTable = globalStrings;
-      curStringTableLen = globalStringsMaxLen;
-
-      // If requested stack frame isn't available, request a new one
-      // (this prevents assert failures when creating local
-      //  variables without a stack frame)
-      if (gEvalState.getStackDepth() <= setFrame)
-         setFrame = -1;
-
-      // Do we want this code to execute using a new stack frame?
-      if (setFrame < 0)
-      {
-         gEvalState.pushFrame(NULL, NULL);
-         popFrame = true;
-      }
-      else
-      {
-         // We want to copy a reference to an existing stack frame
-         // on to the top of the stack.  Any change that occurs to 
-         // the locals during this new frame will also occur in the 
-         // original frame.
-         S32 stackIndex = gEvalState.getStackDepth() - setFrame - 1;
-         gEvalState.pushFrameRef( stackIndex );
-         popFrame = true;
-      }
-   }
-
-   // Grab the state of the telenet debugger here once
-   // so that the push and pop frames are always balanced.
-   const bool telDebuggerOn = TelDebugger && TelDebugger->isConnected();
-   if ( telDebuggerOn && setFrame < 0 )
-      TelDebugger->pushStackFrame();
-
-   StringTableEntry var, objParent;
-   StringTableEntry fnName;
-   StringTableEntry fnNamespace, fnPackage;
-
-   // Add local object creation stack [7/9/2007 Black]
-   static const U32 objectCreationStackSize = 32;
-   U32 objectCreationStackIndex = 0;
-   struct {
-      SimObject *newObject;
-      U32 failJump;
-   } objectCreationStack[ objectCreationStackSize ];
-   
-   SimObject *currentNewObject = 0;
-   U32 failJump = 0;
-   StringTableEntry prevField = NULL;
-   StringTableEntry curField = NULL;
-   SimObject *prevObject = NULL;
-   SimObject *curObject = NULL;
-   SimObject *saveObject=NULL;
-   Namespace::Entry *nsEntry;
-   Namespace *ns;
-   const char* curFNDocBlock = NULL;
-   const char* curNSDocBlock = NULL;
-   const S32 nsDocLength = 128;
-   char nsDocBlockClass[nsDocLength];
-
-   U32 callArgc;
-   ConsoleValueRef *callArgv;
-
-   static char curFieldArray[256];
-   static char prevFieldArray[256];
-
-   CodeBlock *saveCodeBlock = smCurrentCodeBlock;
-   smCurrentCodeBlock = this;
-   if(this->name)
-   {
-      Con::gCurrentFile = this->name;
-      Con::gCurrentRoot = this->modPath;
-   }
-   const char * val;
-   StringStackPtr retValue;
-
-   // note: anything returned is pushed to CSTK and will be invalidated on the next exec()
-   ConsoleValueRef returnValue;
-
-   // The frame temp is used by the variable accessor ops (OP_SAVEFIELD_* and
-   // OP_LOADFIELD_*) to store temporary values for the fields.
-   static S32 VAL_BUFFER_SIZE = 1024;
-   FrameTemp<char> valBuffer( VAL_BUFFER_SIZE );
-
-   for(;;)
-   {
-      U32 instruction = code[ip++];
-      nsEntry = NULL;
-breakContinue:
-      switch(instruction)
-      {
-         case OP_FUNC_DECL:
-            if(!noCalls)
-            {
-               fnName       = CodeToSTE(code, ip);
-               fnNamespace  = CodeToSTE(code, ip+2);
-               fnPackage    = CodeToSTE(code, ip+4);
-               bool hasBody = ( code[ ip + 6 ] & 0x01 ) != 0;
-               U32 lineNumber = code[ ip + 6 ] >> 1;
-               
-               Namespace::unlinkPackages();
-               ns = Namespace::find(fnNamespace, fnPackage);
-               ns->addFunction(fnName, this, hasBody ? ip : 0, curFNDocBlock ? dStrdup( curFNDocBlock ) : NULL, lineNumber );// if no body, set the IP to 0
-               if( curNSDocBlock )
-               {
-                  if( fnNamespace == StringTable->lookup( nsDocBlockClass ) )
-                  {
-                     char *usageStr = dStrdup( curNSDocBlock );
-                     usageStr[dStrlen(usageStr)] = '\0';
-                     ns->mUsage = usageStr;
-                     ns->mCleanUpUsage = true;
-                     curNSDocBlock = NULL;
-                  }
-               }
-               Namespace::relinkPackages();
-
-               // If we had a docblock, it's definitely not valid anymore, so clear it out.
-               curFNDocBlock = NULL;
-
-               //Con::printf("Adding function %s::%s (%d)", fnNamespace, fnName, ip);
-            }
-            ip = code[ip + 7];
-            break;
-
-         case OP_CREATE_OBJECT:
-         {
-            // Read some useful info.
-            objParent        = CodeToSTE(code, ip);
-            bool isDataBlock =          code[ip + 2];
-            bool isInternal  =          code[ip + 3];
-            bool isSingleton =          code[ip + 4];
-            U32  lineNumber  =          code[ip + 5];
-            failJump         =          code[ip + 6];
-                        
-            // If we don't allow calls, we certainly don't allow creating objects!
-            // Moved this to after failJump is set. Engine was crashing when
-            // noCalls = true and an object was being created at the beginning of
-            // a file. ADL.
-            if(noCalls)
-            {
-               ip = failJump;
-               break;
-            }
-
-            // Push the old info to the stack
-            //Assert( objectCreationStackIndex < objectCreationStackSize );
-            objectCreationStack[ objectCreationStackIndex ].newObject = currentNewObject;
-            objectCreationStack[ objectCreationStackIndex++ ].failJump = failJump;
-
-            // Get the constructor information off the stack.
-            CSTK.getArgcArgv(NULL, &callArgc, &callArgv);
-            const char *objectName = callArgv[ 2 ];
-
-            // Con::printf("Creating object...");
-
-            // objectName = argv[1]...
-            currentNewObject = NULL;
-
-            // Are we creating a datablock? If so, deal with case where we override
-            // an old one.
-            if(isDataBlock)
-            {
-               // Con::printf("  - is a datablock");
-
-               // Find the old one if any.
-               SimObject *db = Sim::getDataBlockGroup()->findObject( objectName );
-               
-               // Make sure we're not changing types on ourselves...
-               if(db && dStricmp(db->getClassName(), callArgv[1]))
-               {
-                  Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare data block %s with a different class.", getFileLine(ip), objectName);
-                  ip = failJump;
-                  STR.popFrame();
-                  CSTK.popFrame();
-                  break;
-               }
-
-               // If there was one, set the currentNewObject and move on.
-               if(db)
-                  currentNewObject = db;
-            }
-            else if (!isInternal)
-            {
-               // IF we aren't looking at a local/internal object, then check if 
-               // this object already exists in the global space
-
-               AbstractClassRep* rep = AbstractClassRep::findClassRep( objectName );
-               if (rep != NULL) {
-                  Con::errorf(ConsoleLogEntry::General, "%s: Cannot name object [%s] the same name as a script class.",
-                     getFileLine(ip), objectName);
-                  ip = failJump;
-                  STR.popFrame();
-                  break;
-               }
-
-               SimObject *obj = Sim::findObject( (const char*)objectName );
-               if (obj /*&& !obj->isLocalName()*/)
-               {
-                  if ( isSingleton )
-                  {
-                     // Make sure we're not trying to change types
-                     if ( dStricmp( obj->getClassName(), (const char*)callArgv[1] ) != 0 )
-                     {
-                        Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare object [%s] with a different class [%s] - was [%s].",
-                           getFileLine(ip), objectName, (const char*)callArgv[1], obj->getClassName());
-                        ip = failJump;
-                        STR.popFrame();
-                        CSTK.popFrame();
-                        break;
-                     }
-
-                     // We're creating a singleton, so use the found object
-                     // instead of creating a new object.
-                     currentNewObject = obj;
-                  }
-                  else
-                  {
-                     const char* redefineBehavior = Con::getVariable( "$Con::redefineBehavior" );
-                     
-                     if( dStricmp( redefineBehavior, "replaceExisting" ) == 0 )
-                     {
-                        // Save our constructor args as the argv vector is stored on the
-                        // string stack and may get stomped if deleteObject triggers
-                        // script execution.
-                        
-                        ConsoleValueRef savedArgv[ StringStack::MaxArgs ];
-                        for (int i=0; i<callArgc; i++) {
-                           savedArgv[i] = callArgv[i];
-                        }
-                        //dMemcpy( savedArgv, callArgv, sizeof( savedArgv[ 0 ] ) * callArgc );
-                        
-                        // Prevent stack value corruption
-                        CSTK.pushFrame();
-                        STR.pushFrame();
-                        // --
-
-                        obj->deleteObject();
-                        obj = NULL;
-
-                        // Prevent stack value corruption
-                        CSTK.popFrame();
-                        STR.popFrame();
-                        // --
-
-                        //dMemcpy( callArgv, savedArgv, sizeof( callArgv[ 0 ] ) * callArgc );
-                        for (int i=0; i<callArgc; i++) {
-                           callArgv[i] = savedArgv[i];
-                        }
-                     }
-                     else if( dStricmp( redefineBehavior, "renameNew" ) == 0 )
-                     {
-                        for( U32 i = 1;; ++ i )
-                        {
-                           String newName = String::ToString( "%s%i", objectName, i );
-                           if( !Sim::findObject( newName ) )
-                           {
-                              objectName = StringTable->insert( newName );
-                              break;
-                           }
-                        }
-                     }
-                     else if( dStricmp( redefineBehavior, "unnameNew" ) == 0 )
-                     {
-                        objectName = StringTable->insert( "" );
-                     }
-                     else if( dStricmp( redefineBehavior, "postfixNew" ) == 0 )
-                     {
-                        const char* postfix = Con::getVariable( "$Con::redefineBehaviorPostfix" );
-                        String newName = String::ToString( "%s%s", objectName, postfix );
-                        
-                        if( Sim::findObject( newName ) )
-                        {
-                           Con::errorf( ConsoleLogEntry::General, "%s: Cannot re-declare object with postfix [%s].",
-                              getFileLine(ip), newName.c_str() );
-                           ip = failJump;
-                           STR.popFrame();
-                           CSTK.popFrame();
-                           break;
-                        }
-                        else
-                           objectName = StringTable->insert( newName );
-                     }
-                     else
-                     {
-                        Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare object [%s].",
-                           getFileLine(ip), objectName);
-                        ip = failJump;
-                        STR.popFrame();
-                        CSTK.popFrame();
-                        break;
-                     }
-                  }
-               }
-            }
-
-            STR.popFrame();
-            CSTK.popFrame();
-            
-            if(!currentNewObject)
-            {
-               // Well, looks like we have to create a new object.
-               ConsoleObject *object = ConsoleObject::create((const char*)callArgv[1]);
-
-               // Deal with failure!
-               if(!object)
-               {
-                  Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-conobject class %s.", getFileLine(ip), (const char*)callArgv[1]);
-                  ip = failJump;
-                  break;
-               }
-
-               // Do special datablock init if appropros
-               if(isDataBlock)
-               {
-                  SimDataBlock *dataBlock = dynamic_cast<SimDataBlock *>(object);
-                  if(dataBlock)
-                  {
-                     dataBlock->assignId();
-                  }
-                  else
-                  {
-                     // They tried to make a non-datablock with a datablock keyword!
-                     Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-datablock class %s.", getFileLine(ip), (const char*)callArgv[1]);
-                     // Clean up...
-                     delete object;
-                     currentNewObject = NULL;
-                     ip = failJump;
-                     break;
-                  }
-               }
-
-               // Finally, set currentNewObject to point to the new one.
-               currentNewObject = dynamic_cast<SimObject *>(object);
-
-               // Deal with the case of a non-SimObject.
-               if(!currentNewObject)
-               {
-                  Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-SimObject class %s.", getFileLine(ip), (const char*)callArgv[1]);
-                  delete object;
-                  currentNewObject = NULL;
-                  ip = failJump;
-                  break;
-               }
-
-               // Set the declaration line
-               currentNewObject->setDeclarationLine(lineNumber);
-
-               // Set the file that this object was created in
-               currentNewObject->setFilename(name);
-
-               // Does it have a parent object? (ie, the copy constructor : syntax, not inheriance)
-               if(*objParent)
-               {
-                  // Find it!
-                  SimObject *parent;
-                  if(Sim::findObject(objParent, parent))
-                  {
-                     // Con::printf(" - Parent object found: %s", parent->getClassName());
-
-                     currentNewObject->setCopySource( parent );
-                     currentNewObject->assignFieldsFrom( parent );
-                     // copy any substitution statements
-                     SimDataBlock* parent_db = dynamic_cast<SimDataBlock*>(parent);
-                     if (parent_db)
-                     {
-                        SimDataBlock* currentNewObject_db = dynamic_cast<SimDataBlock*>(currentNewObject);
-                        if (currentNewObject_db)
-                           currentNewObject_db->copySubstitutionsFrom(parent_db);
-                     }
-                  }
-                  else
-                  {
-                     if ( Con::gObjectCopyFailures == -1 )
-                        Con::errorf(ConsoleLogEntry::General, "%s: Unable to find parent object %s for %s.", getFileLine(ip), objParent, (const char*)callArgv[1]);
-                     else
-                        ++Con::gObjectCopyFailures;
-
-                     // Fail to create the object.
-                     delete object;
-                     currentNewObject = NULL;
-                     ip = failJump;
-                     break;
-                  }
-               }
-
-               // If a name was passed, assign it.
-               if( objectName[ 0 ] )
-               {
-                  if( !isInternal )
-                     currentNewObject->assignName( objectName );
-                  else
-                     currentNewObject->setInternalName( objectName );
-
-                  // Set the original name
-                  currentNewObject->setOriginalName( objectName );
-               }
-
-               // Prevent stack value corruption
-               CSTK.pushFrame();
-               STR.pushFrame();
-               // --
-
-               // Do the constructor parameters.
-               if(!currentNewObject->processArguments(callArgc-3, callArgv+3))
-               {
-                  delete currentNewObject;
-                  currentNewObject = NULL;
-                  ip = failJump;
-
-                  // Prevent stack value corruption
-                  CSTK.popFrame();
-                  STR.popFrame();
-                  // --
-                  break;
-               }
-
-               // Prevent stack value corruption
-               CSTK.popFrame();
-               STR.popFrame();
-               // --
-
-               // If it's not a datablock, allow people to modify bits of it.
-               if(!isDataBlock)
-               {
-                  currentNewObject->setModStaticFields(true);
-                  currentNewObject->setModDynamicFields(true);
-               }
-            }
-            else
-            {
-               currentNewObject->reloadReset(); // AFX (reload-reset)
-               // Does it have a parent object? (ie, the copy constructor : syntax, not inheriance)
-               if(*objParent)
-               {
-                  // Find it!
-                  SimObject *parent;
-                  if(Sim::findObject(objParent, parent))
-                  {
-                     // Con::printf(" - Parent object found: %s", parent->getClassName());
-
-                     // temporarily block name change
-                     SimObject::preventNameChanging = true;
-                     currentNewObject->setCopySource( parent );
-                     currentNewObject->assignFieldsFrom(parent);
-                     // restore name changing
-                     SimObject::preventNameChanging = false;
-
-                     // copy any substitution statements
-                     SimDataBlock* parent_db = dynamic_cast<SimDataBlock*>(parent);
-                     if (parent_db)
-                     {
-                        SimDataBlock* currentNewObject_db = dynamic_cast<SimDataBlock*>(currentNewObject);
-                        if (currentNewObject_db)
-                           currentNewObject_db->copySubstitutionsFrom(parent_db);
-                     }
-                  }
-                  else
-                     Con::errorf(ConsoleLogEntry::General, "%d: Unable to find parent object %s for %s.", lineNumber, objParent, (const char*)callArgv[1]);
-               }
-            }
-
-            // Advance the IP past the create info...
-            ip += 7;
-            break;
-         }
-
-         case OP_ADD_OBJECT:
-         {
-            // See OP_SETCURVAR for why we do this.
-            curFNDocBlock = NULL;
-            curNSDocBlock = NULL;
-            
-            // Do we place this object at the root?
-            bool placeAtRoot = code[ip++];
-
-            // Con::printf("Adding object %s", currentNewObject->getName());
-
-            // Prevent stack value corruption
-            CSTK.pushFrame();
-            STR.pushFrame();
-            // --
-
-            // Make sure it wasn't already added, then add it.
-            if(currentNewObject->isProperlyAdded() == false)
-            {
-               bool ret = false;
-
-               Message *msg = dynamic_cast<Message *>(currentNewObject);
-               if(msg)
-               {
-                  SimObjectId id = Message::getNextMessageID();
-                  if(id != 0xffffffff)
-                     ret = currentNewObject->registerObject(id);
-                  else
-                     Con::errorf("%s: No more object IDs available for messages", getFileLine(ip));
-               }
-               else
-                  ret = currentNewObject->registerObject();
-
-               if(! ret)
-               {
-                  // This error is usually caused by failing to call Parent::initPersistFields in the class' initPersistFields().
-                  Con::warnf(ConsoleLogEntry::General, "%s: Register object failed for object %s of class %s.", getFileLine(ip), currentNewObject->getName(), currentNewObject->getClassName());
-                  delete currentNewObject;
-                  currentNewObject = NULL;
-                  ip = failJump;
-                  // Prevent stack value corruption
-                  CSTK.popFrame();
-                  STR.popFrame();
-                  // --
-                  break;
-               }
-            }
-
-            // Are we dealing with a datablock?
-            SimDataBlock *dataBlock = dynamic_cast<SimDataBlock *>(currentNewObject);
-            static String errorStr;
-
-
-
-            // If so, preload it.
-            if(dataBlock && !dataBlock->preload(true, errorStr))
-            {
-               Con::errorf(ConsoleLogEntry::General, "%s: preload failed for %s: %s.", getFileLine(ip),
-                           currentNewObject->getName(), errorStr.c_str());
-               dataBlock->deleteObject();
-               currentNewObject = NULL;
-               ip = failJump;
-            
-               // Prevent stack value corruption
-               CSTK.popFrame();
-               STR.popFrame();
-               // --
-               break;
-            }
-
-            // What group will we be added to, if any?
-            U32 groupAddId = intStack[_UINT];
-            SimGroup *grp = NULL;
-            SimSet   *set = NULL;
-            bool isMessage = dynamic_cast<Message *>(currentNewObject) != NULL;
-
-            if(!placeAtRoot || !currentNewObject->getGroup())
-            {
-               if(! isMessage)
-               {
-                  if(! placeAtRoot)
-                  {
-                     // Otherwise just add to the requested group or set.
-                     if(!Sim::findObject(groupAddId, grp))
-                        Sim::findObject(groupAddId, set);
-                  }
-                  
-                  if(placeAtRoot)
-                  {
-                     // Deal with the instantGroup if we're being put at the root or we're adding to a component.
-                     if( Con::gInstantGroup.isEmpty()
-                        || !Sim::findObject( Con::gInstantGroup, grp ) )
-                        grp = Sim::getRootGroup();
-                  }
-               }
-
-               // If we didn't get a group, then make sure we have a pointer to
-               // the rootgroup.
-               if(!grp)
-                  grp = Sim::getRootGroup();
-
-               // add to the parent group
-               grp->addObject(currentNewObject);
-               
-               // If for some reason the add failed, add the object to the
-               // root group so it won't leak.
-               if( !currentNewObject->getGroup() )
-                  Sim::getRootGroup()->addObject( currentNewObject );
-
-               // add to any set we might be in
-               if(set)
-                  set->addObject(currentNewObject);
-            }
-
-            // store the new object's ID on the stack (overwriting the group/set
-            // id, if one was given, otherwise getting pushed)
-            if(placeAtRoot) 
-               intStack[_UINT] = currentNewObject->getId();
-            else
-               intStack[++_UINT] = currentNewObject->getId();
-
-            // Prevent stack value corruption
-            CSTK.popFrame();
-            STR.popFrame();
-            // --
-            break;
-         }
-
-         case OP_END_OBJECT:
-         {
-            // If we're not to be placed at the root, make sure we clean up
-            // our group reference.
-            bool placeAtRoot = code[ip++];
-            if(!placeAtRoot)
-               _UINT--;
-            break;
-         }
-
-         case OP_FINISH_OBJECT:
-         {
-            if (currentNewObject)
-               currentNewObject->onPostAdd();
-
-            //Assert( objectCreationStackIndex >= 0 );
-            // Restore the object info from the stack [7/9/2007 Black]
-            currentNewObject = objectCreationStack[ --objectCreationStackIndex ].newObject;
-            failJump = objectCreationStack[ objectCreationStackIndex ].failJump;
-            break;
-         }
-
-         case OP_JMPIFFNOT:
-            if(floatStack[_FLT--])
-            {
-               ip++;
-               break;
-            }
-            ip = code[ip];
-            break;
-         case OP_JMPIFNOT:
-            if(intStack[_UINT--])
-            {
-               ip++;
-               break;
-            }
-            ip = code[ip];
-            break;
-         case OP_JMPIFF:
-            if(!floatStack[_FLT--])
-            {
-               ip++;
-               break;
-            }
-            ip = code[ip];
-            break;
-         case OP_JMPIF:
-            if(!intStack[_UINT--])
-            {
-               ip ++;
-               break;
-            }
-            ip = code[ip];
-            break;
-         case OP_JMPIFNOT_NP:
-            if(intStack[_UINT])
-            {
-               _UINT--;
-               ip++;
-               break;
-            }
-            ip = code[ip];
-            break;
-         case OP_JMPIF_NP:
-            if(!intStack[_UINT])
-            {
-               _UINT--;
-               ip++;
-               break;
-            }
-            ip = code[ip];
-            break;
-         case OP_JMP:
-            ip = code[ip];
-            break;
-            
-         // This fixes a bug when not explicitly returning a value.
-         case OP_RETURN_VOID:
-            STR.setStringValue("");
-            // We're falling thru here on purpose.
-            
-         case OP_RETURN:
-            retValue = STR.getStringValuePtr();
-
-            if( iterDepth > 0 )
-            {
-               // Clear iterator state.
-               while( iterDepth > 0 )
-               {
-                  iterStack[ -- _ITER ].mIsStringIter = false;
-                  -- iterDepth;
-               }
-
-               STR.rewind();
-               STR.setStringValue( StringStackPtrRef(retValue).getPtr(&STR) ); // Not nice but works.
-               retValue = STR.getStringValuePtr();
-            }
-
-            // Previously the return value was on the stack and would be returned using STR.getStringValue().
-            // Now though we need to wrap it in a ConsoleValueRef 
-            returnValue.value = CSTK.pushStringStackPtr(retValue);
-               
-            goto execFinished;
-
-         case OP_RETURN_FLT:
-         
-            if( iterDepth > 0 )
-            {
-               // Clear iterator state.
-               while( iterDepth > 0 )
-               {
-                  iterStack[ -- _ITER ].mIsStringIter = false;
-                  -- iterDepth;
-               }
-               
-            }
-
-            returnValue.value = CSTK.pushFLT(floatStack[_FLT]);
-            _FLT--;
-               
-            goto execFinished;
-
-         case OP_RETURN_UINT:
-         
-            if( iterDepth > 0 )
-            {
-               // Clear iterator state.
-               while( iterDepth > 0 )
-               {
-                  iterStack[ -- _ITER ].mIsStringIter = false;
-                  -- iterDepth;
-               }
-            }
-
-            returnValue.value = CSTK.pushUINT(intStack[_UINT]);
-            _UINT--;
-               
-            goto execFinished;
-            
-         case OP_CMPEQ:
-            intStack[_UINT+1] = bool(floatStack[_FLT] == floatStack[_FLT-1]);
-            _UINT++;
-            _FLT -= 2;
-            break;
-
-         case OP_CMPGR:
-            intStack[_UINT+1] = bool(floatStack[_FLT] > floatStack[_FLT-1]);
-            _UINT++;
-            _FLT -= 2;
-            break;
-
-         case OP_CMPGE:
-            intStack[_UINT+1] = bool(floatStack[_FLT] >= floatStack[_FLT-1]);
-            _UINT++;
-            _FLT -= 2;
-            break;
-
-         case OP_CMPLT:
-            intStack[_UINT+1] = bool(floatStack[_FLT] < floatStack[_FLT-1]);
-            _UINT++;
-            _FLT -= 2;
-            break;
-
-         case OP_CMPLE:
-            intStack[_UINT+1] = bool(floatStack[_FLT] <= floatStack[_FLT-1]);
-            _UINT++;
-            _FLT -= 2;
-            break;
-
-         case OP_CMPNE:
-            intStack[_UINT+1] = bool(floatStack[_FLT] != floatStack[_FLT-1]);
-            _UINT++;
-            _FLT -= 2;
-            break;
-
-         case OP_XOR:
-            intStack[_UINT-1] = intStack[_UINT] ^ intStack[_UINT-1];
-            _UINT--;
-            break;
-
-         case OP_MOD:
-            if(  intStack[_UINT-1] != 0 )
-               intStack[_UINT-1] = intStack[_UINT] % intStack[_UINT-1];
-            else
-               intStack[_UINT-1] = 0;
-            _UINT--;
-            break;
-
-         case OP_BITAND:
-            intStack[_UINT-1] = intStack[_UINT] & intStack[_UINT-1];
-            _UINT--;
-            break;
-
-         case OP_BITOR:
-            intStack[_UINT-1] = intStack[_UINT] | intStack[_UINT-1];
-            _UINT--;
-            break;
-
-         case OP_NOT:
-            intStack[_UINT] = !intStack[_UINT];
-            break;
-
-         case OP_NOTF:
-            intStack[_UINT+1] = !floatStack[_FLT];
-            _FLT--;
-            _UINT++;
-            break;
-
-         case OP_ONESCOMPLEMENT:
-            intStack[_UINT] = ~intStack[_UINT];
-            break;
-
-         case OP_SHR:
-            intStack[_UINT-1] = intStack[_UINT] >> intStack[_UINT-1];
-            _UINT--;
-            break;
-
-         case OP_SHL:
-            intStack[_UINT-1] = intStack[_UINT] << intStack[_UINT-1];
-            _UINT--;
-            break;
-
-         case OP_AND:
-            intStack[_UINT-1] = intStack[_UINT] && intStack[_UINT-1];
-            _UINT--;
-            break;
-
-         case OP_OR:
-            intStack[_UINT-1] = intStack[_UINT] || intStack[_UINT-1];
-            _UINT--;
-            break;
-
-         case OP_ADD:
-            floatStack[_FLT-1] = floatStack[_FLT] + floatStack[_FLT-1];
-            _FLT--;
-            break;
-
-         case OP_SUB:
-            floatStack[_FLT-1] = floatStack[_FLT] - floatStack[_FLT-1];
-            _FLT--;
-            break;
-
-         case OP_MUL:
-            floatStack[_FLT-1] = floatStack[_FLT] * floatStack[_FLT-1];
-            _FLT--;
-            break;
-         case OP_DIV:
-            floatStack[_FLT-1] = floatStack[_FLT] / floatStack[_FLT-1];
-            _FLT--;
-            break;
-         case OP_NEG:
-            floatStack[_FLT] = -floatStack[_FLT];
-            break;
-
-         case OP_SETCURVAR:
-            var = CodeToSTE(code, ip);
-            ip += 2;
-
-            // If a variable is set, then these must be NULL. It is necessary
-            // to set this here so that the vector parser can appropriately
-            // identify whether it's dealing with a vector.
-            prevField = NULL;
-            prevObject = NULL;
-            curObject = NULL;
-
-            gEvalState.setCurVarName(var);
-
-            // In order to let docblocks work properly with variables, we have
-            // clear the current docblock when we do an assign. This way it 
-            // won't inappropriately carry forward to following function decls.
-            curFNDocBlock = NULL;
-            curNSDocBlock = NULL;
-            break;
-
-         case OP_SETCURVAR_CREATE:
-            var = CodeToSTE(code, ip);
-            ip += 2;
-
-            // See OP_SETCURVAR
-            prevField = NULL;
-            prevObject = NULL;
-            curObject = NULL;
-
-            gEvalState.setCurVarNameCreate(var);
-
-            // See OP_SETCURVAR for why we do this.
-            curFNDocBlock = NULL;
-            curNSDocBlock = NULL;
-            break;
-
-         case OP_SETCURVAR_ARRAY:
-            var = STR.getSTValue();
-
-            // See OP_SETCURVAR
-            prevField = NULL;
-            prevObject = NULL;
-            curObject = NULL;
-
-            gEvalState.setCurVarName(var);
-
-            // See OP_SETCURVAR for why we do this.
-            curFNDocBlock = NULL;
-            curNSDocBlock = NULL;
-            break;
-
-         case OP_SETCURVAR_ARRAY_CREATE:
-            var = STR.getSTValue();
-
-            // See OP_SETCURVAR
-            prevField = NULL;
-            prevObject = NULL;
-            curObject = NULL;
-
-            gEvalState.setCurVarNameCreate(var);
-
-            // See OP_SETCURVAR for why we do this.
-            curFNDocBlock = NULL;
-            curNSDocBlock = NULL;
-            break;
-
-         case OP_LOADVAR_UINT:
-            intStack[_UINT+1] = gEvalState.getIntVariable();
-            _UINT++;
-            break;
-
-         case OP_LOADVAR_FLT:
-            floatStack[_FLT+1] = gEvalState.getFloatVariable();
-            _FLT++;
-            break;
-
-         case OP_LOADVAR_STR:
-            val = gEvalState.getStringVariable();
-            STR.setStringValue(val);
-            break;
-
-         case OP_LOADVAR_VAR:
-            // Sets current source of OP_SAVEVAR_VAR
-            gEvalState.copyVariable = gEvalState.currentVariable;
-            break;
-
-         case OP_SAVEVAR_UINT:
-            gEvalState.setIntVariable(intStack[_UINT]);
-            break;
-
-         case OP_SAVEVAR_FLT:
-            gEvalState.setFloatVariable(floatStack[_FLT]);
-            break;
-
-         case OP_SAVEVAR_STR:
-            gEvalState.setStringVariable(STR.getStringValue());
-            break;
-          
-         case OP_SAVEVAR_VAR:
-            // this basically handles %var1 = %var2
-            gEvalState.setCopyVariable();
-            break;
-
-         case OP_SETCUROBJECT:
-            // Save the previous object for parsing vector fields.
-            prevObject = curObject;
-            val = STR.getStringValue();
-
-            // Sim::findObject will sometimes find valid objects from
-            // multi-component strings. This makes sure that doesn't
-            // happen.
-            for( const char* check = val; *check; check++ )
-            {
-               if( *check == ' ' )
-               {
-                  val = "";
-                  break;
-               }
-            }
-            curObject = Sim::findObject(val);
-            break;
-
-         case OP_SETCUROBJECT_INTERNAL:
-            ++ip; // To skip the recurse flag if the object wasn't found
-            if(curObject)
-            {
-               SimSet *set = dynamic_cast<SimSet *>(curObject);
-               if(set)
-               {
-                  StringTableEntry intName = StringTable->insert(STR.getStringValue());
-                  bool recurse = code[ip-1];
-                  SimObject *obj = set->findObjectByInternalName(intName, recurse);
-                  intStack[_UINT+1] = obj ? obj->getId() : 0;
-                  _UINT++;
-               }
-               else
-               {
-                  Con::errorf(ConsoleLogEntry::Script, "%s: Attempt to use -> on non-set %s of class %s.", getFileLine(ip-2), curObject->getName(), curObject->getClassName());
-                  intStack[_UINT] = 0;
-               }
-            }
-            break;
-
-         case OP_SETCUROBJECT_NEW:
-            curObject = currentNewObject;
-            break;
-
-         case OP_SETCURFIELD:
-            // Save the previous field for parsing vector fields.
-            prevField = curField;
-            dStrcpy( prevFieldArray, curFieldArray );
-            curField = CodeToSTE(code, ip);
-            curFieldArray[0] = 0;
-            ip += 2;
-            break;
-
-         case OP_SETCURFIELD_ARRAY:
-            dStrcpy(curFieldArray, STR.getStringValue());
-            break;
-
-         case OP_SETCURFIELD_TYPE:
-            if(curObject)
-               curObject->setDataFieldType(code[ip], curField, curFieldArray);
-            ip++;
-            break;
-
-         case OP_LOADFIELD_UINT:
-            if(curObject)
-               intStack[_UINT+1] = U32(dAtoi(curObject->getDataField(curField, curFieldArray)));
-            else
-            {
-               // The field is not being retrieved from an object. Maybe it's
-               // a special accessor?
-               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer );
-               intStack[_UINT+1] = dAtoi( valBuffer );
-            }
-            _UINT++;
-            break;
-
-         case OP_LOADFIELD_FLT:
-            if(curObject)
-               floatStack[_FLT+1] = dAtof(curObject->getDataField(curField, curFieldArray));
-            else
-            {
-               // The field is not being retrieved from an object. Maybe it's
-               // a special accessor?
-               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer );
-               floatStack[_FLT+1] = dAtof( valBuffer );
-            }
-            _FLT++;
-            break;
-
-         case OP_LOADFIELD_STR:
-            if(curObject)
-            {
-               val = curObject->getDataField(curField, curFieldArray);
-               STR.setStringValue( val );
-            }
-            else
-            {
-               // The field is not being retrieved from an object. Maybe it's
-               // a special accessor?
-               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer );
-               STR.setStringValue( valBuffer );
-            }
-            break;
-
-         case OP_SAVEFIELD_UINT:
-            STR.setIntValue(intStack[_UINT]);
-            if(curObject)
-               curObject->setDataField(curField, curFieldArray, STR.getStringValue());
-            else
-            {
-               // The field is not being set on an object. Maybe it's
-               // a special accessor?
-               setFieldComponent( prevObject, prevField, prevFieldArray, curField );
-               prevObject = NULL;
-            }
-            break;
-
-         case OP_SAVEFIELD_FLT:
-            STR.setFloatValue(floatStack[_FLT]);
-            if(curObject)
-               curObject->setDataField(curField, curFieldArray, STR.getStringValue());
-            else
-            {
-               // The field is not being set on an object. Maybe it's
-               // a special accessor?
-               setFieldComponent( prevObject, prevField, prevFieldArray, curField );
-               prevObject = NULL;
-            }
-            break;
-
-         case OP_SAVEFIELD_STR:
-            if(curObject)
-               curObject->setDataField(curField, curFieldArray, STR.getStringValue());
-            else
-            {
-               // The field is not being set on an object. Maybe it's
-               // a special accessor?
-               setFieldComponent( prevObject, prevField, prevFieldArray, curField );
-               prevObject = NULL;
-            }
-            break;
-
-         case OP_STR_TO_UINT:
-            intStack[_UINT+1] = STR.getIntValue();
-            _UINT++;
-            break;
-
-         case OP_STR_TO_FLT:
-            floatStack[_FLT+1] = STR.getFloatValue();
-            _FLT++;
-            break;
-
-         case OP_STR_TO_NONE:
-            // This exists simply to deal with certain typecast situations.
-            break;
-
-         case OP_FLT_TO_UINT:
-            intStack[_UINT+1] = (S64)floatStack[_FLT];
-            _FLT--;
-            _UINT++;
-            break;
-
-         case OP_FLT_TO_STR:
-            STR.setFloatValue(floatStack[_FLT]);
-            _FLT--;
-            break;
-
-         case OP_FLT_TO_NONE:
-            _FLT--;
-            break;
-
-         case OP_UINT_TO_FLT:
-            floatStack[_FLT+1] = (F32)intStack[_UINT];
-            _UINT--;
-            _FLT++;
-            break;
-
-         case OP_UINT_TO_STR:
-            STR.setIntValue(intStack[_UINT]);
-            _UINT--;
-            break;
-
-         case OP_UINT_TO_NONE:
-            _UINT--;
-            break;
-
-         case OP_COPYVAR_TO_NONE:
-            gEvalState.copyVariable = NULL;
-            break;
-
-         case OP_LOADIMMED_UINT:
-            intStack[_UINT+1] = code[ip++];
-            _UINT++;
-            break;
-
-         case OP_LOADIMMED_FLT:
-            floatStack[_FLT+1] = curFloatTable[code[ip]];
-            ip++;
-            _FLT++;
-            break;
-            
-         case OP_TAG_TO_STR:
-            code[ip-1] = OP_LOADIMMED_STR;
-            // it's possible the string has already been converted
-            if(U8(curStringTable[code[ip]]) != StringTagPrefixByte)
-            {
-               U32 id = GameAddTaggedString(curStringTable + code[ip]);
-               dSprintf(curStringTable + code[ip] + 1, 7, "%d", id);
-               *(curStringTable + code[ip]) = StringTagPrefixByte;
-            }
-         case OP_LOADIMMED_STR:
-            STR.setStringValue(curStringTable + code[ip++]);
-            break;
-
-         case OP_DOCBLOCK_STR:
-            {
-               // If the first word of the doc is '\class' or '@class', then this
-               // is a namespace doc block, otherwise it is a function doc block.
-               const char* docblock = curStringTable + code[ip++];
-
-               const char* sansClass = dStrstr( docblock, "@class" );
-               if( !sansClass )
-                  sansClass = dStrstr( docblock, "\\class" );
-
-               if( sansClass )
-               {
-                  // Don't save the class declaration. Scan past the 'class'
-                  // keyword and up to the first whitespace.
-                  sansClass += 7;
-                  S32 index = 0;
-                  while( ( *sansClass != ' ' ) && ( *sansClass != '\n' ) && *sansClass && ( index < ( nsDocLength - 1 ) ) )
-                  {
-                     nsDocBlockClass[index++] = *sansClass;
-                     sansClass++;
-                  }
-                  nsDocBlockClass[index] = '\0';
-
-                  curNSDocBlock = sansClass + 1;
-               }
-               else
-                  curFNDocBlock = docblock;
-            }
-
-            break;
-
-         case OP_LOADIMMED_IDENT:
-            STR.setStringValue(CodeToSTE(code, ip));
-            ip += 2;
-            break;
-
-         case OP_CALLFUNC_RESOLVE:
-            // This deals with a function that is potentially living in a namespace.
-            fnNamespace = CodeToSTE(code, ip+2);
-            fnName      = CodeToSTE(code, ip);
-
-            // Try to look it up.
-            ns = Namespace::find(fnNamespace);
-            nsEntry = ns->lookup(fnName);
-            if(!nsEntry)
-            {
-               ip+= 5;
-               Con::warnf(ConsoleLogEntry::General,
-                  "%s: Unable to find function %s%s%s",
-                  getFileLine(ip-7), fnNamespace ? fnNamespace : "",
-                  fnNamespace ? "::" : "", fnName);
-               STR.popFrame();
-               CSTK.popFrame();
-               break;
-            }
-            
-#ifdef COMPILER_OPTIMIZE_FUNCTION_CALLS
-            // Now fall through to OP_CALLFUNC...
-            // Now, rewrite our code a bit (ie, avoid future lookups) and fall
-            // through to OP_CALLFUNC
-#ifdef TORQUE_CPU_X64
-            *((U64*)(code+ip+2)) = ((U64)nsEntry);
-#else
-            code[ip+2] = ((U32)nsEntry);
-#endif
-            code[ip-1] = OP_CALLFUNC;
-#endif
-
-         case OP_CALLFUNC:
-         {
-            // This routingId is set when we query the object as to whether
-            // it handles this method.  It is set to an enum from the table
-            // above indicating whether it handles it on a component it owns
-            // or just on the object.
-            S32 routingId = 0;
-
-            fnName = CodeToSTE(code, ip);
-
-            //if this is called from inside a function, append the ip and codeptr
-            if( gEvalState.getStackDepth() > 0 )
-            {
-               gEvalState.getCurrentFrame().code = this;
-               gEvalState.getCurrentFrame().ip = ip - 1;
-            }
-
-            U32 callType = code[ip+4];
-
-            ip += 5;
-            CSTK.getArgcArgv(fnName, &callArgc, &callArgv);
-
-            const char *componentReturnValue = "";
-
-            if(callType == FuncCallExprNode::FunctionCall) 
-            {
-               if( !nsEntry )
-               {
-#ifdef COMPILER_OPTIMIZE_FUNCTION_CALLS
-#ifdef TORQUE_CPU_X64
-                  nsEntry = ((Namespace::Entry *) *((U64*)(code+ip-3)));
-#else
-                  nsEntry = ((Namespace::Entry *) *(code+ip-3));
-#endif
-#else
-                  nsEntry = Namespace::global()->lookup( fnName );
-#endif
-                  ns = NULL;
-               }
-               ns = NULL;
-            }
-            else if(callType == FuncCallExprNode::MethodCall)
-            {
-               saveObject = gEvalState.thisObject;
-               gEvalState.thisObject = Sim::findObject((const char*)callArgv[1]);
-               if(!gEvalState.thisObject)
-               {
-                  // Go back to the previous saved object.
-                  gEvalState.thisObject = saveObject;
-
-                  Con::warnf(ConsoleLogEntry::General,"%s: Unable to find object: '%s' attempting to call function '%s'", getFileLine(ip-4), (const char*)callArgv[1], fnName);
-                  STR.popFrame();
-                  CSTK.popFrame();
-                  STR.setStringValue("");
-                  break;
-               }
-               
-               bool handlesMethod = gEvalState.thisObject->handlesConsoleMethod(fnName,&routingId);
-               if( handlesMethod && routingId == MethodOnComponent )
-               {
-                  ICallMethod *pComponent = dynamic_cast<ICallMethod *>( gEvalState.thisObject );
-                  if( pComponent )
-                     componentReturnValue = pComponent->callMethodArgList( callArgc, callArgv, false );
-               }
-               
-               ns = gEvalState.thisObject->getNamespace();
-               if(ns)
-                  nsEntry = ns->lookup(fnName);
-               else
-                  nsEntry = NULL;
-            }
-            else // it's a ParentCall
-            {
-               if(thisNamespace)
-               {
-                  ns = thisNamespace->mParent;
-                  if(ns)
-                     nsEntry = ns->lookup(fnName);
-                  else
-                     nsEntry = NULL;
-               }
-               else
-               {
-                  ns = NULL;
-                  nsEntry = NULL;
-               }
-            }
-
-            Namespace::Entry::CallbackUnion * nsCb = NULL;
-            const char * nsUsage = NULL;
-            if (nsEntry)
-            {
-               nsCb = &nsEntry->cb;
-               nsUsage = nsEntry->mUsage;
-               routingId = 0;
-            }
-            if(!nsEntry || noCalls)
-            {
-               if(!noCalls && !( routingId == MethodOnComponent ) )
-               {
-                  Con::warnf(ConsoleLogEntry::General,"%s: Unknown command %s.", getFileLine(ip-6), fnName);
-                  if(callType == FuncCallExprNode::MethodCall)
-                  {
-                     Con::warnf(ConsoleLogEntry::General, "  Object %s(%d) %s",
-                           gEvalState.thisObject->getName() ? gEvalState.thisObject->getName() : "",
-                           gEvalState.thisObject->getId(), Con::getNamespaceList(ns) );
-                  }
-               }
-               STR.popFrame();
-               CSTK.popFrame();
-
-               if( routingId == MethodOnComponent )
-                  STR.setStringValue( componentReturnValue );
-               else
-                  STR.setStringValue( "" );
-
-               break;
-            }
-            if(nsEntry->mType == Namespace::Entry::ConsoleFunctionType)
-            {
-               ConsoleValueRef ret;
-               if(nsEntry->mFunctionOffset)
-                  ret = nsEntry->mCode->exec(nsEntry->mFunctionOffset, fnName, nsEntry->mNamespace, callArgc, callArgv, false, nsEntry->mPackage);
-
-               STR.popFrame();
-               // Functions are assumed to return strings, so look ahead to see if we can skip the conversion
-               if(code[ip] == OP_STR_TO_UINT)
-               {
-                  ip++;
-                  intStack[++_UINT] = (U32)((S32)ret);
-               }
-               else if(code[ip] == OP_STR_TO_FLT)
-               {
-                  ip++;
-                  floatStack[++_FLT] = (F32)ret;
-               }
-               else if(code[ip] == OP_STR_TO_NONE)
-               {
-                  STR.setStringValue(ret.getStringValue());
-                  ip++;
-               }
-               else
-                  STR.setStringValue((const char*)ret);
-
-               // This will clear everything including returnValue
-               CSTK.popFrame();
-               //STR.clearFunctionOffset();
-            }
-            else
-            {
-               const char* nsName = ns? ns->mName: "";
-#ifndef TORQUE_DEBUG
-               // [tom, 12/13/2006] This stops tools functions from working in the console,
-               // which is useful behavior when debugging so I'm ifdefing this out for debug builds.
-               if(nsEntry->mToolOnly && ! Con::isCurrentScriptToolScript())
-               {
-                  Con::errorf(ConsoleLogEntry::Script, "%s: %s::%s - attempting to call tools only function from outside of tools.", getFileLine(ip-6), nsName, fnName);
-               }
-               else
-#endif
-               if((nsEntry->mMinArgs && S32(callArgc) < nsEntry->mMinArgs) || (nsEntry->mMaxArgs && S32(callArgc) > nsEntry->mMaxArgs))
-               {
-                  Con::warnf(ConsoleLogEntry::Script, "%s: %s::%s - wrong number of arguments (got %i, expected min %i and max %i).",
-                     getFileLine(ip-6), nsName, fnName,
-                     callArgc, nsEntry->mMinArgs, nsEntry->mMaxArgs);
-                  Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", getFileLine(ip-6), nsEntry->mUsage);
-                  STR.popFrame();
-                  CSTK.popFrame();
-               }
-               else
-               {
-                  switch(nsEntry->mType)
-                  {
-                     case Namespace::Entry::StringCallbackType:
-                     {
-                        const char *ret = nsEntry->cb.mStringCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
-                        STR.popFrame();
-                        CSTK.popFrame();
-                        if(ret != STR.getStringValue())
-                           STR.setStringValue(ret);
-                        //else
-                        //   STR.setLen(dStrlen(ret));
-                        break;
-                     }
-                     case Namespace::Entry::IntCallbackType:
-                     {
-                        S32 result = nsEntry->cb.mIntCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
-                        STR.popFrame();
-                        CSTK.popFrame();
-                        if(code[ip] == OP_STR_TO_UINT)
-                        {
-                           ip++;
-                           intStack[++_UINT] = result;
-                           break;
-                        }
-                        else if(code[ip] == OP_STR_TO_FLT)
-                        {
-                           ip++;
-                           floatStack[++_FLT] = result;
-                           break;
-                        }
-                        else if(code[ip] == OP_STR_TO_NONE)
-                           ip++;
-                        else
-                           STR.setIntValue(result);
-                        break;
-                     }
-                     case Namespace::Entry::FloatCallbackType:
-                     {
-                        F64 result = nsEntry->cb.mFloatCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
-                        STR.popFrame();
-                        CSTK.popFrame();
-                        if(code[ip] == OP_STR_TO_UINT)
-                        {
-                           ip++;
-                           intStack[++_UINT] = (S64)result;
-                           break;
-                        }
-                        else if(code[ip] == OP_STR_TO_FLT)
-                        {
-                           ip++;
-                           floatStack[++_FLT] = result;
-                           break;
-                        }
-                        else if(code[ip] == OP_STR_TO_NONE)
-                           ip++;
-                        else
-                           STR.setFloatValue(result);
-                        break;
-                     }
-                     case Namespace::Entry::VoidCallbackType:
-                        nsEntry->cb.mVoidCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
-                        if( code[ ip ] != OP_STR_TO_NONE && Con::getBoolVariable( "$Con::warnVoidAssignment", true ) )
-                           Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", getFileLine(ip-6), fnName, functionName);
-                        
-                        STR.popFrame();
-                        CSTK.popFrame();
-                        STR.setStringValue("");
-                        break;
-                     case Namespace::Entry::BoolCallbackType:
-                     {
-                        bool result = nsEntry->cb.mBoolCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
-                        STR.popFrame();
-                        CSTK.popFrame();
-                        if(code[ip] == OP_STR_TO_UINT)
-                        {
-                           ip++;
-                           intStack[++_UINT] = result;
-                           break;
-                        }
-                        else if(code[ip] == OP_STR_TO_FLT)
-                        {
-                           ip++;
-                           floatStack[++_FLT] = result;
-                           break;
-                        }
-                        else if(code[ip] == OP_STR_TO_NONE)
-                           ip++;
-                        else
-                           STR.setIntValue(result);
-                        break;
-                     }
-                  }
-               }
-            }
-
-            if(callType == FuncCallExprNode::MethodCall)
-               gEvalState.thisObject = saveObject;
-            break;
-         }
-         case OP_ADVANCE_STR:
-            STR.advance();
-            break;
-         case OP_ADVANCE_STR_APPENDCHAR:
-            STR.advanceChar(code[ip++]);
-            break;
-
-         case OP_ADVANCE_STR_COMMA:
-            STR.advanceChar('_');
-            break;
-
-         case OP_ADVANCE_STR_NUL:
-            STR.advanceChar(0);
-            break;
-
-         case OP_REWIND_STR:
-            STR.rewind();
-            break;
-
-         case OP_TERMINATE_REWIND_STR:
-            STR.rewindTerminate();
-            break;
-
-         case OP_COMPARE_STR:
-            intStack[++_UINT] = STR.compare();
-            break;
-         case OP_PUSH:
-            STR.push();
-            CSTK.pushStringStackPtr(STR.getPreviousStringValuePtr());
-            break;
-         case OP_PUSH_UINT:
-            CSTK.pushUINT(intStack[_UINT]);
-            _UINT--;
-            break;
-         case OP_PUSH_FLT:
-            CSTK.pushFLT(floatStack[_FLT]);
-            _FLT--;
-            break;
-         case OP_PUSH_VAR:
-            if (gEvalState.currentVariable)
-               CSTK.pushValue(gEvalState.currentVariable->value);
-            else
-               CSTK.pushString("");
-            break;
-
-         case OP_PUSH_FRAME:
-            STR.pushFrame();
-            CSTK.pushFrame();
-            break;
-
-         case OP_ASSERT:
-         {
-            if( !intStack[_UINT--] )
-            {
-               const char *message = curStringTable + code[ip];
-
-               U32 breakLine, inst;
-               findBreakLine( ip - 1, breakLine, inst );
-
-               if ( PlatformAssert::processAssert( PlatformAssert::Fatal, 
-                                                   name ? name : "eval", 
-                                                   breakLine,  
-                                                   message ) )
-               {
-                  if ( TelDebugger && TelDebugger->isConnected() && breakLine > 0 )
-                  {
-                     TelDebugger->breakProcess();
-                  }
-                  else
-                     Platform::debugBreak();
-               }
-            }
-
-            ip++;
-            break;
-         }
-
-         case OP_BREAK:
-         {
-            //append the ip and codeptr before managing the breakpoint!
-            AssertFatal( gEvalState.getStackDepth() > 0, "Empty eval stack on break!");
-            gEvalState.getCurrentFrame().code = this;
-            gEvalState.getCurrentFrame().ip = ip - 1;
-
-            U32 breakLine;
-            findBreakLine(ip-1, breakLine, instruction);
-            if(!breakLine)
-               goto breakContinue;
-            TelDebugger->executionStopped(this, breakLine);
-            goto breakContinue;
-         }
-         
-         case OP_ITER_BEGIN_STR:
-         {
-            iterStack[ _ITER ].mIsStringIter = true;
-            /* fallthrough */
-         }
-         
-         case OP_ITER_BEGIN:
-         {
-            StringTableEntry varName = CodeToSTE(code, ip);
-            U32 failIp = code[ ip + 2 ];
-            
-            IterStackRecord& iter = iterStack[ _ITER ];
-            
-            iter.mVariable = gEvalState.getCurrentFrame().add( varName );
-            
-            if( iter.mIsStringIter )
-            {
-               iter.mData.mStr.mString = STR.getStringValuePtr();
-               iter.mData.mStr.mIndex = 0;
-            }
-            else
-            {
-               // Look up the object.
-               
-               SimSet* set;
-               if( !Sim::findObject( STR.getStringValue(), set ) )
-               {
-                  Con::errorf( ConsoleLogEntry::General, "No SimSet object '%s'", STR.getStringValue() );
-                  Con::errorf( ConsoleLogEntry::General, "Did you mean to use 'foreach$' instead of 'foreach'?" );
-                  ip = failIp;
-                  continue;
-               }
-               
-               // Set up.
-               
-               iter.mData.mObj.mSet = set;
-               iter.mData.mObj.mIndex = 0;
-            }
-            
-            _ITER ++;
-            iterDepth ++;
-            
-            STR.push();
-            
-            ip += 3;
-            break;
-         }
-         
-         case OP_ITER:
-         {
-            U32 breakIp = code[ ip ];
-            IterStackRecord& iter = iterStack[ _ITER - 1 ];
-            
-            if( iter.mIsStringIter )
-            {
-               const char* str = StringStackPtrRef(iter.mData.mStr.mString).getPtr(&STR);
-                              
-               U32 startIndex = iter.mData.mStr.mIndex;
-               U32 endIndex = startIndex;
-               
-               // Break if at end.
-
-               if( !str[ startIndex ] )
-               {
-                  ip = breakIp;
-                  continue;
-               }
-
-               // Find right end of current component.
-               
-               if( !dIsspace( str[ endIndex ] ) )
-                  do ++ endIndex;
-                  while( str[ endIndex ] && !dIsspace( str[ endIndex ] ) );
-                  
-               // Extract component.
-                  
-               if( endIndex != startIndex )
-               {
-                  char savedChar = str[ endIndex ];
-                  const_cast< char* >( str )[ endIndex ] = '\0'; // We are on the string stack so this is okay.
-                  iter.mVariable->setStringValue( &str[ startIndex ] );
-                  const_cast< char* >( str )[ endIndex ] = savedChar;                  
-               }
-               else
-                  iter.mVariable->setStringValue( "" );
-
-               // Skip separator.
-               if( str[ endIndex ] != '\0' )
-                  ++ endIndex;
-               
-               iter.mData.mStr.mIndex = endIndex;
-            }
-            else
-            {
-               U32 index = iter.mData.mObj.mIndex;
-               SimSet* set = iter.mData.mObj.mSet;
-               
-               if( index >= set->size() )
-               {
-                  ip = breakIp;
-                  continue;
-               }
-               
-               iter.mVariable->setIntValue( set->at( index )->getId() );
-               iter.mData.mObj.mIndex = index + 1;
-            }
-            
-            ++ ip;
-            break;
-         }
-         
-         case OP_ITER_END:
-         {
-            -- _ITER;
-            -- iterDepth;
-            
-            STR.rewind();
-            
-            iterStack[ _ITER ].mIsStringIter = false;
-            break;
-         }
-         
-         case OP_INVALID:
-
-         default:
-            // error!
-            goto execFinished;
-      }
-   }
-execFinished:
-
-   if ( telDebuggerOn && setFrame < 0 )
-      TelDebugger->popStackFrame();
-
-   if ( popFrame )
-      gEvalState.popFrame();
-
-   if(argv)
-   {
-      if(gEvalState.traceOn)
-      {
-         traceBuffer[0] = 0;
-         dStrcat(traceBuffer, "Leaving ");
-
-         if(packageName)
-         {
-            dStrcat(traceBuffer, "[");
-            dStrcat(traceBuffer, packageName);
-            dStrcat(traceBuffer, "]");
-         }
-         if(thisNamespace && thisNamespace->mName)
-         {
-            dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
-               "%s::%s() - return %s", thisNamespace->mName, thisFunctionName, STR.getStringValue());
-         }
-         else
-         {
-            dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
-               "%s() - return %s", thisFunctionName, STR.getStringValue());
-         }
-         Con::printf("%s", traceBuffer);
-      }
-   }
-
-   smCurrentCodeBlock = saveCodeBlock;
-   if(saveCodeBlock && saveCodeBlock->name)
-   {
-      Con::gCurrentFile = saveCodeBlock->name;
-      Con::gCurrentRoot = saveCodeBlock->modPath;
-   }
-
-   decRefCount();
-
-#ifdef TORQUE_VALIDATE_STACK
-   AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec");
-   AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec");
-#endif
-
-   return returnValue;
+   CodeInterpreter interpreter(this);
+   return interpreter.exec(ip, functionName, thisNamespace, argc, argv, noCalls, packageName, setFrame);
 }
 
 //------------------------------------------------------------

+ 69 - 64
Engine/source/console/compiler.cpp

@@ -40,13 +40,13 @@ namespace Compiler
    F64 consoleStringToNumber(const char *str, StringTableEntry file, U32 line)
    {
       F64 val = dAtof(str);
-      if(val != 0)
+      if (val != 0)
          return val;
-      else if(!dStricmp(str, "true"))
+      else if (!dStricmp(str, "true"))
          return 1;
-      else if(!dStricmp(str, "false"))
+      else if (!dStricmp(str, "false"))
          return 0;
-      else if(file)
+      else if (file)
       {
          Con::warnf(ConsoleLogEntry::General, "%s (%d): string always evaluates to 0.", file, line);
          return 0;
@@ -57,7 +57,7 @@ namespace Compiler
    //------------------------------------------------------------
 
    CompilerStringTable *gCurrentStringTable, gGlobalStringTable, gFunctionStringTable;
-   CompilerFloatTable  *gCurrentFloatTable,  gGlobalFloatTable,  gFunctionFloatTable;
+   CompilerFloatTable  *gCurrentFloatTable, gGlobalFloatTable, gFunctionFloatTable;
    DataChunker          gConsoleAllocator;
    CompilerIdentTable   gIdentTable;
 
@@ -71,16 +71,16 @@ namespace Compiler
       *ptr = (U32)ste;
 #endif
    }
-   
+
    void compileSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr)
    {
-      if(ste)
+      if (ste)
          getIdentTable().add(ste, ip);
       *ptr = 0;
-      *(ptr+1) = 0;
+      *(ptr + 1) = 0;
    }
-   
-   void (*STEtoCode)(StringTableEntry ste, U32 ip, U32 *ptr) = evalSTEtoCode;
+
+   void(*STEtoCode)(StringTableEntry ste, U32 ip, U32 *ptr) = evalSTEtoCode;
 
    //------------------------------------------------------------
 
@@ -88,23 +88,23 @@ namespace Compiler
 
    //------------------------------------------------------------
 
-   CompilerStringTable *getCurrentStringTable()  { return gCurrentStringTable;  }
-   CompilerStringTable &getGlobalStringTable()   { return gGlobalStringTable;   }
+   CompilerStringTable *getCurrentStringTable() { return gCurrentStringTable; }
+   CompilerStringTable &getGlobalStringTable() { return gGlobalStringTable; }
    CompilerStringTable &getFunctionStringTable() { return gFunctionStringTable; }
 
-   void setCurrentStringTable (CompilerStringTable* cst) { gCurrentStringTable  = cst; }
+   void setCurrentStringTable(CompilerStringTable* cst) { gCurrentStringTable = cst; }
 
-   CompilerFloatTable *getCurrentFloatTable()    { return gCurrentFloatTable;   }
-   CompilerFloatTable &getGlobalFloatTable()     { return gGlobalFloatTable;    }
-   CompilerFloatTable &getFunctionFloatTable()   { return gFunctionFloatTable; }
+   CompilerFloatTable *getCurrentFloatTable() { return gCurrentFloatTable; }
+   CompilerFloatTable &getGlobalFloatTable() { return gGlobalFloatTable; }
+   CompilerFloatTable &getFunctionFloatTable() { return gFunctionFloatTable; }
 
-   void setCurrentFloatTable (CompilerFloatTable* cst) { gCurrentFloatTable  = cst; }
+   void setCurrentFloatTable(CompilerFloatTable* cst) { gCurrentFloatTable = cst; }
 
    CompilerIdentTable &getIdentTable() { return gIdentTable; }
 
    void precompileIdent(StringTableEntry ident)
    {
-      if(ident)
+      if (ident)
          gGlobalStringTable.add(ident);
    }
 
@@ -119,8 +119,8 @@ namespace Compiler
       getIdentTable().reset();
    }
 
-   void *consoleAlloc(U32 size) { return gConsoleAllocator.alloc(size);  }
-   void consoleAllocReset()     { gConsoleAllocator.freeBlocks(); }
+   void *consoleAlloc(U32 size) { return gConsoleAllocator.alloc(size); }
+   void consoleAllocReset() { gConsoleAllocator.freeBlocks(); }
 
 }
 
@@ -135,36 +135,40 @@ U32 CompilerStringTable::add(const char *str, bool caseSens, bool tag)
 {
    // Is it already in?
    Entry **walk;
-   for(walk = &list; *walk; walk = &((*walk)->next))
+   for (walk = &list; *walk; walk = &((*walk)->next))
    {
-      if((*walk)->tag != tag)
+      if ((*walk)->tag != tag)
          continue;
 
-      if(caseSens)
+      if (caseSens)
       {
-         if(!dStrcmp((*walk)->string, str))
+         if (!dStrcmp((*walk)->string, str))
             return (*walk)->start;
       }
       else
       {
-         if(!dStricmp((*walk)->string, str))
+         if (!dStricmp((*walk)->string, str))
             return (*walk)->start;
       }
    }
 
    // Write it out.
-   Entry *newStr = (Entry *) consoleAlloc(sizeof(Entry));
+   Entry *newStr = (Entry *)consoleAlloc(sizeof(Entry));
    *walk = newStr;
    newStr->next = NULL;
    newStr->start = totalLen;
    U32 len = dStrlen(str) + 1;
-   if(tag && len < 7) // alloc space for the numeric tag 1 for tag, 5 for # and 1 for nul
+   if (tag && len < 7) // alloc space for the numeric tag 1 for tag, 5 for # and 1 for nul
       len = 7;
    totalLen += len;
-   newStr->string = (char *) consoleAlloc(len);
+   newStr->string = (char *)consoleAlloc(len);
    newStr->len = len;
    newStr->tag = tag;
    dStrcpy(newStr->string, str);
+
+   // Put into the hash table.
+   hashTable[str] = newStr;
+
    return newStr->start;
 }
 
@@ -189,7 +193,8 @@ void CompilerStringTable::reset()
 char *CompilerStringTable::build()
 {
    char *ret = new char[totalLen];
-   for(Entry *walk = list; walk; walk = walk->next)
+   dMemset(ret, 0, totalLen);
+   for (Entry *walk = list; walk; walk = walk->next)
       dStrcpy(ret + walk->start, walk->string);
    return ret;
 }
@@ -197,7 +202,7 @@ char *CompilerStringTable::build()
 void CompilerStringTable::write(Stream &st)
 {
    st.write(totalLen);
-   for(Entry *walk = list; walk; walk = walk->next)
+   for (Entry *walk = list; walk; walk = walk->next)
       st.write(walk->len, walk->string);
 }
 
@@ -207,15 +212,15 @@ U32 CompilerFloatTable::add(F64 value)
 {
    Entry **walk;
    U32 i = 0;
-   for(walk = &list; *walk; walk = &((*walk)->next), i++)
-      if(value == (*walk)->val)
+   for (walk = &list; *walk; walk = &((*walk)->next), i++)
+      if (value == (*walk)->val)
          return i;
-   Entry *newFloat = (Entry *) consoleAlloc(sizeof(Entry));
+   Entry *newFloat = (Entry *)consoleAlloc(sizeof(Entry));
    newFloat->val = value;
    newFloat->next = NULL;
    count++;
    *walk = newFloat;
-   return count-1;
+   return count - 1;
 }
 void CompilerFloatTable::reset()
 {
@@ -226,7 +231,7 @@ F64 *CompilerFloatTable::build()
 {
    F64 *ret = new F64[count];
    U32 i = 0;
-   for(Entry *walk = list; walk; walk = walk->next, i++)
+   for (Entry *walk = list; walk; walk = walk->next, i++)
       ret[i] = walk->val;
    return ret;
 }
@@ -234,7 +239,7 @@ F64 *CompilerFloatTable::build()
 void CompilerFloatTable::write(Stream &st)
 {
    st.write(count);
-   for(Entry *walk = list; walk; walk = walk->next)
+   for (Entry *walk = list; walk; walk = walk->next)
       st.write(walk->val);
 }
 
@@ -248,12 +253,12 @@ void CompilerIdentTable::reset()
 void CompilerIdentTable::add(StringTableEntry ste, U32 ip)
 {
    U32 index = gGlobalStringTable.add(ste, false);
-   Entry *newEntry = (Entry *) consoleAlloc(sizeof(Entry));
+   Entry *newEntry = (Entry *)consoleAlloc(sizeof(Entry));
    newEntry->offset = index;
    newEntry->ip = ip;
-   for(Entry *walk = list; walk; walk = walk->next)
+   for (Entry *walk = list; walk; walk = walk->next)
    {
-      if(walk->offset == index)
+      if (walk->offset == index)
       {
          newEntry->nextIdent = walk->nextIdent;
          walk->nextIdent = newEntry;
@@ -269,24 +274,24 @@ void CompilerIdentTable::write(Stream &st)
 {
    U32 count = 0;
    Entry * walk;
-   for(walk = list; walk; walk = walk->next)
+   for (walk = list; walk; walk = walk->next)
       count++;
    st.write(count);
-   for(walk = list; walk; walk = walk->next)
+   for (walk = list; walk; walk = walk->next)
    {
       U32 ec = 0;
       Entry * el;
-      for(el = walk; el; el = el->nextIdent)
+      for (el = walk; el; el = el->nextIdent)
          ec++;
       st.write(walk->offset);
       st.write(ec);
-      for(el = walk; el; el = el->nextIdent)
+      for (el = walk; el; el = el->nextIdent)
          st.write(el->ip);
    }
 }
 
 //-------------------------------------------------------------------------
-  
+
 U8 *CodeStream::allocCode(U32 sz)
 {
    U8 *ptr = NULL;
@@ -300,12 +305,12 @@ U8 *CodeStream::allocCode(U32 sz)
          return ptr;
       }
    }
-   
+
    CodeData *data = new CodeData;
    data->data = (U8*)dMalloc(BlockSize);
    data->size = sz;
    data->next = NULL;
-   
+
    if (mCodeHead)
       mCodeHead->next = data;
    mCodeHead = data;
@@ -313,21 +318,21 @@ U8 *CodeStream::allocCode(U32 sz)
       mCode = data;
    return data->data;
 }
-  
+
 //-------------------------------------------------------------------------
-  
+
 void CodeStream::fixLoop(U32 loopBlockStart, U32 breakPoint, U32 continuePoint)
 {
    AssertFatal(mFixStack.size() > 0, "Fix stack mismatch");
-   
-   U32 fixStart = mFixStack[mFixStack.size()-1];
-   for (U32 i=fixStart; i<mFixList.size(); i += 2)
+
+   U32 fixStart = mFixStack[mFixStack.size() - 1];
+   for (U32 i = fixStart; i<mFixList.size(); i += 2)
    {
-      FixType type = (FixType)mFixList[i+1];
-      
+      FixType type = (FixType)mFixList[i + 1];
+
       U32 fixedIp = 0;
       bool valid = true;
-      
+
       switch (type)
       {
          case FIXTYPE_LOOPBLOCKSTART:
@@ -344,7 +349,7 @@ void CodeStream::fixLoop(U32 loopBlockStart, U32 breakPoint, U32 continuePoint)
             valid = false;
             break;
       }
-      
+
       if (valid)
       {
          patch(mFixList[i], fixedIp);
@@ -353,7 +358,7 @@ void CodeStream::fixLoop(U32 loopBlockStart, U32 breakPoint, U32 continuePoint)
 }
 
 //-------------------------------------------------------------------------
-  
+
 void CodeStream::emitCodeStream(U32 *size, U32 **stream, U32 **lineBreaks)
 {
    // Alloc stream
@@ -361,7 +366,7 @@ void CodeStream::emitCodeStream(U32 *size, U32 **stream, U32 **lineBreaks)
    *stream = new U32[mCodePos + (numLineBreaks * 2)];
    dMemset(*stream, '\0', mCodePos + (numLineBreaks * 2));
    *size = mCodePos;
-   
+
    // Dump chunks & line breaks
    U32 outBytes = mCodePos * sizeof(U32);
    U8 *outPtr = *((U8**)stream);
@@ -372,20 +377,20 @@ void CodeStream::emitCodeStream(U32 *size, U32 **stream, U32 **lineBreaks)
       outPtr += bytesToCopy;
       outBytes -= bytesToCopy;
    }
-   
+
    *lineBreaks = *stream + mCodePos;
    dMemcpy(*lineBreaks, mBreakLines.address(), sizeof(U32) * mBreakLines.size());
-   
+
    // Apply patches on top
-   for (U32 i=0; i<mPatchList.size(); i++)
+   for (U32 i = 0; i<mPatchList.size(); i++)
    {
       PatchEntry &e = mPatchList[i];
       (*stream)[e.addr] = e.value;
    }
 }
-  
+
 //-------------------------------------------------------------------------
-  
+
 void CodeStream::reset()
 {
    mCodePos = 0;
@@ -393,7 +398,7 @@ void CodeStream::reset()
    mFixLoopStack.clear();
    mFixList.clear();
    mBreakLines.clear();
-   
+
    // Pop down to one code block
    CodeData *itr = mCode ? mCode->next : NULL;
    while (itr != NULL)
@@ -403,7 +408,7 @@ void CodeStream::reset()
       delete(itr);
       itr = next;
    }
-   
+
    if (mCode)
    {
       mCode->size = 0;

+ 59 - 43
Engine/source/console/compiler.h

@@ -30,6 +30,9 @@
 #include <stdio.h>
 #endif
 
+#include <string>
+#include <unordered_map>
+
 class Stream;
 class DataChunker;
 
@@ -91,10 +94,15 @@ namespace Compiler
       OP_DIV,
       OP_NEG,
 
+      OP_INC,
+      OP_DEC,
+
       OP_SETCURVAR,
       OP_SETCURVAR_CREATE,
       OP_SETCURVAR_ARRAY,
+      OP_SETCURVAR_ARRAY_VARLOOKUP,
       OP_SETCURVAR_ARRAY_CREATE,
+      OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP,
 
       OP_LOADVAR_UINT,// 40
       OP_LOADVAR_FLT,
@@ -113,6 +121,8 @@ namespace Compiler
       OP_SETCURFIELD,
       OP_SETCURFIELD_ARRAY, // 50
       OP_SETCURFIELD_TYPE,
+      OP_SETCURFIELD_ARRAY_VAR,
+      OP_SETCURFIELD_THIS,
 
       OP_LOADFIELD_UINT,
       OP_LOADFIELD_FLT,
@@ -142,6 +152,8 @@ namespace Compiler
 
       OP_CALLFUNC_RESOLVE,
       OP_CALLFUNC,
+      OP_CALLFUNC_POINTER,
+      OP_CALLFUNC_THIS,
 
       OP_ADVANCE_STR,
       OP_ADVANCE_STR_APPENDCHAR,
@@ -155,23 +167,26 @@ namespace Compiler
       OP_PUSH_UINT,     // Integer
       OP_PUSH_FLT,      // Float
       OP_PUSH_VAR,      // Variable
+      OP_PUSH_THIS,     // This pointer
       OP_PUSH_FRAME,    // Frame
 
       OP_ASSERT,
       OP_BREAK,
-      
+
       OP_ITER_BEGIN,       ///< Prepare foreach iterator.
       OP_ITER_BEGIN_STR,   ///< Prepare foreach$ iterator.
       OP_ITER,             ///< Enter foreach loop.
       OP_ITER_END,         ///< End foreach loop.
 
-      OP_INVALID   // 90
+      OP_INVALID,   // 90
+
+      MAX_OP_CODELEN ///< The amount of op codes.
    };
 
    //------------------------------------------------------------
 
    F64 consoleStringToNumber(const char *str, StringTableEntry file = 0, U32 line = 0);
-   
+
    U32 compileBlock(StmtNode *block, CodeStream &codeStream, U32 ip);
 
    //------------------------------------------------------------
@@ -207,6 +222,7 @@ namespace Compiler
       Entry *list;
 
       char buf[256];
+      std::unordered_map<std::string, Entry*> hashTable;
 
       U32 add(const char *str, bool caseSens = true, bool tag = false);
       U32 addIntString(U32 value);
@@ -239,14 +255,14 @@ namespace Compiler
    inline StringTableEntry CodeToSTE(U32 *code, U32 ip)
    {
 #ifdef TORQUE_CPU_X64
-      return (StringTableEntry)(*((U64*)(code+ip)));
+      return (StringTableEntry)(*((U64*)(code + ip)));
 #else
-      return (StringTableEntry)(*(code+ip));
+      return (StringTableEntry)(*(code + ip));
 #endif
    }
 
-   extern void (*STEtoCode)(StringTableEntry ste, U32 ip, U32 *ptr);
-   
+   extern void(*STEtoCode)(StringTableEntry ste, U32 ip, U32 *ptr);
+
    void evalSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr);
    void compileSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr);
 
@@ -254,13 +270,13 @@ namespace Compiler
    CompilerStringTable &getGlobalStringTable();
    CompilerStringTable &getFunctionStringTable();
 
-   void setCurrentStringTable (CompilerStringTable* cst);
+   void setCurrentStringTable(CompilerStringTable* cst);
 
    CompilerFloatTable *getCurrentFloatTable();
    CompilerFloatTable &getGlobalFloatTable();
    CompilerFloatTable &getFunctionFloatTable();
 
-   void setCurrentFloatTable (CompilerFloatTable* cst);
+   void setCurrentFloatTable(CompilerFloatTable* cst);
 
    CompilerIdentTable &getIdentTable();
 
@@ -280,7 +296,7 @@ namespace Compiler
 class CodeStream
 {
 public:
-   
+
    enum FixType
    {
       // For loops
@@ -288,37 +304,37 @@ public:
       FIXTYPE_BREAK,
       FIXTYPE_CONTINUE
    };
-   
+
    enum Constants
    {
       BlockSize = 16384,
    };
-   
+
 protected:
-   
+
    typedef struct PatchEntry
    {
       U32 addr;  ///< Address to patch
       U32 value; ///< Value to place at addr
-      
-      PatchEntry() {;}
-      PatchEntry(U32 a, U32 v)  : addr(a), value(v) {;}
+
+      PatchEntry() { ; }
+      PatchEntry(U32 a, U32 v) : addr(a), value(v) { ; }
    } PatchEntry;
-   
+
    typedef struct CodeData
    {
       U8 *data;       ///< Allocated data (size is BlockSize)
       U32 size;       ///< Bytes used in data
       CodeData *next; ///< Next block
    } CodeData;
-   
+
    /// @name Emitted code
    /// {
    CodeData *mCode;
    CodeData *mCodeHead;
    U32 mCodePos;
    /// }
-   
+
    /// @name Code fixing stacks
    /// {
    Vector<U32> mFixList;
@@ -326,28 +342,28 @@ protected:
    Vector<bool> mFixLoopStack;
    Vector<PatchEntry> mPatchList;
    /// }
-   
+
    Vector<U32> mBreakLines; ///< Line numbers
-   
+
 public:
 
    CodeStream() : mCode(0), mCodeHead(NULL), mCodePos(0)
    {
    }
-   
+
    ~CodeStream()
    {
       reset();
-      
+
       if (mCode)
       {
          dFree(mCode->data);
          delete mCode;
       }
    }
-   
+
    U8 *allocCode(U32 sz);
-   
+
    inline U32 emit(U32 code)
    {
       U32 *ptr = (U32*)allocCode(4);
@@ -357,7 +373,7 @@ public:
 #endif
       return mCodePos++;
    }
-   
+
    inline void patch(U32 addr, U32 code)
    {
 #ifdef DEBUG_CODESTREAM
@@ -365,7 +381,7 @@ public:
 #endif
       mPatchList.push_back(PatchEntry(addr, code));
    }
-   
+
    inline U32 emitSTE(const char *code)
    {
       U64 *ptr = (U64*)allocCode(8);
@@ -375,70 +391,70 @@ public:
       printf("code[%u] = %s\n", mCodePos, code);
 #endif
       mCodePos += 2;
-      return mCodePos-2;
+      return mCodePos - 2;
    }
-   
+
    inline U32 tell()
    {
       return mCodePos;
    }
-   
+
    inline bool inLoop()
    {
-      for (U32 i=0; i<mFixLoopStack.size(); i++)
+      for (U32 i = 0; i<mFixLoopStack.size(); i++)
       {
          if (mFixLoopStack[i])
             return true;
       }
       return false;
    }
-   
+
    inline U32 emitFix(FixType type)
    {
       U32 *ptr = (U32*)allocCode(4);
       *ptr = (U32)type;
-      
+
 #ifdef DEBUG_CODESTREAM
       printf("code[%u] = [FIX:%u]\n", mCodePos, (U32)type);
 #endif
-      
+
       mFixList.push_back(mCodePos);
       mFixList.push_back((U32)type);
       return mCodePos++;
    }
-   
+
    inline void pushFixScope(bool isLoop)
    {
       mFixStack.push_back(mFixList.size());
       mFixLoopStack.push_back(isLoop);
    }
-   
+
    inline void popFixScope()
    {
       AssertFatal(mFixStack.size() > 0, "Fix stack mismatch");
-      
-      U32 newSize = mFixStack[mFixStack.size()-1];
+
+      U32 newSize = mFixStack[mFixStack.size() - 1];
       while (mFixList.size() > newSize)
          mFixList.pop_back();
       mFixStack.pop_back();
       mFixLoopStack.pop_back();
    }
-   
+
    void fixLoop(U32 loopBlockStart, U32 breakPoint, U32 continuePoint);
-   
+
    inline void addBreakLine(U32 lineNumber, U32 ip)
    {
       mBreakLines.push_back(lineNumber);
       mBreakLines.push_back(ip);
    }
-   
+
    inline U32 getNumLineBreaks()
    {
       return mBreakLines.size() / 2;
    }
-   
+
    void emitCodeStream(U32 *size, U32 **stream, U32 **lineBreaks);
-   
+
    void reset();
 };
 

+ 144 - 142
Engine/source/console/console.h

@@ -24,13 +24,13 @@
 #define _CONSOLE_H_
 
 #ifndef _PLATFORM_H_
-   #include "platform/platform.h"
+#include "platform/platform.h"
 #endif
 #ifndef _BITSET_H_
-   #include "core/bitSet.h"
+#include "core/bitSet.h"
 #endif
 #ifndef _REFBASE_H_
-   #include "core/util/refBase.h"
+#include "core/util/refBase.h"
 #endif
 #include <stdarg.h>
 
@@ -95,8 +95,8 @@ struct ConsoleLogEntry
       Script,
       GUI,
       Network,
-     GGConnect,
-     NUM_TYPE
+      GGConnect,
+      NUM_TYPE
    } mType;
 
    /// Indicates the actual log entry.
@@ -120,7 +120,7 @@ extern char *typeValueEmpty;
 class ConsoleValue
 {
 public:
-   
+
    enum
    {
       TypeInternalInt = -5,
@@ -129,17 +129,17 @@ public:
       TypeInternalStackString = -2,
       TypeInternalString = -1,
    };
-   
+
    S32 type;
-   
+
 public:
-   
+
    // NOTE: This is protected to ensure no one outside
    // of this structure is messing with it.
-   
+
 #pragma warning( push )
 #pragma warning( disable : 4201 ) // warning C4201: nonstandard extension used : nameless struct/union
-   
+
    // An variable is either a real dynamic type or
    // its one exposed from C++ using a data pointer.
    //
@@ -154,24 +154,24 @@ public:
          F32 fval;
          U32 bufferLen;
       };
-      
+
       struct
       {
          /// The real data pointer.
          void *dataPtr;
-         
+
          /// The enum lookup table for enumerated types.
          const EnumTable *enumTable;
       };
    };
-   
+
    U32 getIntValue();
    S32 getSignedIntValue();
    F32 getFloatValue();
    const char *getStringValue();
    StringStackPtr getStringStackPtr();
    bool getBoolValue();
-   
+
    void setIntValue(U32 val);
    void setIntValue(S32 val);
    void setFloatValue(F32 val);
@@ -179,7 +179,7 @@ public:
    void setStackStringValue(const char *value);
    void setStringStackPtrValue(StringStackPtr ptr);
    void setBoolValue(bool val);
-   
+
    void init()
    {
       ival = 0;
@@ -188,7 +188,7 @@ public:
       bufferLen = 0;
       type = TypeInternalString;
    }
-   
+
    void cleanup()
    {
       if ((type <= TypeInternalString) && (bufferLen > 0))
@@ -201,8 +201,8 @@ public:
       ival = 0;
       fval = 0;
    }
-   ConsoleValue(){ init(); };
-   ~ConsoleValue(){ cleanup(); };
+   ConsoleValue() { init(); };
+   ~ConsoleValue() { cleanup(); };
 };
 
 // Proxy class for console variables
@@ -234,7 +234,7 @@ public:
    inline operator S32() { return getSignedIntValue(); }
    inline operator F32() { return getFloatValue(); }
    inline operator bool() { return getBoolValue(); }
-   
+
    inline bool isStringStackPtr() { return value ? value->type == ConsoleValue::TypeInternalStringStackPtr : false; }
    inline bool isString() { return value ? value->type >= ConsoleValue::TypeInternalStringStackPtr : true; }
    inline bool isInt() { return value ? value->type == ConsoleValue::TypeInternalInt : false; }
@@ -320,12 +320,12 @@ public:
 
 ///
 typedef const char * (*StringCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]);
-typedef S32             (*IntCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]);
-typedef F32           (*FloatCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]);
-typedef void           (*VoidCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]); // We have it return a value so things don't break..
-typedef bool           (*BoolCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]);
+typedef S32(*IntCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]);
+typedef F32(*FloatCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]);
+typedef void(*VoidCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]); // We have it return a value so things don't break..
+typedef bool(*BoolCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]);
 
-typedef void (*ConsumerCallback)(U32 level, const char *consoleLine);
+typedef void(*ConsumerCallback)(U32 level, const char *consoleLine);
 /// @}
 
 /// @defgroup console_types Scripting Engine Type Functions
@@ -333,7 +333,7 @@ typedef void (*ConsumerCallback)(U32 level, const char *consoleLine);
 /// @see Con::registerType
 /// @{
 typedef const char* (*GetDataFunction)(void *dptr, EnumTable *tbl, BitSet32 flag);
-typedef void        (*SetDataFunction)(void *dptr, S32 argc, const char **argv, EnumTable *tbl, BitSet32 flag);
+typedef void(*SetDataFunction)(void *dptr, S32 argc, const char **argv, EnumTable *tbl, BitSet32 flag);
 /// @}
 
 /// This namespace contains the core of the console functionality.
@@ -347,7 +347,7 @@ typedef void        (*SetDataFunction)(void *dptr, S32 argc, const char **argv,
 namespace Con
 {
    /// Various configuration constants.
-   enum Constants 
+   enum Constants
    {
       /// This is the version number associated with DSO files.
       ///
@@ -361,20 +361,22 @@ namespace Con
       /// 12/29/04 - BJG - 33->34 Removed some opcodes, part of namespace upgrade.
       /// 12/30/04 - BJG - 34->35 Reordered some things, further general shuffling.
       /// 11/03/05 - BJG - 35->36 Integrated new debugger code.
-      //  09/08/06 - THB - 36->37 New opcode for internal names
-      //  09/15/06 - THB - 37->38 Added unit conversions
-      //  11/23/06 - THB - 38->39 Added recursive internal name operator
-      //  02/15/07 - THB - 39->40 Bumping to 40 for TGB since the console has been
-      //                          majorly hacked without the version number being bumped
-      //  02/16/07 - THB - 40->41 newmsg operator
-      //  06/15/07 - THB - 41->42 script types
+      /// 09/08/06 - THB - 36->37 New opcode for internal names
+      /// 09/15/06 - THB - 37->38 Added unit conversions
+      /// 11/23/06 - THB - 38->39 Added recursive internal name operator
+      /// 02/15/07 - THB - 39->40 Bumping to 40 for TGB since the console has been
+      ///                         majorly hacked without the version number being bumped
+      /// 02/16/07 - THB - 40->41 newmsg operator
+      /// 06/15/07 - THB - 41->42 script types
       /// 07/31/07 - THB - 42->43 Patch from Andreas Kirsch: Added opcode to support nested new declarations.
       /// 09/12/07 - CAF - 43->44 remove newmsg operator
       /// 09/27/07 - RDB - 44->45 Patch from Andreas Kirsch: Added opcode to support correct void return
       /// 01/13/09 - TMS - 45->46 Added script assert
       /// 09/07/14 - jamesu - 46->47 64bit support
       /// 10/14/14 - jamesu - 47->48 Added opcodes to reduce reliance on strings in function calls
-      DSOVersion = 48,
+      /// 10/07/17 - JTH - 48->49 Added opcode for function pointers and revamp of interpreter 
+      ///                         from switch to function calls.
+      DSOVersion = 49,
 
       MaxLineLength = 512,  ///< Maximum length of a line of console input.
       MaxDataTypes = 256    ///< Maximum number of registered data types.
@@ -552,11 +554,11 @@ namespace Con
    /// @param usage     Documentation string.
    ///
    /// @see ConsoleDynamicTypes
-   void addVariable( const char *name, 
-                     S32 type, 
-                     void *pointer, 
-                     const char* usage = NULL );
-                     
+   void addVariable(const char *name,
+      S32 type,
+      void *pointer,
+      const char* usage = NULL);
+
    /// Add a console constant that references the value of a constant in C++ code.
    ///
    /// @param name      Global console constant name to create.
@@ -565,11 +567,11 @@ namespace Con
    /// @param usage     Documentation string.
    ///
    /// @see ConsoleDynamicTypes
-   void addConstant( const char *name, 
-                     S32 type, 
-                     const void *pointer, 
-                     const char* usage = NULL );
-                     
+   void addConstant(const char *name,
+      S32 type,
+      const void *pointer,
+      const char* usage = NULL);
+
    /// Remove a console variable.
    ///
    /// @param name   Global console variable name to remove
@@ -582,14 +584,14 @@ namespace Con
    /// @param name      An existing global console variable name.
    /// @param callback  The notification delegate function.
    ///
-   void addVariableNotify( const char *name, const NotifyDelegate &callback );
+   void addVariableNotify(const char *name, const NotifyDelegate &callback);
 
    /// Remove an existing variable assignment notification callback.
    ///
    /// @param name      An existing global console variable name.
    /// @param callback  The notification delegate function.
    ///
-   void removeVariableNotify( const char *name, const NotifyDelegate &callback );
+   void removeVariableNotify(const char *name, const NotifyDelegate &callback);
 
    /// Assign a string value to a locally scoped console variable
    ///
@@ -628,31 +630,31 @@ namespace Con
    const char* getObjectField(const char* name);
 
    /// Same as setVariable(), but for bools.
-   void setBoolVariable (const char* name,bool var);
+   void setBoolVariable(const char* name, bool var);
 
    /// Same as getVariable(), but for bools.
    ///
    /// @param  name  Name of the variable.
    /// @param  def   Default value to supply if no matching variable is found.
-   bool getBoolVariable (const char* name,bool def = false);
+   bool getBoolVariable(const char* name, bool def = false);
 
    /// Same as setVariable(), but for ints.
-   void setIntVariable  (const char* name,S32 var);
+   void setIntVariable(const char* name, S32 var);
 
    /// Same as getVariable(), but for ints.
    ///
    /// @param  name  Name of the variable.
    /// @param  def   Default value to supply if no matching variable is found.
-   S32  getIntVariable  (const char* name,S32 def = 0);
+   S32  getIntVariable(const char* name, S32 def = 0);
 
    /// Same as setVariable(), but for floats.
-   void setFloatVariable(const char* name,F32 var);
+   void setFloatVariable(const char* name, F32 var);
 
    /// Same as getVariable(), but for floats.
    ///
    /// @param  name  Name of the variable.
    /// @param  def   Default value to supply if no matching variable is found.
-   F32  getFloatVariable(const char* name,F32 def = .0f);
+   F32  getFloatVariable(const char* name, F32 def = .0f);
 
    /// @}
 
@@ -668,52 +670,52 @@ namespace Con
    /// @param maxArgs   Maximum number of arguments this function accepts
    /// @param toolOnly  Wether this is a TORQUE_TOOLS only function.
    /// @param header    The extended function header.
-   void addCommand( const char* name, StringCallback cb, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
-
-   void addCommand( const char* name, IntCallback    cb, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL ); ///< @copydoc addCommand( const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
-   void addCommand( const char* name, FloatCallback  cb, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL ); ///< @copydoc addCommand( const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
-   void addCommand( const char* name, VoidCallback   cb, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL ); ///< @copydoc addCommand( const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
-   void addCommand( const char* name, BoolCallback   cb, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL ); ///< @copydoc addCommand( const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
-   
-   /// @}
-
-   /// @name Namespace Function Registration
-   /// @{
-
-   /// Register a C++ function with the console making it callable
-   /// as a method of the given namespace from the scripting engine.
-   ///
-   /// @param nameSpace Name of the namespace to associate the new function with; this is usually the name of a class.
-   /// @param name      Name of the new function.
-   /// @param cb        Pointer to the function implementing the scripting call; a console callback function returning a specific type value.
-   /// @param usage     Documentation for this function. @ref console_autodoc
-   /// @param minArgs   Minimum number of arguments this function accepts
-   /// @param maxArgs   Maximum number of arguments this function accepts
-   /// @param toolOnly  Wether this is a TORQUE_TOOLS only function.
-   /// @param header    The extended function header.
-   void addCommand(const char *nameSpace, const char *name,StringCallback cb, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
-
-   void addCommand(const char *nameSpace, const char *name,IntCallback cb,    const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL ); ///< @copydoc addCommand( const char*, const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
-   void addCommand(const char *nameSpace, const char *name,FloatCallback cb,  const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL ); ///< @copydoc addCommand( const char*, const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
-   void addCommand(const char *nameSpace, const char *name,VoidCallback cb,   const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL ); ///< @copydoc addCommand( const char*, const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
-   void addCommand(const char *nameSpace, const char *name,BoolCallback cb,   const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL ); ///< @copydoc addCommand( const char*, const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
-
-   /// @}
-
-   /// @name Special Purpose Registration
-   ///
-   /// These are special-purpose functions that exist to allow commands to be grouped, so
-   /// that when we generate console docs, they can be more meaningfully presented.
-   ///
-   /// @ref console_autodoc "Click here for more information about console docs and grouping."
-   ///
-   /// @{
-
-   void markCommandGroup (const char * nsName, const char *name, const char* usage=NULL);
+   void addCommand(const char* name, StringCallback cb, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
+
+   void addCommand(const char* name, IntCallback    cb, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL); ///< @copydoc addCommand( const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
+   void addCommand(const char* name, FloatCallback  cb, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL); ///< @copydoc addCommand( const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
+   void addCommand(const char* name, VoidCallback   cb, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL); ///< @copydoc addCommand( const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
+   void addCommand(const char* name, BoolCallback   cb, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL); ///< @copydoc addCommand( const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
+
+                                                                                                                                                                   /// @}
+
+                                                                                                                                                                   /// @name Namespace Function Registration
+                                                                                                                                                                   /// @{
+
+                                                                                                                                                                   /// Register a C++ function with the console making it callable
+                                                                                                                                                                   /// as a method of the given namespace from the scripting engine.
+                                                                                                                                                                   ///
+                                                                                                                                                                   /// @param nameSpace Name of the namespace to associate the new function with; this is usually the name of a class.
+                                                                                                                                                                   /// @param name      Name of the new function.
+                                                                                                                                                                   /// @param cb        Pointer to the function implementing the scripting call; a console callback function returning a specific type value.
+                                                                                                                                                                   /// @param usage     Documentation for this function. @ref console_autodoc
+                                                                                                                                                                   /// @param minArgs   Minimum number of arguments this function accepts
+                                                                                                                                                                   /// @param maxArgs   Maximum number of arguments this function accepts
+                                                                                                                                                                   /// @param toolOnly  Wether this is a TORQUE_TOOLS only function.
+                                                                                                                                                                   /// @param header    The extended function header.
+   void addCommand(const char *nameSpace, const char *name, StringCallback cb, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
+
+   void addCommand(const char *nameSpace, const char *name, IntCallback cb, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL); ///< @copydoc addCommand( const char*, const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
+   void addCommand(const char *nameSpace, const char *name, FloatCallback cb, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL); ///< @copydoc addCommand( const char*, const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
+   void addCommand(const char *nameSpace, const char *name, VoidCallback cb, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL); ///< @copydoc addCommand( const char*, const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
+   void addCommand(const char *nameSpace, const char *name, BoolCallback cb, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL); ///< @copydoc addCommand( const char*, const char *, StringCallback, const char *, S32, S32, bool, ConsoleFunctionHeader* )
+
+                                                                                                                                                                                        /// @}
+
+                                                                                                                                                                                        /// @name Special Purpose Registration
+                                                                                                                                                                                        ///
+                                                                                                                                                                                        /// These are special-purpose functions that exist to allow commands to be grouped, so
+                                                                                                                                                                                        /// that when we generate console docs, they can be more meaningfully presented.
+                                                                                                                                                                                        ///
+                                                                                                                                                                                        /// @ref console_autodoc "Click here for more information about console docs and grouping."
+                                                                                                                                                                                        ///
+                                                                                                                                                                                        /// @{
+
+   void markCommandGroup(const char * nsName, const char *name, const char* usage = NULL);
    void beginCommandGroup(const char * nsName, const char *name, const char* usage);
-   void endCommandGroup  (const char * nsName, const char *name);
+   void endCommandGroup(const char * nsName, const char *name);
 
-   void noteScriptCallback( const char *className, const char *funcName, const char *usage, ConsoleFunctionHeader* header = NULL );
+   void noteScriptCallback(const char *className, const char *funcName, const char *usage, ConsoleFunctionHeader* header = NULL);
 
    /// @}
 
@@ -841,15 +843,15 @@ namespace Con
    ///
    char* getReturnBuffer(U32 bufferSize);
    char* getReturnBuffer(const char *stringToCopy);
-   char* getReturnBuffer( const String& str );
-   char* getReturnBuffer( const StringBuilder& str );
+   char* getReturnBuffer(const String& str);
+   char* getReturnBuffer(const StringBuilder& str);
 
    char* getArgBuffer(U32 bufferSize);
    char* getFloatArg(F64 arg);
-   char* getIntArg  (S32 arg);
+   char* getIntArg(S32 arg);
    char* getBoolArg(bool arg);
-   char* getStringArg( const char* arg );
-   char* getStringArg( const String& arg );
+   char* getStringArg(const char* arg);
+   char* getStringArg(const String& arg);
    /// @}
 
    /// @name Namespaces
@@ -877,7 +879,7 @@ namespace Con
    /// @name Instant Group
    /// @{
 
-   void pushInstantGroup( String name = String() );
+   void pushInstantGroup(String name = String());
    void popInstantGroup();
 
    /// @}
@@ -915,7 +917,7 @@ namespace Con
    template<typename R, typename ...ArgTs>
    ConsoleValueRef executef(R r, ArgTs ...argTs)
    {
-      _EngineConsoleExecCallbackHelper<R> callback( r );
+      _EngineConsoleExecCallbackHelper<R> callback(r);
       return callback.template call<ConsoleValueRef>(argTs...);
    }
    /// }
@@ -931,25 +933,25 @@ struct ConsoleFunctionHeader
 {
    /// Return type string.
    const char* mReturnString;
-   
+
    /// List of arguments taken by the function.  Used for documentation.
    const char* mArgString;
-   
+
    /// List of default argument values.  Used for documentation.
    const char* mDefaultArgString;
-   
+
    /// Whether this is a static method in a class.
    bool mIsStatic;
-   
+
    ConsoleFunctionHeader(
       const char* returnString,
       const char* argString,
       const char* defaultArgString,
-      bool isStatic = false )
-      : mReturnString( returnString ),
-        mArgString( argString ),
-        mDefaultArgString( defaultArgString ),
-        mIsStatic( isStatic ) {}
+      bool isStatic = false)
+      : mReturnString(returnString),
+      mArgString(argString),
+      mDefaultArgString(defaultArgString),
+      mIsStatic(isStatic) {}
 };
 
 
@@ -969,7 +971,7 @@ public:
    ///
    /// @ref console_autodoc
    /// @{
-   
+
    StringCallback sc;   ///< A function/method that returns a string.
    IntCallback ic;      ///< A function/method that returns an int.
    FloatCallback fc;    ///< A function/method that returns a float.
@@ -979,18 +981,18 @@ public:
    bool ns;             ///< Indicates that this is a namespace marker.
                         ///  @deprecated Unused.
    bool callback;       ///< Is this a callback into script?
-   
-   /// @}
 
-   /// Minimum number of arguments expected by the function.
+                        /// @}
+
+                        /// Minimum number of arguments expected by the function.
    S32 mina;
-   
+
    /// Maximum number of arguments accepted by the funtion.  Zero for varargs.
    S32 maxa;
-      
+
    /// Name of the function/method.
    const char* funcName;
-   
+
    /// Name of the class namespace to which to add the method.
    const char* className;
 
@@ -999,10 +1001,10 @@ public:
 
    /// Whether this is a TORQUE_TOOLS only function.
    bool toolOnly;
-   
+
    /// The extended function header.
    ConsoleFunctionHeader* header;
-   
+
    /// @name ConsoleConstructor Innards
    ///
    /// The ConsoleConstructor class is used as the backend for the ConsoleFunction() and
@@ -1067,7 +1069,7 @@ public:
    ConsoleConstructor *next;
    static ConsoleConstructor *first;
 
-   void init( const char* cName, const char* fName, const char *usg, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
+   void init(const char* cName, const char* fName, const char *usg, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
 
    static void setup();
 
@@ -1079,12 +1081,12 @@ public:
    /// @name Basic Console Constructors
    /// @{
 
-   ConsoleConstructor( const char* className, const char* funcName, StringCallback sfunc, const char* usage,  S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
-   ConsoleConstructor( const char* className, const char* funcName, IntCallback    ifunc, const char* usage,  S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
-   ConsoleConstructor( const char* className, const char* funcName, FloatCallback  ffunc, const char* usage,  S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
-   ConsoleConstructor( const char* className, const char* funcName, VoidCallback   vfunc, const char* usage,  S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
-   ConsoleConstructor( const char* className, const char* funcName, BoolCallback   bfunc, const char* usage,  S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
-   
+   ConsoleConstructor(const char* className, const char* funcName, StringCallback sfunc, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
+   ConsoleConstructor(const char* className, const char* funcName, IntCallback    ifunc, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
+   ConsoleConstructor(const char* className, const char* funcName, FloatCallback  ffunc, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
+   ConsoleConstructor(const char* className, const char* funcName, VoidCallback   vfunc, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
+   ConsoleConstructor(const char* className, const char* funcName, BoolCallback   bfunc, const char* usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
+
    /// @}
 
    /// @name Magic Console Constructors
@@ -1097,10 +1099,10 @@ public:
    ///
    /// @see Con::markCommandGroup
    /// @ref console_autodoc
-   ConsoleConstructor( const char *className, const char *groupName, const char* usage );
+   ConsoleConstructor(const char *className, const char *groupName, const char* usage);
 
    /// Indicates a callback declared with the DECLARE_SCRIPT_CALLBACK macro and friends.
-   ConsoleConstructor( const char *className, const char *callbackName, const char *usage, ConsoleFunctionHeader* header );
+   ConsoleConstructor(const char *className, const char *callbackName, const char *usage, ConsoleFunctionHeader* header);
 
    /// @}
 };
@@ -1112,25 +1114,25 @@ struct ConsoleDocFragment
    /// The class in which to put the fragment.  If NULL, the fragment
    /// will be placed globally.
    const char* mClass;
-   
+
    /// The definition to output for this fragment.  NULL for fragments
    /// not associated with a definition.
    const char* mDefinition;
-   
+
    /// The documentation text.
    const char* mText;
-   
+
    /// Next fragment in the global link chain.
    ConsoleDocFragment* mNext;
-   
+
    /// First fragment in the global link chain.
    static ConsoleDocFragment* smFirst;
-   
-   ConsoleDocFragment( const char* text, const char* inClass = NULL, const char* definition = NULL )
-      : mClass( inClass ),
-        mDefinition( definition ),
-        mText( text ),
-        mNext( smFirst )
+
+   ConsoleDocFragment(const char* text, const char* inClass = NULL, const char* definition = NULL)
+      : mClass(inClass),
+      mDefinition(definition),
+      mText(text),
+      mNext(smFirst)
    {
       smFirst = this;
    }
@@ -1229,7 +1231,7 @@ public:
 
 #  define ConsoleMethodGroupEnd(className, groupName) \
    static ConsoleConstructor cc_##className##_##groupName##_GroupEnd(#className,#groupName,NULL)
-   
+
 /// Add a fragment of auto-doc text to the console API reference.
 /// @note There can only be one ConsoleDoc per source file.
 #  define ConsoleDoc( text )                                \

File diff suppressed because it is too large
+ 266 - 250
Engine/source/console/consoleInternal.cpp


+ 241 - 242
Engine/source/console/consoleInternal.h

@@ -24,22 +24,21 @@
 #define _CONSOLEINTERNAL_H_
 
 #ifndef _STRINGFUNCTIONS_H_
-   #include "core/strings/stringFunctions.h"
+#include "core/strings/stringFunctions.h"
 #endif
 #ifndef _STRINGTABLE_H_
-   #include "core/stringTable.h"
+#include "core/stringTable.h"
 #endif
 #ifndef _CONSOLETYPES_H
-   #include "console/consoleTypes.h"
+#include "console/consoleTypes.h"
 #endif
 #ifndef _CONSOLEOBJECT_H_
-   #include "console/simObject.h"
+#include "console/simObject.h"
 #endif
 #ifndef _DATACHUNKER_H_
-   #include "core/dataChunker.h"
+#include "core/dataChunker.h"
 #endif
 
-
 /// @ingroup console_system Console System
 /// @{
 
@@ -55,222 +54,222 @@ class AbstractClassRep;
 /// Namespaces are used for dispatching calls in the console system.
 class Namespace
 {
-      enum {
-        MaxActivePackages = 512,
+   enum {
+      MaxActivePackages = 512,
+   };
+
+   static U32 mNumActivePackages;
+   static U32 mOldNumActivePackages;
+   static StringTableEntry mActivePackages[MaxActivePackages];
+
+public:
+   StringTableEntry mName;
+   StringTableEntry mPackage;
+
+   Namespace *mParent;
+   Namespace *mNext;
+   AbstractClassRep *mClassRep;
+   U32 mRefCountToParent;
+
+   const char* mUsage;
+
+   /// Script defined usage strings need to be cleaned up. This
+   /// field indicates whether or not the usage was set from script.
+   bool mCleanUpUsage;
+
+   /// A function entry in the namespace.
+   struct Entry
+   {
+      enum
+      {
+         ScriptCallbackType = -3,
+         GroupMarker = -2,
+         InvalidFunctionType = -1,
+         ConsoleFunctionType,
+         StringCallbackType,
+         IntCallbackType,
+         FloatCallbackType,
+         VoidCallbackType,
+         BoolCallbackType
       };
 
-      static U32 mNumActivePackages;
-      static U32 mOldNumActivePackages;
-      static StringTableEntry mActivePackages[MaxActivePackages];
+      /// Link back to the namespace to which the entry belongs.
+      Namespace* mNamespace;
 
-   public:
-      StringTableEntry mName;
+      /// Next function entry in the hashtable link chain of the namespace.
+      Entry* mNext;
+
+      /// Name of this function.
+      StringTableEntry mFunctionName;
+
+      ///
+      S32 mType;
+
+      /// Min number of arguments expected by this function.
+      S32 mMinArgs;
+
+      /// Max number of arguments expected by this function.  If zero,
+      /// function takes an arbitrary number of arguments.
+      S32 mMaxArgs;
+
+      /// Name of the package to which this function belongs.
       StringTableEntry mPackage;
 
-      Namespace *mParent;
-      Namespace *mNext;
-      AbstractClassRep *mClassRep;
-      U32 mRefCountToParent;
-      
+      /// Whether this function is included only in TORQUE_TOOLS builds.
+      bool mToolOnly;
+
+      /// Usage string for documentation.
       const char* mUsage;
-      
-      /// Script defined usage strings need to be cleaned up. This
-      /// field indicates whether or not the usage was set from script.
-      bool mCleanUpUsage;
 
-      /// A function entry in the namespace.
-      struct Entry
-      {
-         enum 
-         {
-            ScriptCallbackType           = -3,
-            GroupMarker                  = -2,
-            InvalidFunctionType          = -1,
-            ConsoleFunctionType,
-            StringCallbackType,
-            IntCallbackType,
-            FloatCallbackType,
-            VoidCallbackType,
-            BoolCallbackType
-         };
-
-         /// Link back to the namespace to which the entry belongs.
-         Namespace* mNamespace;
-         
-         /// Next function entry in the hashtable link chain of the namespace.
-         Entry* mNext;
-         
-         /// Name of this function.
-         StringTableEntry mFunctionName;
-         
-         ///
-         S32 mType;
-         
-         /// Min number of arguments expected by this function.
-         S32 mMinArgs;
-         
-         /// Max number of arguments expected by this function.  If zero,
-         /// function takes an arbitrary number of arguments.
-         S32 mMaxArgs;
-         
-         /// Name of the package to which this function belongs.
-         StringTableEntry mPackage;
-         
-         /// Whether this function is included only in TORQUE_TOOLS builds.
-         bool mToolOnly;
-
-         /// Usage string for documentation.
-         const char* mUsage;
-         
-         /// Extended console function information.
-         ConsoleFunctionHeader* mHeader;
-
-         /// The compiled script code if this is a script function.
-         CodeBlock* mCode;
-         
-         /// The offset in the compiled script code at which this function begins.
-         U32 mFunctionOffset;
-
-         /// If it's a script function, this is the line of the declaration in code.
-         /// @note 0 for functions read from legacy DSOs that have no line number information.
-         U32 mFunctionLineNumber;
-         
-         union CallbackUnion {
-            StringCallback mStringCallbackFunc;
-            IntCallback mIntCallbackFunc;
-            VoidCallback mVoidCallbackFunc;
-            FloatCallback mFloatCallbackFunc;
-            BoolCallback mBoolCallbackFunc;
-            const char *mGroupName;
-            const char *mCallbackName;
-         } cb;
-         
-         Entry();
-         
-         ///
-         void clear();
-
-         ///
-         ConsoleValueRef execute( S32 argc, ConsoleValueRef* argv, ExprEvalState* state );
-         
-         /// Return a one-line documentation text string for the function.
-         String getBriefDescription( String* outRemainingDocText = NULL ) const;
-         
-         /// Get the auto-doc string for this function.  This string does not included prototype information.
-         String getDocString() const;
-         
-         /// Return a string describing the arguments the function takes including default argument values.
-         String getArgumentsString() const;
-
-         /// Return a full prototype string for the function including return type, function name,
-         /// and arguments.
-         String getPrototypeString() const;
-      };
-      
-      Entry* mEntryList;
+      /// Extended console function information.
+      ConsoleFunctionHeader* mHeader;
 
-      Entry** mHashTable;
-      
-      U32 mHashSize;
-      U32 mHashSequence;   ///< @note The hash sequence is used by the autodoc console facility
-                           ///        as a means of testing reference state.
+      /// The compiled script code if this is a script function.
+      CodeBlock* mCode;
 
-      Namespace();
-      ~Namespace();
+      /// The offset in the compiled script code at which this function begins.
+      U32 mFunctionOffset;
 
-      void addFunction( StringTableEntry name, CodeBlock* cb, U32 functionOffset, const char* usage = NULL, U32 lineNumber = 0 );
-      void addCommand( StringTableEntry name, StringCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
-      void addCommand( StringTableEntry name, IntCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
-      void addCommand( StringTableEntry name, FloatCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
-      void addCommand( StringTableEntry name, VoidCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
-      void addCommand( StringTableEntry name, BoolCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL );
+      /// If it's a script function, this is the line of the declaration in code.
+      /// @note 0 for functions read from legacy DSOs that have no line number information.
+      U32 mFunctionLineNumber;
 
-      void addScriptCallback( const char *funcName, const char *usage, ConsoleFunctionHeader* header = NULL );
+      union CallbackUnion {
+         StringCallback mStringCallbackFunc;
+         IntCallback mIntCallbackFunc;
+         VoidCallback mVoidCallbackFunc;
+         FloatCallback mFloatCallbackFunc;
+         BoolCallback mBoolCallbackFunc;
+         const char *mGroupName;
+         const char *mCallbackName;
+      } cb;
 
-      void markGroup(const char* name, const char* usage);
-      char * lastUsage;
+      Entry();
 
-      /// Returns true if this namespace represents an engine defined
-      /// class and is not just a script defined class namespace.
-      bool isClass() const { return mClassRep && mClassRep->getNameSpace() == this; }
+      ///
+      void clear();
 
-      void getEntryList(VectorPtr<Entry *> *);
+      ///
+      ConsoleValueRef execute(S32 argc, ConsoleValueRef* argv, ExprEvalState* state);
 
-      /// Return the name of this namespace.
-      StringTableEntry getName() const { return mName; }
+      /// Return a one-line documentation text string for the function.
+      String getBriefDescription(String* outRemainingDocText = NULL) const;
 
-      /// Return the superordinate namespace to this namespace. Symbols are inherited from
-      /// this namespace.
-      Namespace* getParent() const { return mParent; }
+      /// Get the auto-doc string for this function.  This string does not included prototype information.
+      String getDocString() const;
 
-      /// Return the topmost package in the parent hierarchy of this namespace
-      /// that still refers to the same namespace.  If packages are active and
-      /// adding to this namespace, then they will be linked in-between the namespace
-      /// they are adding to and its real parent namespace.
-      Namespace* getPackageRoot()
-      {
-         Namespace* walk = this;
-         while( walk->mParent && walk->mParent->mName == mName )
-            walk = walk->mParent;
+      /// Return a string describing the arguments the function takes including default argument values.
+      String getArgumentsString() const;
 
-         return walk;
-      }
+      /// Return a full prototype string for the function including return type, function name,
+      /// and arguments.
+      String getPrototypeString() const;
+   };
 
-      /// Return the package in which this namespace is defined.
-      StringTableEntry getPackage() const { return mPackage; }
+   Entry* mEntryList;
 
-      /// Increase the count on the reference that this namespace
-      /// holds to its parent.
-      /// @note Must not be called on namespaces coming from packages.
-      void incRefCountToParent()
-      {
-         AssertFatal( mPackage == NULL, "Namespace::incRefCountToParent - Must not be called on a namespace coming from a package!" );
-         mRefCountToParent ++;
-      }
+   Entry** mHashTable;
 
-      /// Decrease the count on the reference that this namespace
-      /// holds to its parent.
-      /// @note Must not be called on namespaces coming from packages.
-      void decRefCountToParent()
-      {
-         unlinkClass( NULL );
-      }
+   U32 mHashSize;
+   U32 mHashSequence;   ///< @note The hash sequence is used by the autodoc console facility
+                        ///        as a means of testing reference state.
+
+   Namespace();
+   ~Namespace();
+
+   void addFunction(StringTableEntry name, CodeBlock* cb, U32 functionOffset, const char* usage = NULL, U32 lineNumber = 0);
+   void addCommand(StringTableEntry name, StringCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
+   void addCommand(StringTableEntry name, IntCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
+   void addCommand(StringTableEntry name, FloatCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
+   void addCommand(StringTableEntry name, VoidCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
+   void addCommand(StringTableEntry name, BoolCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
+
+   void addScriptCallback(const char *funcName, const char *usage, ConsoleFunctionHeader* header = NULL);
+
+   void markGroup(const char* name, const char* usage);
+   char * lastUsage;
 
-      Entry *lookup(StringTableEntry name);
-      Entry *lookupRecursive(StringTableEntry name);
-      Entry *createLocalEntry(StringTableEntry name);
-      void buildHashTable();
-      void clearEntries();
-      bool classLinkTo(Namespace *parent);
-      bool unlinkClass(Namespace *parent);
-      void getUniqueEntryLists( Namespace *other, VectorPtr<Entry *> *outThisList, VectorPtr<Entry *> *outOtherList );
-
-      const char *tabComplete(const char *prevText, S32 baseLen, bool fForward);
-
-      static U32 mCacheSequence;
-      static DataChunker mCacheAllocator;
-      static DataChunker mAllocator;
-      static void trashCache();
-      static Namespace *mNamespaceList;
-      static Namespace *mGlobalNamespace;
-
-      static void init();
-      static void shutdown();
-      static Namespace *global();
-
-      static Namespace *find(StringTableEntry name, StringTableEntry package=NULL);
-
-      static void activatePackage(StringTableEntry name);
-      static void deactivatePackage(StringTableEntry name);
-      static void deactivatePackageStack(StringTableEntry name);
-      static void dumpClasses( bool dumpScript = true, bool dumpEngine = true );
-      static void dumpFunctions( bool dumpScript = true, bool dumpEngine = true );
-      static void printNamespaceEntries(Namespace * g, bool dumpScript = true, bool dumpEngine = true);
-      static void unlinkPackages();
-      static void relinkPackages();
-      static bool isPackage(StringTableEntry name);
-      static U32 getActivePackagesCount();
-      static StringTableEntry getActivePackage(U32 index);
+   /// Returns true if this namespace represents an engine defined
+   /// class and is not just a script defined class namespace.
+   bool isClass() const { return mClassRep && mClassRep->getNameSpace() == this; }
+
+   void getEntryList(VectorPtr<Entry *> *);
+
+   /// Return the name of this namespace.
+   StringTableEntry getName() const { return mName; }
+
+   /// Return the superordinate namespace to this namespace. Symbols are inherited from
+   /// this namespace.
+   Namespace* getParent() const { return mParent; }
+
+   /// Return the topmost package in the parent hierarchy of this namespace
+   /// that still refers to the same namespace.  If packages are active and
+   /// adding to this namespace, then they will be linked in-between the namespace
+   /// they are adding to and its real parent namespace.
+   Namespace* getPackageRoot()
+   {
+      Namespace* walk = this;
+      while (walk->mParent && walk->mParent->mName == mName)
+         walk = walk->mParent;
+
+      return walk;
+   }
+
+   /// Return the package in which this namespace is defined.
+   StringTableEntry getPackage() const { return mPackage; }
+
+   /// Increase the count on the reference that this namespace
+   /// holds to its parent.
+   /// @note Must not be called on namespaces coming from packages.
+   void incRefCountToParent()
+   {
+      AssertFatal(mPackage == NULL, "Namespace::incRefCountToParent - Must not be called on a namespace coming from a package!");
+      mRefCountToParent++;
+   }
+
+   /// Decrease the count on the reference that this namespace
+   /// holds to its parent.
+   /// @note Must not be called on namespaces coming from packages.
+   void decRefCountToParent()
+   {
+      unlinkClass(NULL);
+   }
+
+   Entry *lookup(StringTableEntry name);
+   Entry *lookupRecursive(StringTableEntry name);
+   Entry *createLocalEntry(StringTableEntry name);
+   void buildHashTable();
+   void clearEntries();
+   bool classLinkTo(Namespace *parent);
+   bool unlinkClass(Namespace *parent);
+   void getUniqueEntryLists(Namespace *other, VectorPtr<Entry *> *outThisList, VectorPtr<Entry *> *outOtherList);
+
+   const char *tabComplete(const char *prevText, S32 baseLen, bool fForward);
+
+   static U32 mCacheSequence;
+   static DataChunker mCacheAllocator;
+   static DataChunker mAllocator;
+   static void trashCache();
+   static Namespace *mNamespaceList;
+   static Namespace *mGlobalNamespace;
+
+   static void init();
+   static void shutdown();
+   static Namespace *global();
+
+   static Namespace *find(StringTableEntry name, StringTableEntry package = NULL);
+
+   static void activatePackage(StringTableEntry name);
+   static void deactivatePackage(StringTableEntry name);
+   static void deactivatePackageStack(StringTableEntry name);
+   static void dumpClasses(bool dumpScript = true, bool dumpEngine = true);
+   static void dumpFunctions(bool dumpScript = true, bool dumpEngine = true);
+   static void printNamespaceEntries(Namespace * g, bool dumpScript = true, bool dumpEngine = true);
+   static void unlinkPackages();
+   static void relinkPackages();
+   static bool isPackage(StringTableEntry name);
+   static U32 getActivePackagesCount();
+   static StringTableEntry getActivePackage(U32 index);
 };
 
 typedef VectorPtr<Namespace::Entry *>::iterator NamespaceEntryListIterator;
@@ -292,10 +291,10 @@ public:
       /// The optional notification signal called when
       /// a value is assigned to this variable.
       NotifySignal *notify;
-      
+
       /// Usage doc string.
       const char* mUsage;
-      
+
       /// Whether this is a constant that cannot be assigned to.
       bool mIsConstant;
 
@@ -309,16 +308,16 @@ public:
          mIsConstant = false;
          value.init();
       }
-      
+
       Entry(StringTableEntry name);
       ~Entry();
-      
+
       Entry *mNext;
-      
+
       void reset() {
          name = NULL;
          value.cleanup();
-         if ( notify )
+         if (notify)
             delete notify;
       }
 
@@ -339,63 +338,63 @@ public:
 
       void setIntValue(U32 val)
       {
-         if( mIsConstant )
+         if (mIsConstant)
          {
-            Con::errorf( "Cannot assign value to constant '%s'.", name );
+            Con::errorf("Cannot assign value to constant '%s'.", name);
             return;
          }
-         
+
          value.setIntValue(val);
 
          // Fire off the notification if we have one.
-         if ( notify )
+         if (notify)
             notify->trigger();
       }
 
       void setFloatValue(F32 val)
       {
-         if( mIsConstant )
+         if (mIsConstant)
          {
-            Con::errorf( "Cannot assign value to constant '%s'.", name );
+            Con::errorf("Cannot assign value to constant '%s'.", name);
             return;
          }
-         
+
          value.setFloatValue(val);
 
          // Fire off the notification if we have one.
-         if ( notify )
+         if (notify)
             notify->trigger();
       }
 
       void setStringStackPtrValue(StringStackPtr newValue)
       {
-         if( mIsConstant )
+         if (mIsConstant)
          {
-            Con::errorf( "Cannot assign value to constant '%s'.", name );
+            Con::errorf("Cannot assign value to constant '%s'.", name);
             return;
          }
-         
+
          value.setStringStackPtrValue(newValue);
-         
-         
+
+
          // Fire off the notification if we have one.
-         if ( notify )
+         if (notify)
             notify->trigger();
       }
 
       void setStringValue(const char *newValue)
       {
-         if( mIsConstant )
+         if (mIsConstant)
          {
-            Con::errorf( "Cannot assign value to constant '%s'.", name );
+            Con::errorf("Cannot assign value to constant '%s'.", name);
             return;
          }
-         
+
          value.setStringValue(newValue);
-         
-         
+
+
          // Fire off the notification if we have one.
-         if ( notify )
+         if (notify)
             notify->trigger();
       }
    };
@@ -407,9 +406,9 @@ public:
       S32 count;
       Entry **data;
       FreeListChunker< Entry > mChunker;
-     
-      HashTableData( Dictionary* owner )
-         : owner( owner ), size( 0 ), count( 0 ), data( NULL ) {}
+
+      HashTableData(Dictionary* owner)
+         : owner(owner), size(0), count(0), data(NULL) {}
    };
 
    HashTableData* hashTable;
@@ -426,13 +425,13 @@ public:
 
    Entry *lookup(StringTableEntry name);
    Entry *add(StringTableEntry name);
-   void setState(ExprEvalState *state, Dictionary* ref=NULL);
+   void setState(ExprEvalState *state, Dictionary* ref = NULL);
    void remove(Entry *);
    void reset();
 
-   void exportVariables( const char *varString, const char *fileName, bool append );
-   void exportVariables( const char *varString, Vector<String> *names, Vector<String> *values );
-   void deleteVariables( const char *varString );
+   void exportVariables(const char *varString, const char *fileName, bool append);
+   void exportVariables(const char *varString, Vector<String> *names, Vector<String> *values);
+   void deleteVariables(const char *varString);
 
    void setVariable(StringTableEntry name, const char *value);
    const char *getVariable(StringTableEntry name, bool *valid = NULL);
@@ -449,19 +448,19 @@ public:
    }
 
    /// @see Con::addVariable
-   Entry* addVariable(  const char *name, 
-                        S32 type, 
-                        void *dataPtr, 
-                        const char* usage );
+   Entry* addVariable(const char *name,
+      S32 type,
+      void *dataPtr,
+      const char* usage);
 
    /// @see Con::removeVariable
    bool removeVariable(StringTableEntry name);
 
    /// @see Con::addVariableNotify
-   void addVariableNotify( const char *name, const Con::NotifyDelegate &callback );
+   void addVariableNotify(const char *name, const Con::NotifyDelegate &callback);
 
    /// @see Con::removeVariableNotify
-   void removeVariableNotify( const char *name, const Con::NotifyDelegate &callback );
+   void removeVariableNotify(const char *name, const Con::NotifyDelegate &callback);
 
    /// Return the best tab completion for prevText, with the length
    /// of the pre-tab string in baseLen.
@@ -520,15 +519,15 @@ public:
    /// Puts a reference to an existing stack frame
    /// on the top of the stack.
    void pushFrameRef(S32 stackIndex);
- 
+
    U32 getStackDepth() const
    {
       return mStackDepth;
    }
- 
+
    Dictionary& getCurrentFrame()
    {
-      return *( stack[ mStackDepth - 1 ] );
+      return *(stack[mStackDepth - 1]);
    }
 
    /// @}

+ 65 - 65
Engine/source/console/simDictionary.cpp

@@ -45,7 +45,7 @@ SimNameDictionary::~SimNameDictionary()
 
 void SimNameDictionary::insert(SimObject* obj)
 {
-   if(!obj || !obj->objectName)
+   if (!obj || !obj->objectName)
       return;
 
    SimObject* checkForDup = find(obj->objectName);
@@ -55,47 +55,47 @@ void SimNameDictionary::insert(SimObject* obj)
 
    Mutex::lockMutex(mutex);
 #ifndef USE_NEW_SIMDICTIONARY
-   if(!hashTable)
+   if (!hashTable)
    {
       hashTable = new SimObject *[DefaultTableSize];
       hashTableSize = DefaultTableSize;
       hashEntryCount = 0;
-      
-      dMemset( hashTable, 0, sizeof( *hashTable ) * DefaultTableSize );
+
+      dMemset(hashTable, 0, sizeof(*hashTable) * DefaultTableSize);
    }
-   
+
    S32 idx = HashPointer(obj->objectName) % hashTableSize;
    obj->nextNameObject = hashTable[idx];
    hashTable[idx] = obj;
    hashEntryCount++;
-   
+
    // Rehash if necessary.
 
-   if( hashEntryCount > hashTableSize )
+   if (hashEntryCount > hashTableSize)
    {
       // Allocate new table.
-      
+
       U32 newHashTableSize = hashTableSize * 2 + 1;
-      SimObject** newHashTable = new SimObject *[ newHashTableSize ];
-      dMemset( newHashTable, 0, sizeof( newHashTable[ 0 ] ) * newHashTableSize );
-      
+      SimObject** newHashTable = new SimObject *[newHashTableSize];
+      dMemset(newHashTable, 0, sizeof(newHashTable[0]) * newHashTableSize);
+
       // Move entries over.
 
-      for( U32 i = 0; i < hashTableSize; ++ i )
-         for( SimObject* object = hashTable[ i ]; object != NULL; )
+      for (U32 i = 0; i < hashTableSize; ++i)
+         for (SimObject* object = hashTable[i]; object != NULL; )
          {
             SimObject* next = object->nextNameObject;
 
-            idx = HashPointer( object->objectName ) % newHashTableSize;
-            object->nextNameObject = newHashTable[ idx ];
-            newHashTable[ idx ] = object;
-            
+            idx = HashPointer(object->objectName) % newHashTableSize;
+            object->nextNameObject = newHashTable[idx];
+            newHashTable[idx] = object;
+
             object = next;
          }
-         
+
       // Switch tables.
-      
-      delete [] hashTable;
+
+      delete[] hashTable;
       hashTable = newHashTable;
       hashTableSize = newHashTableSize;
    }
@@ -109,16 +109,16 @@ SimObject* SimNameDictionary::find(StringTableEntry name)
 {
 #ifndef USE_NEW_SIMDICTIONARY
    // NULL is a valid lookup - it will always return NULL
-   if(!hashTable)
+   if (!hashTable)
       return NULL;
-      
+
    Mutex::lockMutex(mutex);
 
    S32 idx = HashPointer(name) % hashTableSize;
    SimObject *walk = hashTable[idx];
-   while(walk)
+   while (walk)
    {
-      if(walk->objectName == name)
+      if (walk->objectName == name)
       {
          Mutex::unlockMutex(mutex);
          return walk;
@@ -129,28 +129,28 @@ SimObject* SimNameDictionary::find(StringTableEntry name)
    Mutex::unlockMutex(mutex);
    return NULL;
 #else
-  Mutex::lockMutex(mutex);
-  StringDictDef::iterator it = root.find(name);
-  SimObject* f = (it == root.end() ? NULL : it->second);
-  Mutex::unlockMutex(mutex);
-  return f;
+   Mutex::lockMutex(mutex);
+   StringDictDef::iterator it = root.find(name);
+   SimObject* f = (it == root.end() ? NULL : it->second);
+   Mutex::unlockMutex(mutex);
+   return f;
 #endif
 }
 
 void SimNameDictionary::remove(SimObject* obj)
 {
-   if(!obj || !obj->objectName)
+   if (!obj || !obj->objectName)
       return;
 
    Mutex::lockMutex(mutex);
 #ifndef USE_NEW_SIMDICTIONARY
    SimObject **walk = &hashTable[HashPointer(obj->objectName) % hashTableSize];
-   while(*walk)
+   while (*walk)
    {
-      if(*walk == obj)
+      if (*walk == obj)
       {
          *walk = obj->nextNameObject;
-         obj->nextNameObject = (SimObject*)-1;
+         obj->nextNameObject = nullptr;
          hashEntryCount--;
 
          Mutex::unlockMutex(mutex);
@@ -164,7 +164,7 @@ void SimNameDictionary::remove(SimObject* obj)
       root.erase(name);
 #endif
    Mutex::unlockMutex(mutex);
-}  
+}
 
 //----------------------------------------------------------------------------
 
@@ -174,8 +174,8 @@ SimManagerNameDictionary::SimManagerNameDictionary()
    hashTable = new SimObject *[DefaultTableSize];
    hashTableSize = DefaultTableSize;
    hashEntryCount = 0;
-   
-   dMemset( hashTable, 0, sizeof( hashTable[ 0 ] ) * hashTableSize );
+
+   dMemset(hashTable, 0, sizeof(hashTable[0]) * hashTableSize);
 #endif
    mutex = Mutex::createMutex();
 }
@@ -190,7 +190,7 @@ SimManagerNameDictionary::~SimManagerNameDictionary()
 
 void SimManagerNameDictionary::insert(SimObject* obj)
 {
-   if(!obj || !obj->objectName)
+   if (!obj || !obj->objectName)
       return;
 
    Mutex::lockMutex(mutex);
@@ -199,34 +199,34 @@ void SimManagerNameDictionary::insert(SimObject* obj)
    obj->nextManagerNameObject = hashTable[idx];
    hashTable[idx] = obj;
    hashEntryCount++;
-   
+
    // Rehash if necessary.
 
-   if( hashEntryCount > hashTableSize )
+   if (hashEntryCount > hashTableSize)
    {
       // Allocate new table.
-      
+
       U32 newHashTableSize = hashTableSize * 2 + 1;
-      SimObject** newHashTable = new SimObject *[ newHashTableSize ];
-      dMemset( newHashTable, 0, sizeof( newHashTable[ 0 ] ) * newHashTableSize );
-      
+      SimObject** newHashTable = new SimObject *[newHashTableSize];
+      dMemset(newHashTable, 0, sizeof(newHashTable[0]) * newHashTableSize);
+
       // Move entries over.
 
-      for( U32 i = 0; i < hashTableSize; ++ i )
-         for( SimObject* object = hashTable[ i ]; object != NULL; )
+      for (U32 i = 0; i < hashTableSize; ++i)
+         for (SimObject* object = hashTable[i]; object != NULL; )
          {
             SimObject* next = object->nextManagerNameObject;
 
-            idx = HashPointer( object->objectName ) % newHashTableSize;
-            object->nextManagerNameObject = newHashTable[ idx ];
-            newHashTable[ idx ] = object;
-            
+            idx = HashPointer(object->objectName) % newHashTableSize;
+            object->nextManagerNameObject = newHashTable[idx];
+            newHashTable[idx] = object;
+
             object = next;
          }
-         
+
       // Switch tables.
-      
-      delete [] hashTable;
+
+      delete[] hashTable;
       hashTable = newHashTable;
       hashTableSize = newHashTableSize;
    }
@@ -245,9 +245,9 @@ SimObject* SimManagerNameDictionary::find(StringTableEntry name)
 #ifndef USE_NEW_SIMDICTIONARY
    S32 idx = HashPointer(name) % hashTableSize;
    SimObject *walk = hashTable[idx];
-   while(walk)
+   while (walk)
    {
-      if(walk->objectName == name)
+      if (walk->objectName == name)
       {
          Mutex::unlockMutex(mutex);
          return walk;
@@ -267,19 +267,19 @@ SimObject* SimManagerNameDictionary::find(StringTableEntry name)
 
 void SimManagerNameDictionary::remove(SimObject* obj)
 {
-   if(!obj || !obj->objectName)
+   if (!obj || !obj->objectName)
       return;
 
 #ifndef USE_NEW_SIMDICTIONARY
    Mutex::lockMutex(mutex);
 
    SimObject **walk = &hashTable[HashPointer(obj->objectName) % hashTableSize];
-   while(*walk)
+   while (*walk)
    {
-      if(*walk == obj)
+      if (*walk == obj)
       {
          *walk = obj->nextManagerNameObject;
-         obj->nextManagerNameObject = (SimObject*)-1;
+         obj->nextManagerNameObject = nullptr;
          hashEntryCount--;
 
          Mutex::unlockMutex(mutex);
@@ -293,7 +293,7 @@ void SimManagerNameDictionary::remove(SimObject* obj)
       root.erase(name);
 #endif
    Mutex::unlockMutex(mutex);
-}  
+}
 
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -301,7 +301,7 @@ void SimManagerNameDictionary::remove(SimObject* obj)
 SimIdDictionary::SimIdDictionary()
 {
 #ifndef USE_NEW_SIMDICTIONARY
-   dMemset( table, 0, sizeof( table[ 0 ] ) * DefaultTableSize );
+   dMemset(table, 0, sizeof(table[0]) * DefaultTableSize);
 #endif
    mutex = Mutex::createMutex();
 }
@@ -322,7 +322,7 @@ void SimIdDictionary::insert(SimObject* obj)
 #ifndef USE_NEW_SIMDICTIONARY
    S32 idx = obj->getId() & TableBitMask;
    obj->nextIdObject = table[idx];
-   AssertFatal( obj->nextIdObject != obj, "SimIdDictionary::insert - Creating Infinite Loop linking to self!" );
+   AssertFatal(obj->nextIdObject != obj, "SimIdDictionary::insert - Creating Infinite Loop linking to self!");
    table[idx] = obj;
 #else
    root[obj->getId()] = obj;
@@ -336,9 +336,9 @@ SimObject* SimIdDictionary::find(S32 id)
 #ifndef USE_NEW_SIMDICTIONARY
    S32 idx = id & TableBitMask;
    SimObject *walk = table[idx];
-   while(walk)
+   while (walk)
    {
-      if(walk->getId() == U32(id))
+      if (walk->getId() == U32(id))
       {
          Mutex::unlockMutex(mutex);
          return walk;
@@ -364,9 +364,9 @@ void SimIdDictionary::remove(SimObject* obj)
    Mutex::lockMutex(mutex);
 #ifndef USE_NEW_SIMDICTIONARY
    SimObject **walk = &table[obj->getId() & TableBitMask];
-   while(*walk && *walk != obj)
+   while (*walk && *walk != obj)
       walk = &((*walk)->nextIdObject);
-   if(*walk)
+   if (*walk)
       *walk = obj->nextIdObject;
 #else
    root.erase(obj->getId());

+ 171 - 159
Engine/source/console/simFieldDictionary.cpp

@@ -32,79 +32,60 @@
 #include "console/consoleInternal.h"
 #include "core/frameAllocator.h"
 
-SimFieldDictionary::Entry *SimFieldDictionary::smFreeList = NULL;
-
-static Chunker<SimFieldDictionary::Entry> fieldChunker;
-
-U32 SimFieldDictionary::getHashValue( StringTableEntry slotName )
+U32 SimFieldDictionary::getHashValue(StringTableEntry slotName)
 {
-   return HashPointer( slotName ) % HashTableSize;
+   return HashPointer(slotName) % HashTableSize;
 }
 
-U32 SimFieldDictionary::getHashValue( const String& fieldName )
+U32 SimFieldDictionary::getHashValue(const String& fieldName)
 {
-   return getHashValue( StringTable->insert( fieldName ) );
+   return getHashValue(StringTable->insert(fieldName));
 }
 
-SimFieldDictionary::Entry *SimFieldDictionary::addEntry( U32 bucket, StringTableEntry slotName, ConsoleBaseType* type, char* value )
+SimFieldDictionary::Entry *SimFieldDictionary::addEntry(U32 bucket, StringTableEntry slotName, ConsoleBaseType* type, char* value)
 {
-   Entry* ret;
-   if(smFreeList)
-   {
-      ret = smFreeList;
-      smFreeList = ret->next;
-   }
-   else
-      ret = fieldChunker.alloc();
-
-   ret->next      = mHashTable[ bucket ];
-   ret->slotName  = slotName;
-   ret->type      = type;
-   ret->value     = value;
+   Entry ret;
+   ret.slotName = slotName;
+   ret.type = type;
+   ret.value = value;
 
-   mHashTable[ bucket ] = ret;
-   mNumFields ++;
-   mVersion ++;
+   mNumFields++;
+   mVersion++;
 
-   return ret;
+   mHashTable[bucket].push_back(std::move(ret));
+   return &mHashTable[bucket].back();
 }
 
 void SimFieldDictionary::freeEntry(SimFieldDictionary::Entry *ent)
 {
-   ent->next = smFreeList;
-   smFreeList = ent;
+   auto &vec = mHashTable[getHashValue(ent->slotName)];
 
-   mNumFields --;
+   // Find the slot.
+   auto iter = std::find_if(vec.begin(), vec.end(), [&](const Entry &ref) -> bool {
+      return ref.slotName == ent->slotName;
+   });
+   if (iter != vec.end())
+   {
+      vec.erase(iter);
+      mNumFields--;
+   }
 }
 
 SimFieldDictionary::SimFieldDictionary()
-:  mNumFields( 0 ),
-   mVersion( 0 )
+   : mNumFields(0),
+   mVersion(0)
 {
-   dMemset( mHashTable, 0, sizeof( mHashTable ) );
+
 }
 
 SimFieldDictionary::~SimFieldDictionary()
 {
-   for(U32 i = 0; i < HashTableSize; i++)
-   {
-      for(Entry *walk = mHashTable[i]; walk;)
-      {
-         Entry *temp = walk;
-         walk = temp->next;
-
-         if( temp->value )
-            dFree(temp->value);
-         freeEntry(temp);
-      }
-   }
 
-   AssertFatal( mNumFields == 0, "Incorrect count on field dictionary" );
 }
 
 void SimFieldDictionary::setFieldType(StringTableEntry slotName, const char *typeString)
 {
-   ConsoleBaseType *cbt = ConsoleBaseType::getTypeByName( typeString );
+   ConsoleBaseType *cbt = ConsoleBaseType::getTypeByName(typeString);
    setFieldType(slotName, cbt);
 }
 
@@ -117,56 +98,66 @@ void SimFieldDictionary::setFieldType(StringTableEntry slotName, const U32 typeI
 void SimFieldDictionary::setFieldType(StringTableEntry slotName, ConsoleBaseType *type)
 {
    // If the field exists on the object, set the type
-   U32 bucket = getHashValue( slotName );
+   U32 bucket = getHashValue(slotName);
 
-   for( Entry *walk = mHashTable[bucket]; walk; walk = walk->next )
+   for (Entry &ref : mHashTable[bucket])
    {
-      if( walk->slotName == slotName )
+      if (ref.slotName == slotName)
       {
          // Found and type assigned, let's bail
-         walk->type = type;
+         ref.type = type;
          return;
       }
    }
 
    // Otherwise create the field, and set the type. Assign a null value.
-   addEntry( bucket, slotName, type );
+   addEntry(bucket, slotName, type);
 }
 
 U32 SimFieldDictionary::getFieldType(StringTableEntry slotName) const
 {
-   U32 bucket = getHashValue( slotName );
+   U32 bucket = getHashValue(slotName);
 
-   for( Entry *walk = mHashTable[bucket]; walk; walk = walk->next )
-      if( walk->slotName == slotName )
-         return walk->type ? walk->type->getTypeID() : TypeString;
+   const std::vector<Entry> &vec = mHashTable[bucket];
+   size_t size = vec.size();
+   for (size_t i = 0; i < size; ++i)
+   {
+      const Entry &ref = vec[i];
+      if (ref.slotName == slotName)
+         return ref.type ? ref.type->getTypeID() : TypeString;
+   }
 
    return TypeString;
 }
 
 SimFieldDictionary::Entry  *SimFieldDictionary::findDynamicField(const String &fieldName) const
 {
-   U32 bucket = getHashValue( fieldName );
+   U32 bucket = getHashValue(fieldName);
 
-   for( Entry *walk = mHashTable[bucket]; walk; walk = walk->next )
+   const std::vector<Entry> &vec = mHashTable[bucket];
+   size_t size = vec.size();
+   for (size_t i = 0; i < size; ++i)
    {
-      if( fieldName.equal(walk->slotName, String::NoCase) )
-         return walk;
+      const Entry &ref = vec[i];
+      if (fieldName.equal(ref.slotName, String::NoCase))
+         return const_cast<Entry*>(&ref);
    }
 
    return NULL;
 }
 
-SimFieldDictionary::Entry *SimFieldDictionary::findDynamicField( StringTableEntry fieldName) const
+SimFieldDictionary::Entry *SimFieldDictionary::findDynamicField(StringTableEntry fieldName) const
 {
-   U32 bucket = getHashValue( fieldName );
+   U32 bucket = getHashValue(fieldName);
 
-   for( Entry *walk = mHashTable[bucket]; walk; walk = walk->next )
+   const std::vector<Entry> &vec = mHashTable[bucket];
+   size_t size = vec.size();
+   for (size_t i = 0; i < size; ++i)
    {
-       if( walk->slotName == fieldName )
-       {
-        return walk;
-       }
+      if (vec[i].slotName == fieldName)
+      {
+         return const_cast<Entry*>(&vec[i]);
+      }
    }
 
    return NULL;
@@ -176,45 +167,43 @@ SimFieldDictionary::Entry *SimFieldDictionary::findDynamicField( StringTableEntr
 void SimFieldDictionary::setFieldValue(StringTableEntry slotName, const char *value)
 {
    U32 bucket = getHashValue(slotName);
-   Entry **walk = &mHashTable[bucket];
-   while(*walk && (*walk)->slotName != slotName)
-      walk = &((*walk)->next);
 
-   Entry *field = *walk;
-   if( !value || !*value )
+   for (Entry &ref : mHashTable[bucket])
    {
-      if(field)
+      if (ref.slotName == slotName)
       {
-         mVersion++;
+         if (!value || !*value)
+         {
+            mVersion++;
 
-         if( field->value )
-            dFree(field->value);
+            if (ref.value)
+               dFree(ref.value);
 
-         *walk = field->next;
-         freeEntry(field);
-      }
-   }
-   else
-   {
-      if(field)
-      {
-         if( field->value )
-            dFree(field->value);
+            freeEntry(&ref);
+         }
+         else
+         {
+            if (ref.value)
+               dFree(ref.value);
 
-         field->value = dStrdup(value);
+            ref.value = dStrdup(value);
+         }
+
+         return;
       }
-      else
-         addEntry( bucket, slotName, 0, dStrdup( value ) );
    }
+
+   // no field, add entry.
+   addEntry(bucket, slotName, 0, dStrdup(value));
 }
 
 const char *SimFieldDictionary::getFieldValue(StringTableEntry slotName)
 {
    U32 bucket = getHashValue(slotName);
 
-   for(Entry *walk = mHashTable[bucket];walk;walk = walk->next)
-      if(walk->slotName == slotName)
-         return walk->value;
+   for (const Entry &ref : mHashTable[bucket])
+      if (ref.slotName == slotName)
+         return ref.value;
 
    return NULL;
 }
@@ -223,43 +212,43 @@ void SimFieldDictionary::assignFrom(SimFieldDictionary *dict)
 {
    mVersion++;
 
-   for(U32 i = 0; i < HashTableSize; i++)
+   for (U32 i = 0; i < HashTableSize; i++)
    {
-      for(Entry *walk = dict->mHashTable[i];walk; walk = walk->next)
+      for (const Entry &ref : mHashTable[i])
       {
-         setFieldValue(walk->slotName, walk->value);
-         setFieldType(walk->slotName, walk->type);
+         setFieldValue(ref.slotName, ref.value);
+         setFieldType(ref.slotName, ref.type);
       }
    }
 }
 
-static S32 QSORT_CALLBACK compareEntries(const void* a,const void* b)
+static S32 QSORT_CALLBACK compareEntries(const void* a, const void* b)
 {
-   SimFieldDictionary::Entry *fa = *((SimFieldDictionary::Entry **)a);
-   SimFieldDictionary::Entry *fb = *((SimFieldDictionary::Entry **)b);
+   const SimFieldDictionary::Entry *fa = reinterpret_cast<const SimFieldDictionary::Entry*>(a);
+   const SimFieldDictionary::Entry *fb = reinterpret_cast<const SimFieldDictionary::Entry*>(b);
    return dStricmp(fa->slotName, fb->slotName);
 }
 
 void SimFieldDictionary::writeFields(SimObject *obj, Stream &stream, U32 tabStop)
 {
    const AbstractClassRep::FieldList &list = obj->getFieldList();
-   Vector<Entry *> flist(__FILE__, __LINE__);
+   Vector<Entry> flist(__FILE__, __LINE__);
 
-   for(U32 i = 0; i < HashTableSize; i++)
+   for (U32 i = 0; i < HashTableSize; i++)
    {
-      for(Entry *walk = mHashTable[i];walk; walk = walk->next)
+      for (const Entry &walk : mHashTable[i])
       {
          // make sure we haven't written this out yet:
-         U32 i;
-         for(i = 0; i < list.size(); i++)
-            if(list[i].pFieldname == walk->slotName)
+         U32 j;
+         for (j = 0; j < list.size(); j++)
+            if (list[j].pFieldname == walk.slotName)
                break;
 
-         if(i != list.size())
+         if (j != list.size())
             continue;
 
 
-         if (!obj->writeField(walk->slotName, walk->value))
+         if (!obj->writeField(walk.slotName, walk.value))
             continue;
 
          flist.push_back(walk);
@@ -267,23 +256,23 @@ void SimFieldDictionary::writeFields(SimObject *obj, Stream &stream, U32 tabStop
    }
 
    // Sort Entries to prevent version control conflicts
-   dQsort(flist.address(),flist.size(),sizeof(Entry *),compareEntries);
+   dQsort(flist.address(), flist.size(), sizeof(Entry), compareEntries);
 
    // Save them out
-   for(Vector<Entry *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
+   for (const Entry &ref : flist)
    {
-      U32 nBufferSize = (dStrlen( (*itr)->value ) * 2) + dStrlen( (*itr)->slotName ) + 16;
-      FrameTemp<char> expandedBuffer( nBufferSize );
+      U32 nBufferSize = (dStrlen(ref.value) * 2) + dStrlen(ref.slotName) + 16;
+      FrameTemp<char> expandedBuffer(nBufferSize);
 
-      stream.writeTabs(tabStop+1);
+      stream.writeTabs(tabStop + 1);
 
-      const char *typeName = (*itr)->type && (*itr)->type->getTypeID() != TypeString ? (*itr)->type->getTypeName() : "";
-      dSprintf(expandedBuffer, nBufferSize, "%s%s%s = \"", typeName, *typeName ? " " : "", (*itr)->slotName);
-      if ( (*itr)->value )
-         expandEscape((char*)expandedBuffer + dStrlen(expandedBuffer), (*itr)->value);
+      const char *typeName = ref.type && ref.type->getTypeID() != TypeString ? ref.type->getTypeName() : "";
+      dSprintf(expandedBuffer, nBufferSize, "%s%s%s = \"", typeName, *typeName ? " " : "", ref.slotName);
+      if (ref.value)
+         expandEscape((char*)expandedBuffer + dStrlen(expandedBuffer), ref.value);
       dStrcat(expandedBuffer, "\";\r\n");
 
-      stream.write(dStrlen(expandedBuffer),expandedBuffer);
+      stream.write(dStrlen(expandedBuffer), expandedBuffer);
    }
 
 }
@@ -291,44 +280,44 @@ void SimFieldDictionary::printFields(SimObject *obj)
 {
    const AbstractClassRep::FieldList &list = obj->getFieldList();
    char expandedBuffer[4096];
-   Vector<Entry *> flist(__FILE__, __LINE__);
+   Vector<Entry> flist(__FILE__, __LINE__);
 
-   for(U32 i = 0; i < HashTableSize; i++)
+   for (U32 i = 0; i < HashTableSize; i++)
    {
-      for(Entry *walk = mHashTable[i];walk; walk = walk->next)
+      for (const Entry &walk : mHashTable[i])
       {
          // make sure we haven't written this out yet:
-         U32 i;
-         for(i = 0; i < list.size(); i++)
-            if(list[i].pFieldname == walk->slotName)
+         U32 j;
+         for (j = 0; j < list.size(); j++)
+            if (list[i].pFieldname == walk.slotName)
                break;
 
-         if(i != list.size())
+         if (j != list.size())
             continue;
 
          flist.push_back(walk);
       }
    }
-   dQsort(flist.address(),flist.size(),sizeof(Entry *),compareEntries);
+   dQsort(flist.address(), flist.size(), sizeof(Entry), compareEntries);
 
-   for(Vector<Entry *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
+   for (const Entry &ref : flist)
    {
       const char* type = "string";
-      if( ( *itr )->type )
-         type = ( *itr )->type->getTypeClassName();
-         
-      dSprintf( expandedBuffer, sizeof( expandedBuffer ), "  %s %s = \"", type, ( *itr )->slotName );
-      if ( (*itr)->value )
-         expandEscape(expandedBuffer + dStrlen(expandedBuffer), (*itr)->value);
+      if (ref.type)
+         type = ref.type->getTypeClassName();
+
+      dSprintf(expandedBuffer, sizeof(expandedBuffer), "  %s %s = \"", type, ref.slotName);
+      if (ref.value)
+         expandEscape(expandedBuffer + dStrlen(expandedBuffer), ref.value);
       Con::printf("%s\"", expandedBuffer);
    }
 }
 
 SimFieldDictionary::Entry  *SimFieldDictionary::operator[](U32 index)
 {
-   AssertFatal ( index < mNumFields, "out of range" );
+   AssertFatal(index < mNumFields, "out of range");
 
-   if ( index > mNumFields )
+   if (index > mNumFields)
       return NULL;
 
    SimFieldDictionaryIterator itr(this);
@@ -343,29 +332,44 @@ SimFieldDictionary::Entry  *SimFieldDictionary::operator[](U32 index)
 SimFieldDictionaryIterator::SimFieldDictionaryIterator(SimFieldDictionary * dictionary)
 {
    mDictionary = dictionary;
-   mHashIndex = -1;
-   mEntry = 0;
+   mHashIndex = 0;
+   mVecIndex = -1; // -1 since we immediately call operator++
+   mEntry = NULL;
    operator++();
 }
 
 SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator++()
 {
-   if(!mDictionary)
-      return(mEntry);
+   if (!mDictionary || mHashIndex >= SimFieldDictionary::HashTableSize)
+   {
+      mEntry = NULL;
+      return NULL;
+   }
 
-   if(mEntry)
-      mEntry = mEntry->next;
+   std::vector<SimFieldDictionary::Entry> &vec = mDictionary->mHashTable[mHashIndex];
 
-   while(!mEntry && (mHashIndex < (SimFieldDictionary::HashTableSize-1)))
-      mEntry = mDictionary->mHashTable[++mHashIndex];
+   while (vec.size() == 0 && mHashIndex < (SimFieldDictionary::HashTableSize - 1))
+   {
+      vec = mDictionary->mHashTable[++mHashIndex];
+      mVecIndex = 0;
+   }
+
+   if (mVecIndex >= vec.size() || mHashIndex >= SimFieldDictionary::HashTableSize)
+   {
+      mEntry = NULL;
+      return NULL;
+   }
 
-   return(mEntry);
+   mEntry = &vec[mVecIndex];
+   ++mVecIndex;
+   return mEntry;
 }
 
 SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator*()
 {
-   return(mEntry);
+   return mEntry;
 }
+
 // A variation of the stock SimFieldDictionary::setFieldValue(), this method adds the
 // <no_replace> argument which, when true, prohibits the replacement of fields that
 // already have a value. 
@@ -385,15 +389,15 @@ void SimFieldDictionary::setFieldValue(StringTableEntry slotName, const char *va
       return;
 
    U32 bucket = getHashValue(slotName);
-   Entry **walk = &mHashTable[bucket];
-   while(*walk && (*walk)->slotName != slotName)
-      walk = &((*walk)->next);
-
-   Entry *field = *walk;
-   if (field)
-      return;
+   for (const Entry &walk : mHashTable[bucket])
+   {
+      if (walk.slotName == slotName)
+      {
+         return;
+      }
+   }
 
-   addEntry( bucket, slotName, type, dStrdup( value ) );
+   addEntry(bucket, slotName, type, dStrdup(value));
 }
 // A variation of the stock SimFieldDictionary::assignFrom(), this method adds <no_replace>
 // and <filter> arguments. When true, <no_replace> prohibits the replacement of fields that already
@@ -412,15 +416,23 @@ void SimFieldDictionary::assignFrom(SimFieldDictionary *dict, const char* filter
 
    if (filter_len == 0)
    {
-      for(U32 i = 0; i < HashTableSize; i++)
-         for(Entry *walk = dict->mHashTable[i];walk; walk = walk->next)
-            setFieldValue(walk->slotName, walk->value, walk->type, no_replace);
+      for (U32 i = 0; i < HashTableSize; i++)
+      {
+         for (const Entry &walk : dict->mHashTable[i])
+         {
+            setFieldValue(walk.slotName, walk.value, walk.type, no_replace);
+         }
+      }
    }
    else
    {
-      for(U32 i = 0; i < HashTableSize; i++)
-         for(Entry *walk = dict->mHashTable[i];walk; walk = walk->next)
-            if (dStrncmp(walk->slotName, filter, filter_len) == 0)
-               setFieldValue(walk->slotName, walk->value, walk->type, no_replace);
+      for (U32 i = 0; i < HashTableSize; i++)
+      {
+         for (const Entry &walk : dict->mHashTable[i])
+         {
+            if (dStrncmp(walk.slotName, filter, filter_len) == 0)
+               setFieldValue(walk.slotName, walk.value, walk.type, no_replace);
+         }
+      }
    }
-}
+}

+ 12 - 9
Engine/source/console/simFieldDictionary.h

@@ -32,6 +32,9 @@
 class ConsoleBaseType;
 class SimObject;
 
+#include <array>
+#include <vector>
+
 #include "core/stringTable.h"
 #include "core/stream/stream.h"
 
@@ -47,27 +50,26 @@ class SimFieldDictionary
 public:
    struct Entry
    {
-      Entry() : type( NULL ) {};
+      Entry() : type(NULL) {};
 
       StringTableEntry slotName;
       char *value;
-      Entry *next;
       ConsoleBaseType *type;
    };
    enum
    {
       HashTableSize = 19
    };
-   Entry *mHashTable[HashTableSize];
+   //Entry *mHashTable[HashTableSize];
 
-private:
-   static Entry   *smFreeList;
+   std::vector<Entry> mHashTable[HashTableSize];
 
+private:
    void           freeEntry(Entry *entry);
-   Entry*         addEntry( U32 bucket, StringTableEntry slotName, ConsoleBaseType* type, char* value = 0 );
+   Entry*         addEntry(U32 bucket, StringTableEntry slotName, ConsoleBaseType* type, char* value = 0);
 
-   static U32     getHashValue( StringTableEntry slotName );
-   static U32     getHashValue( const String& fieldName );
+   static U32     getHashValue(StringTableEntry slotName);
+   static U32     getHashValue(const String& fieldName);
 
    U32   mNumFields;
 
@@ -88,7 +90,7 @@ public:
    const char *getFieldValue(StringTableEntry slotName);
    U32 getFieldType(StringTableEntry slotName) const;
    Entry  *findDynamicField(const String &fieldName) const;
-   Entry  *findDynamicField( StringTableEntry fieldName) const;
+   Entry  *findDynamicField(StringTableEntry fieldName) const;
    void writeFields(SimObject *obj, Stream &strem, U32 tabStop);
    void printFields(SimObject *obj);
    void assignFrom(SimFieldDictionary *dict);
@@ -103,6 +105,7 @@ class SimFieldDictionaryIterator
 {
    SimFieldDictionary *          mDictionary;
    S32                           mHashIndex;
+   S32                           mVecIndex;
    SimFieldDictionary::Entry *   mEntry;
 
 public:

+ 6 - 4
Engine/source/console/simObject.cpp

@@ -72,8 +72,8 @@ SimObject::SimObject()
    objectName            = NULL;
    mOriginalName         = NULL;
    mInternalName         = NULL;
-   nextNameObject        = (SimObject*)-1;
-   nextManagerNameObject = (SimObject*)-1;
+   nextNameObject        = nullptr;
+   nextManagerNameObject = nullptr;
    nextIdObject          = NULL;
 
    mFilename             = NULL;
@@ -86,6 +86,8 @@ SimObject::SimObject()
    mNotifyList   = NULL;
    mFlags.set( ModStaticFields | ModDynamicFields );
 
+   mProgenitorFile = StringTable->EmptyString();
+
    mFieldDictionary = NULL;
    mCanSaveFieldDictionary =  true;
 
@@ -122,10 +124,10 @@ SimObject::~SimObject()
    if( mCopySource )
       mCopySource->unregisterReference( &mCopySource );
 
-   AssertFatal(nextNameObject == (SimObject*)-1,avar(
+   AssertFatal(nextNameObject == nullptr,avar(
       "SimObject::~SimObject:  Not removed from dictionary: name %s, id %i",
       objectName, mId));
-   AssertFatal(nextManagerNameObject == (SimObject*)-1,avar(
+   AssertFatal(nextManagerNameObject == nullptr,avar(
       "SimObject::~SimObject:  Not removed from manager dictionary: name %s, id %i",
       objectName,mId));
    AssertFatal(mFlags.test(Added) == 0, "SimObject::object "

+ 10 - 13
Engine/source/persistence/taml/taml.cpp

@@ -774,18 +774,18 @@ void Taml::compileDynamicFields( TamlWriteNode* pTamlWriteNode )
     // Fetch field count.
     const U32 fieldCount = fieldList.size();
 
-    Vector<SimFieldDictionary::Entry*> dynamicFieldList(__FILE__, __LINE__);
+    Vector<SimFieldDictionary::Entry> dynamicFieldList(__FILE__, __LINE__);
 
     // Ensure the dynamic field doesn't conflict with static field.
     for( U32 hashIndex = 0; hashIndex < SimFieldDictionary::HashTableSize; ++hashIndex )
     {
-        for( SimFieldDictionary::Entry* pEntry = pFieldDictionary->mHashTable[hashIndex]; pEntry; pEntry = pEntry->next )
-        {
+       for (const SimFieldDictionary::Entry &pEntry : pFieldDictionary->mHashTable[hashIndex])
+       {
             // Iterate static fields.
             U32 fieldIndex;
             for( fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex )
             {
-                if( fieldList[fieldIndex].pFieldname == pEntry->slotName)
+               if (fieldList[fieldIndex].pFieldname == pEntry.slotName)
                     break;
             }
 
@@ -794,7 +794,7 @@ void Taml::compileDynamicFields( TamlWriteNode* pTamlWriteNode )
                 continue;
 
             // Skip if not writing field.
-            if ( !pSimObject->writeField( pEntry->slotName, pEntry->value) )
+            if (!pSimObject->writeField(pEntry.slotName, pEntry.value))
                 continue;
 
             dynamicFieldList.push_back( pEntry );
@@ -803,17 +803,14 @@ void Taml::compileDynamicFields( TamlWriteNode* pTamlWriteNode )
 
     // Sort Entries to prevent version control conflicts
     if ( dynamicFieldList.size() > 1 )
-        dQsort(dynamicFieldList.address(), dynamicFieldList.size(), sizeof(SimFieldDictionary::Entry*), compareFieldEntries);
+       dQsort(dynamicFieldList.address(), dynamicFieldList.size(), sizeof(SimFieldDictionary::Entry), compareFieldEntries);
 
     // Save the fields.
-    for( Vector<SimFieldDictionary::Entry*>::iterator entryItr = dynamicFieldList.begin(); entryItr != dynamicFieldList.end(); ++entryItr )
+    for (const SimFieldDictionary::Entry &pEntry : dynamicFieldList)
     {
-        // Fetch entry.
-        SimFieldDictionary::Entry* pEntry = *entryItr;
-
-        // Save field/value.
-        TamlWriteNode::FieldValuePair*  pFieldValuePair = new TamlWriteNode::FieldValuePair( pEntry->slotName, pEntry->value );
-        pTamlWriteNode->mFields.push_back( pFieldValuePair );
+       // Save field/value.
+       TamlWriteNode::FieldValuePair*  pFieldValuePair = new TamlWriteNode::FieldValuePair(pEntry.slotName, pEntry.value);
+       pTamlWriteNode->mFields.push_back(pFieldValuePair);
     }
 }
 

Some files were not shown because too many files changed in this diff